From 90e65e89f09ab31bc60a47692335efcc0339b501 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Sun, 2 Jul 2017 21:27:36 +0900 Subject: [PATCH 001/228] Initial commit --- .gitignore | 14 ++ LICENSE | 674 +++++++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 2 + 3 files changed, 690 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a1338d6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,14 @@ +# Binaries for programs and plugins +*.exe +*.dll +*.so +*.dylib + +# Test binary, build with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736 +.glide/ diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..9cecc1d --- /dev/null +++ b/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + {one line to give the program's name and a brief idea of what it does.} + Copyright (C) {year} {name of author} + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + {project} Copyright (C) {year} {fullname} + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/README.md b/README.md new file mode 100644 index 0000000..f5df3aa --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# gazelle +ISLisp on golang From 022954f2f9a23d4972957f42fcbb1e2648678116 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Sun, 2 Jul 2017 21:32:46 +0900 Subject: [PATCH 002/228] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index f5df3aa..9bb0f7c 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,4 @@ # gazelle ISLisp on golang +
+
Photo via via Visual Hunt
From 479ca1975d15e2725e09323363bfc0ba6a3c46d3 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Sun, 2 Jul 2017 22:15:31 +0900 Subject: [PATCH 003/228] Add Makefile --- Makefile | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 Makefile diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..17deb94 --- /dev/null +++ b/Makefile @@ -0,0 +1,5 @@ +all: parser.go + +parser.go: parser.go.y + goyacc -o $@ $< + From 5734d5ab121bc5ce9fa399f01c052e8d7edd0da6 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Sun, 2 Jul 2017 23:14:33 +0900 Subject: [PATCH 004/228] Update Makefile --- Makefile | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 17deb94..47c53cf 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,28 @@ -all: parser.go +all: build parser.go: parser.go.y goyacc -o $@ $< +.PHONY: build clean format run vet test gommit + +build: parser.go + go build + +clean: format + go clean + rm -rf parser.go *~ + +format: + go fmt + +run: parser.go + go run + +vet: parser.go + go vet + +test: parser.go vet + go test + +commit: clean + git commit -a From e1918595631782339865a49c57d1d73116ac28c7 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Sun, 2 Jul 2017 23:15:02 +0900 Subject: [PATCH 005/228] Update Makefile --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 47c53cf..6085f75 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ all: build parser.go: parser.go.y goyacc -o $@ $< -.PHONY: build clean format run vet test gommit +.PHONY: build clean format run vet test commit build: parser.go go build From e10f564d18777afa73c9b25b6bb98683be776125 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Sun, 23 Jul 2017 23:18:43 +0900 Subject: [PATCH 006/228] added Read function --- Makefile | 28 ------- main.go | 16 ++++ object.go | 12 +++ read.go | 213 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 241 insertions(+), 28 deletions(-) delete mode 100644 Makefile create mode 100644 main.go create mode 100644 object.go create mode 100644 read.go diff --git a/Makefile b/Makefile deleted file mode 100644 index 6085f75..0000000 --- a/Makefile +++ /dev/null @@ -1,28 +0,0 @@ -all: build - -parser.go: parser.go.y - goyacc -o $@ $< - -.PHONY: build clean format run vet test commit - -build: parser.go - go build - -clean: format - go clean - rm -rf parser.go *~ - -format: - go fmt - -run: parser.go - go run - -vet: parser.go - go vet - -test: parser.go vet - go test - -commit: clean - git commit -a diff --git a/main.go b/main.go new file mode 100644 index 0000000..4537875 --- /dev/null +++ b/main.go @@ -0,0 +1,16 @@ +package main + +import ( + "io" + "strings" + + "github.com/k0kubun/pp" +) + +func main() { + src := "(display #\\\\) (print 10)" + r := strings.NewReader(src) + for exp, err := Read(r); err != io.EOF; exp, err = Read(r) { + pp.Print(exp) + } +} diff --git a/object.go b/object.go new file mode 100644 index 0000000..1f9398a --- /dev/null +++ b/object.go @@ -0,0 +1,12 @@ +package main + +type Object struct { + Type string + Car *Object + Cdr *Object + Val interface{} +} + +func NewCons(car *Object, cdr *Object) *Object { + return &Object{"cons", car, cdr, nil} +} diff --git a/read.go b/read.go new file mode 100644 index 0000000..06ce582 --- /dev/null +++ b/read.go @@ -0,0 +1,213 @@ +package main + +import ( + "errors" + "io" + "math" + "regexp" + "strconv" + "strings" +) + +var errEOP = errors.New("End Of Parentheses") + +func newMatcher(src ...string) *regexp.Regexp { + return regexp.MustCompile("^(?:" + strings.Join(src, ")$|^(?:") + ")$") +} + +type tokens struct { + eof bool + buf string + reader io.RuneReader + matcher *regexp.Regexp +} + +var macroSyntax = ",@|,|'|`" +var integerSyntax = "[+-]?[[:digit:]]+|#[bB][01]+|#[oO][0-7]+|#[xX][[:xdigit:]]+" +var floatSyntax = "[+-]?[[:digit:]]+(?:.[[:digit:]]+|[eE][+-]?[[:digit:]]+|.[[:digit:]]+[eE][+-]?[[:digit:]]+)" +var characterSyntax = "#\\\\?|#\\\\(?:[[:alpha:]]+|[[:graph:]])" +var stringSyntax = "\"(?:\\\\\"|[^\"])*\"?" +var symbolSyntax = "[<>/*=?_!$%[\\]^{}~a-zA-Z][<>/*=?_!$%[\\]^{}~0-9a-zA-Z]*|\\|(?:\\\\\\||[^|])*\\|?" +var parenthesesSyntax = "\\(|\\)" + +func tokenize(r io.RuneReader) *tokens { + return &tokens{true, "", r, newMatcher( + macroSyntax, + integerSyntax, + floatSyntax, + characterSyntax, + stringSyntax, + symbolSyntax, + parenthesesSyntax)} +} + +func (t *tokens) next() (string, error) { + for { + r, _, err := t.reader.ReadRune() + if !t.eof && err == io.EOF { + t.eof = true + return t.buf, nil + } + if err != nil { + return t.buf, err + } + + t.eof = false + if t.matcher.MatchString(t.buf + string(r)) { + t.buf += string(r) + } else { + if t.matcher.MatchString(t.buf) { + result := t.buf + t.buf = string(r) + return result, nil + } else if t.matcher.MatchString(string(r)) { + t.buf = string(r) + } else { + t.buf = "" + } + } + } +} + +func parseCons(t *tokens) (*Object, error) { + car, err := parse(t) + if err != nil { + if err == errEOP { + return nil, nil + } + return nil, err + } + cdr, err := parseCons(t) + if err != nil { + return nil, err + } + return NewCons(car, cdr), nil +} + +func parseInteger(tok string) (*Object, error) { + start := 0 + if tok[0] == '+' || tok[0] == '-' { + start = 1 + } + if tok[start] == '#' { + base := 10 + if tok[start+1] == 'b' || tok[start+1] == 'B' { + base = 2 + } else if tok[start+1] == 'o' || tok[start+1] == 'O' { + base = 8 + } else if tok[start+1] == 'x' || tok[start+1] == 'X' { + base = 16 + } + num, err := strconv.ParseInt(tok[start+2:], base, 32) + if err != nil { + return nil, err + } + if tok[0] == '-' { + num = -num + } + return &Object{"integer", nil, nil, num}, nil + } + num, err := strconv.ParseInt(tok, 10, 32) + if err != nil { + return nil, err + } + return &Object{"integer", nil, nil, num}, nil +} + +func parseFloat(tok string) (*Object, error) { + e := strings.IndexRune(strings.ToUpper(tok), 'E') + if e > 0 { + num, err := strconv.ParseFloat(tok[:e], 32) + if err != nil { + return nil, err + } + exp, err := strconv.ParseFloat(tok[e+1:], 32) + if err != nil { + return nil, err + } + return &Object{"float", nil, nil, num * math.Pow(10.0, exp)}, nil + } + num, err := strconv.ParseFloat(tok, 32) + if err != nil { + return nil, err + } + return &Object{"float", nil, nil, num}, nil +} + +func parseCharacter(tok string) (*Object, error) { + if strings.ToLower(tok) == "newline" { + return &Object{"character", nil, nil, '\n'}, nil + } + if strings.ToLower(tok) == "space" { + return &Object{"character", nil, nil, ' '}, nil + } + if len(tok) != 3 { + return nil, errors.New("Invalid character name") + } + return &Object{"character", nil, nil, tok[2]}, nil +} + +func parseAtom(tok string, t *tokens) (*Object, error) { + if matched, _ := regexp.Match(macroSyntax, []byte(tok)); matched { + cdr, err := parse(t) + if err != nil { + return nil, err + } + return NewCons(&Object{"symbol", nil, nil, tok}, NewCons(cdr, nil)), nil + } + if matched, _ := regexp.Match(integerSyntax, []byte(tok)); matched { + n, err := parseInteger(tok) + if err != nil { + return nil, err + } + return n, nil + } + if matched, _ := regexp.Match(floatSyntax, []byte(tok)); matched { + f, err := parseFloat(tok) + if err != nil { + return nil, err + } + return f, nil + } + if matched, _ := regexp.Match(characterSyntax, []byte(tok)); matched { + c, err := parseCharacter(tok) + if err != nil { + return nil, err + } + return &Object{"character", nil, nil, c}, nil + } + if matched, _ := regexp.Match(stringSyntax, []byte(tok)); matched { + return &Object{"string", nil, nil, tok}, nil + } + if tok[0] != '|' { + return &Object{"symbol", nil, nil, strings.ToUpper(tok)}, nil + } + return &Object{"symbol", nil, nil, tok}, nil +} + +func parse(t *tokens) (*Object, error) { + tok, err := t.next() + if err != nil { + return nil, err + } + if tok == "(" { + cons, err := parseCons(t) + if err != nil { + return nil, err + } + return cons, err + } + if tok == ")" { + return nil, errEOP + } + atom, err := parseAtom(tok, t) + if err != nil { + return nil, err + } + return atom, nil +} + +func Read(r io.RuneReader) (*Object, error) { + exp, err := parse(tokenize(r)) + return exp, err +} From 40ed02a3d48be0220a8888c80bcab3e0b1718ac2 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Mon, 24 Jul 2017 12:14:59 +0900 Subject: [PATCH 007/228] refactor source code --- main.go | 6 +- object.go | 4 + read.go | 213 --------------------------------------------------- reader.go | 155 +++++++++++++++++++++++++++++++++++++ tokenizer.go | 56 ++++++++++++++ util.go | 29 +++++++ 6 files changed, 247 insertions(+), 216 deletions(-) delete mode 100644 read.go create mode 100644 reader.go create mode 100644 tokenizer.go create mode 100644 util.go diff --git a/main.go b/main.go index 4537875..35b269b 100644 --- a/main.go +++ b/main.go @@ -8,9 +8,9 @@ import ( ) func main() { - src := "(display #\\\\) (print 10)" - r := strings.NewReader(src) - for exp, err := Read(r); err != io.EOF; exp, err = Read(r) { + src := "(display #\\a) (println 10)" + r := NewReader(strings.NewReader(src)) + for exp, err := r.ReadExp(); err != io.EOF; exp, err = r.ReadExp() { pp.Print(exp) } } diff --git a/object.go b/object.go index 1f9398a..23f69ac 100644 --- a/object.go +++ b/object.go @@ -10,3 +10,7 @@ type Object struct { func NewCons(car *Object, cdr *Object) *Object { return &Object{"cons", car, cdr, nil} } + +func (o *Object) Is(val interface{}) bool { + return o.Val == val +} diff --git a/read.go b/read.go deleted file mode 100644 index 06ce582..0000000 --- a/read.go +++ /dev/null @@ -1,213 +0,0 @@ -package main - -import ( - "errors" - "io" - "math" - "regexp" - "strconv" - "strings" -) - -var errEOP = errors.New("End Of Parentheses") - -func newMatcher(src ...string) *regexp.Regexp { - return regexp.MustCompile("^(?:" + strings.Join(src, ")$|^(?:") + ")$") -} - -type tokens struct { - eof bool - buf string - reader io.RuneReader - matcher *regexp.Regexp -} - -var macroSyntax = ",@|,|'|`" -var integerSyntax = "[+-]?[[:digit:]]+|#[bB][01]+|#[oO][0-7]+|#[xX][[:xdigit:]]+" -var floatSyntax = "[+-]?[[:digit:]]+(?:.[[:digit:]]+|[eE][+-]?[[:digit:]]+|.[[:digit:]]+[eE][+-]?[[:digit:]]+)" -var characterSyntax = "#\\\\?|#\\\\(?:[[:alpha:]]+|[[:graph:]])" -var stringSyntax = "\"(?:\\\\\"|[^\"])*\"?" -var symbolSyntax = "[<>/*=?_!$%[\\]^{}~a-zA-Z][<>/*=?_!$%[\\]^{}~0-9a-zA-Z]*|\\|(?:\\\\\\||[^|])*\\|?" -var parenthesesSyntax = "\\(|\\)" - -func tokenize(r io.RuneReader) *tokens { - return &tokens{true, "", r, newMatcher( - macroSyntax, - integerSyntax, - floatSyntax, - characterSyntax, - stringSyntax, - symbolSyntax, - parenthesesSyntax)} -} - -func (t *tokens) next() (string, error) { - for { - r, _, err := t.reader.ReadRune() - if !t.eof && err == io.EOF { - t.eof = true - return t.buf, nil - } - if err != nil { - return t.buf, err - } - - t.eof = false - if t.matcher.MatchString(t.buf + string(r)) { - t.buf += string(r) - } else { - if t.matcher.MatchString(t.buf) { - result := t.buf - t.buf = string(r) - return result, nil - } else if t.matcher.MatchString(string(r)) { - t.buf = string(r) - } else { - t.buf = "" - } - } - } -} - -func parseCons(t *tokens) (*Object, error) { - car, err := parse(t) - if err != nil { - if err == errEOP { - return nil, nil - } - return nil, err - } - cdr, err := parseCons(t) - if err != nil { - return nil, err - } - return NewCons(car, cdr), nil -} - -func parseInteger(tok string) (*Object, error) { - start := 0 - if tok[0] == '+' || tok[0] == '-' { - start = 1 - } - if tok[start] == '#' { - base := 10 - if tok[start+1] == 'b' || tok[start+1] == 'B' { - base = 2 - } else if tok[start+1] == 'o' || tok[start+1] == 'O' { - base = 8 - } else if tok[start+1] == 'x' || tok[start+1] == 'X' { - base = 16 - } - num, err := strconv.ParseInt(tok[start+2:], base, 32) - if err != nil { - return nil, err - } - if tok[0] == '-' { - num = -num - } - return &Object{"integer", nil, nil, num}, nil - } - num, err := strconv.ParseInt(tok, 10, 32) - if err != nil { - return nil, err - } - return &Object{"integer", nil, nil, num}, nil -} - -func parseFloat(tok string) (*Object, error) { - e := strings.IndexRune(strings.ToUpper(tok), 'E') - if e > 0 { - num, err := strconv.ParseFloat(tok[:e], 32) - if err != nil { - return nil, err - } - exp, err := strconv.ParseFloat(tok[e+1:], 32) - if err != nil { - return nil, err - } - return &Object{"float", nil, nil, num * math.Pow(10.0, exp)}, nil - } - num, err := strconv.ParseFloat(tok, 32) - if err != nil { - return nil, err - } - return &Object{"float", nil, nil, num}, nil -} - -func parseCharacter(tok string) (*Object, error) { - if strings.ToLower(tok) == "newline" { - return &Object{"character", nil, nil, '\n'}, nil - } - if strings.ToLower(tok) == "space" { - return &Object{"character", nil, nil, ' '}, nil - } - if len(tok) != 3 { - return nil, errors.New("Invalid character name") - } - return &Object{"character", nil, nil, tok[2]}, nil -} - -func parseAtom(tok string, t *tokens) (*Object, error) { - if matched, _ := regexp.Match(macroSyntax, []byte(tok)); matched { - cdr, err := parse(t) - if err != nil { - return nil, err - } - return NewCons(&Object{"symbol", nil, nil, tok}, NewCons(cdr, nil)), nil - } - if matched, _ := regexp.Match(integerSyntax, []byte(tok)); matched { - n, err := parseInteger(tok) - if err != nil { - return nil, err - } - return n, nil - } - if matched, _ := regexp.Match(floatSyntax, []byte(tok)); matched { - f, err := parseFloat(tok) - if err != nil { - return nil, err - } - return f, nil - } - if matched, _ := regexp.Match(characterSyntax, []byte(tok)); matched { - c, err := parseCharacter(tok) - if err != nil { - return nil, err - } - return &Object{"character", nil, nil, c}, nil - } - if matched, _ := regexp.Match(stringSyntax, []byte(tok)); matched { - return &Object{"string", nil, nil, tok}, nil - } - if tok[0] != '|' { - return &Object{"symbol", nil, nil, strings.ToUpper(tok)}, nil - } - return &Object{"symbol", nil, nil, tok}, nil -} - -func parse(t *tokens) (*Object, error) { - tok, err := t.next() - if err != nil { - return nil, err - } - if tok == "(" { - cons, err := parseCons(t) - if err != nil { - return nil, err - } - return cons, err - } - if tok == ")" { - return nil, errEOP - } - atom, err := parseAtom(tok, t) - if err != nil { - return nil, err - } - return atom, nil -} - -func Read(r io.RuneReader) (*Object, error) { - exp, err := parse(tokenize(r)) - return exp, err -} diff --git a/reader.go b/reader.go new file mode 100644 index 0000000..e2b8f1d --- /dev/null +++ b/reader.go @@ -0,0 +1,155 @@ +package main + +import ( + "errors" + "math" + "regexp" + "strconv" + "strings" +) + +var errEOP = errors.New("End Of Parentheses") + +func ParseCons(t *Reader) (*Object, error) { + car, err := Parse(t) + if err == errEOP { + return nil, nil + } + if err != nil { + return nil, err + } + cdr, err := ParseCons(t) + if err != nil { + return nil, err + } + return NewCons(car, cdr), nil +} + +func ParseInteger(tok string) (*Object, error) { + start := 0 + if tok[0] == '+' || tok[0] == '-' { + start = 1 + } + if tok[start] == '#' { + base := 10 + if tok[start+1] == 'b' || tok[start+1] == 'B' { + base = 2 + } else if tok[start+1] == 'o' || tok[start+1] == 'O' { + base = 8 + } else if tok[start+1] == 'x' || tok[start+1] == 'X' { + base = 16 + } + num, err := strconv.ParseInt(tok[start+2:], base, 32) + if err != nil { + return nil, err + } + if tok[0] == '-' { + num = -num + } + return &Object{"integer", nil, nil, num}, nil + } + num, err := strconv.ParseInt(tok, 10, 32) + if err != nil { + return nil, err + } + return &Object{"integer", nil, nil, num}, nil +} + +func ParseFloat(tok string) (*Object, error) { + e := strings.IndexRune(strings.ToUpper(tok), 'E') + if e > 0 { + num, err := strconv.ParseFloat(tok[:e], 32) + if err != nil { + return nil, err + } + exp, err := strconv.ParseFloat(tok[e+1:], 32) + if err != nil { + return nil, err + } + return &Object{"float", nil, nil, num * math.Pow(10.0, exp)}, nil + } + num, err := strconv.ParseFloat(tok, 32) + if err != nil { + return nil, err + } + return &Object{"float", nil, nil, num}, nil +} + +func ParseCharacter(tok string) (*Object, error) { + if strings.ToLower(tok) == "newline" { + return &Object{"character", nil, nil, '\n'}, nil + } + if strings.ToLower(tok) == "space" { + return &Object{"character", nil, nil, ' '}, nil + } + if len(tok) != 3 { + return nil, errors.New("Invalid character name") + } + return &Object{"character", nil, nil, tok[2]}, nil +} + +func ParseAtom(tok string, t *Reader) (*Object, error) { + if matched, _ := regexp.Match(MacroToken, []byte(tok)); matched { + cdr, err := Parse(t) + if err != nil { + return nil, err + } + return NewCons(&Object{"symbol", nil, nil, tok}, NewCons(cdr, nil)), nil + } + if matched, _ := regexp.Match(IntegerToken, []byte(tok)); matched { + n, err := ParseInteger(tok) + if err != nil { + return nil, err + } + return n, nil + } + if matched, _ := regexp.Match(FloatToken, []byte(tok)); matched { + f, err := ParseFloat(tok) + if err != nil { + return nil, err + } + return f, nil + } + if matched, _ := regexp.Match(CharacterToken, []byte(tok)); matched { + c, err := ParseCharacter(tok) + if err != nil { + return nil, err + } + return c, nil + } + if matched, _ := regexp.Match(StringToken, []byte(tok)); matched { + return &Object{"string", nil, nil, tok}, nil + } + return &Object{"symbol", nil, nil, tok}, nil +} + +func Parse(t *Reader) (*Object, error) { + tok, err := t.ReadToken() + if err != nil { + return nil, err + } + if tok == "(" { + cons, err := ParseCons(t) + if err != nil { + return nil, err + } + return cons, err + } + if tok == ")" { + return nil, errEOP + } + atom, err := ParseAtom(tok, t) + if err != nil { + return nil, err + } + return atom, nil +} + +type ExpReader interface { + ReadExp() (*Object, error) +} + +func (r *Reader) ReadExp() (*Object, error) { + exp, err := Parse(r) + return exp, err +} diff --git a/tokenizer.go b/tokenizer.go new file mode 100644 index 0000000..ddde331 --- /dev/null +++ b/tokenizer.go @@ -0,0 +1,56 @@ +package main + +import ( + "regexp" + "strings" +) + +type TokenReader interface { + ReadToken() (rune, int, error) +} + +func NewMatcher(src ...string) *regexp.Regexp { + return regexp.MustCompile("^(?:" + strings.Join(src, ")$|^(?:") + ")$") +} + +var MacroToken = ",@|,|'|`" +var IntegerToken = "[+-]?[[:digit:]]+|#[bB][01]+|#[oO][0-7]+|#[xX][[:xdigit:]]+" +var FloatToken = "[+-]?[[:digit:]]+(?:.[[:digit:]]+|[eE][+-]?[[:digit:]]+|.[[:digit:]]+[eE][+-]?[[:digit:]]+)" +var CharacterToken = "#\\\\?|#\\\\(?:[[:alpha:]]+|[[:graph:]])" +var StringToken = "\"(?:\\\\\"|[^\"])*\"?" +var SymbolToken = "[<>/*=?_!$%[\\]^{}~a-zA-Z][<>/*=?_!$%[\\]^{}~0-9a-zA-Z]*|\\|(?:\\\\\\||[^|])*\\|?" +var ParenthesesToken = "\\(|\\)" + +var token = NewMatcher( + MacroToken, + IntegerToken, + FloatToken, + CharacterToken, + StringToken, + SymbolToken, + ParenthesesToken) + +func (tr *Reader) ReadToken() (string, error) { + buf := "" + for { + if buf == "" { + p, _, err := tr.PeekRune() + if err != nil { + return "", err + } + if token.MatchString(string(p)) { + buf = string(p) + } + } else { + p, _, err := tr.PeekRune() + if err != nil { + return buf, nil + } + if !token.MatchString(buf + string(p)) { + return buf, nil + } + buf += string(p) + } + tr.ReadRune() + } +} diff --git a/util.go b/util.go new file mode 100644 index 0000000..1bff765 --- /dev/null +++ b/util.go @@ -0,0 +1,29 @@ +package main + +import "io" + +type Reader struct { + err error + ru rune + sz int + rr io.RuneReader +} + +func NewReader(r io.RuneReader) *Reader { + b := new(Reader) + b.rr = r + b.ru, b.sz, b.err = b.rr.ReadRune() + return b +} + +func (tr *Reader) PeekRune() (rune, int, error) { + return tr.ru, tr.sz, tr.err +} + +func (tr *Reader) ReadRune() (rune, int, error) { + r := tr.ru + s := tr.sz + e := tr.err + tr.ru, tr.sz, tr.err = tr.rr.ReadRune() + return r, s, e +} From 9f94b809b93fd1773e506cc866bc13bafd097302 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Mon, 24 Jul 2017 12:19:30 +0900 Subject: [PATCH 008/228] added parser.go --- parser.go | 146 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ reader.go | 145 ----------------------------------------------------- 2 files changed, 146 insertions(+), 145 deletions(-) create mode 100644 parser.go diff --git a/parser.go b/parser.go new file mode 100644 index 0000000..429ce53 --- /dev/null +++ b/parser.go @@ -0,0 +1,146 @@ +package main + +import ( + "errors" + "math" + "regexp" + "strconv" + "strings" +) + +var errEOP = errors.New("End Of Parentheses") + +func ParseCons(t *Reader) (*Object, error) { + car, err := Parse(t) + if err == errEOP { + return nil, nil + } + if err != nil { + return nil, err + } + cdr, err := ParseCons(t) + if err != nil { + return nil, err + } + return NewCons(car, cdr), nil +} + +func ParseInteger(tok string) (*Object, error) { + start := 0 + if tok[0] == '+' || tok[0] == '-' { + start = 1 + } + if tok[start] == '#' { + base := 10 + if tok[start+1] == 'b' || tok[start+1] == 'B' { + base = 2 + } else if tok[start+1] == 'o' || tok[start+1] == 'O' { + base = 8 + } else if tok[start+1] == 'x' || tok[start+1] == 'X' { + base = 16 + } + num, err := strconv.ParseInt(tok[start+2:], base, 32) + if err != nil { + return nil, err + } + if tok[0] == '-' { + num = -num + } + return &Object{"integer", nil, nil, num}, nil + } + num, err := strconv.ParseInt(tok, 10, 32) + if err != nil { + return nil, err + } + return &Object{"integer", nil, nil, num}, nil +} + +func ParseFloat(tok string) (*Object, error) { + e := strings.IndexRune(strings.ToUpper(tok), 'E') + if e > 0 { + num, err := strconv.ParseFloat(tok[:e], 32) + if err != nil { + return nil, err + } + exp, err := strconv.ParseFloat(tok[e+1:], 32) + if err != nil { + return nil, err + } + return &Object{"float", nil, nil, num * math.Pow(10.0, exp)}, nil + } + num, err := strconv.ParseFloat(tok, 32) + if err != nil { + return nil, err + } + return &Object{"float", nil, nil, num}, nil +} + +func ParseCharacter(tok string) (*Object, error) { + if strings.ToLower(tok) == "newline" { + return &Object{"character", nil, nil, '\n'}, nil + } + if strings.ToLower(tok) == "space" { + return &Object{"character", nil, nil, ' '}, nil + } + if len(tok) != 3 { + return nil, errors.New("Invalid character name") + } + return &Object{"character", nil, nil, tok[2]}, nil +} + +func ParseAtom(tok string, t *Reader) (*Object, error) { + if matched, _ := regexp.Match(MacroToken, []byte(tok)); matched { + cdr, err := Parse(t) + if err != nil { + return nil, err + } + return NewCons(&Object{"symbol", nil, nil, tok}, NewCons(cdr, nil)), nil + } + if matched, _ := regexp.Match(IntegerToken, []byte(tok)); matched { + n, err := ParseInteger(tok) + if err != nil { + return nil, err + } + return n, nil + } + if matched, _ := regexp.Match(FloatToken, []byte(tok)); matched { + f, err := ParseFloat(tok) + if err != nil { + return nil, err + } + return f, nil + } + if matched, _ := regexp.Match(CharacterToken, []byte(tok)); matched { + c, err := ParseCharacter(tok) + if err != nil { + return nil, err + } + return c, nil + } + if matched, _ := regexp.Match(StringToken, []byte(tok)); matched { + return &Object{"string", nil, nil, tok}, nil + } + return &Object{"symbol", nil, nil, tok}, nil +} + +func Parse(t *Reader) (*Object, error) { + tok, err := t.ReadToken() + if err != nil { + return nil, err + } + if tok == "(" { + cons, err := ParseCons(t) + if err != nil { + return nil, err + } + return cons, err + } + if tok == ")" { + return nil, errEOP + } + atom, err := ParseAtom(tok, t) + if err != nil { + return nil, err + } + return atom, nil +} diff --git a/reader.go b/reader.go index e2b8f1d..e47a381 100644 --- a/reader.go +++ b/reader.go @@ -1,150 +1,5 @@ package main -import ( - "errors" - "math" - "regexp" - "strconv" - "strings" -) - -var errEOP = errors.New("End Of Parentheses") - -func ParseCons(t *Reader) (*Object, error) { - car, err := Parse(t) - if err == errEOP { - return nil, nil - } - if err != nil { - return nil, err - } - cdr, err := ParseCons(t) - if err != nil { - return nil, err - } - return NewCons(car, cdr), nil -} - -func ParseInteger(tok string) (*Object, error) { - start := 0 - if tok[0] == '+' || tok[0] == '-' { - start = 1 - } - if tok[start] == '#' { - base := 10 - if tok[start+1] == 'b' || tok[start+1] == 'B' { - base = 2 - } else if tok[start+1] == 'o' || tok[start+1] == 'O' { - base = 8 - } else if tok[start+1] == 'x' || tok[start+1] == 'X' { - base = 16 - } - num, err := strconv.ParseInt(tok[start+2:], base, 32) - if err != nil { - return nil, err - } - if tok[0] == '-' { - num = -num - } - return &Object{"integer", nil, nil, num}, nil - } - num, err := strconv.ParseInt(tok, 10, 32) - if err != nil { - return nil, err - } - return &Object{"integer", nil, nil, num}, nil -} - -func ParseFloat(tok string) (*Object, error) { - e := strings.IndexRune(strings.ToUpper(tok), 'E') - if e > 0 { - num, err := strconv.ParseFloat(tok[:e], 32) - if err != nil { - return nil, err - } - exp, err := strconv.ParseFloat(tok[e+1:], 32) - if err != nil { - return nil, err - } - return &Object{"float", nil, nil, num * math.Pow(10.0, exp)}, nil - } - num, err := strconv.ParseFloat(tok, 32) - if err != nil { - return nil, err - } - return &Object{"float", nil, nil, num}, nil -} - -func ParseCharacter(tok string) (*Object, error) { - if strings.ToLower(tok) == "newline" { - return &Object{"character", nil, nil, '\n'}, nil - } - if strings.ToLower(tok) == "space" { - return &Object{"character", nil, nil, ' '}, nil - } - if len(tok) != 3 { - return nil, errors.New("Invalid character name") - } - return &Object{"character", nil, nil, tok[2]}, nil -} - -func ParseAtom(tok string, t *Reader) (*Object, error) { - if matched, _ := regexp.Match(MacroToken, []byte(tok)); matched { - cdr, err := Parse(t) - if err != nil { - return nil, err - } - return NewCons(&Object{"symbol", nil, nil, tok}, NewCons(cdr, nil)), nil - } - if matched, _ := regexp.Match(IntegerToken, []byte(tok)); matched { - n, err := ParseInteger(tok) - if err != nil { - return nil, err - } - return n, nil - } - if matched, _ := regexp.Match(FloatToken, []byte(tok)); matched { - f, err := ParseFloat(tok) - if err != nil { - return nil, err - } - return f, nil - } - if matched, _ := regexp.Match(CharacterToken, []byte(tok)); matched { - c, err := ParseCharacter(tok) - if err != nil { - return nil, err - } - return c, nil - } - if matched, _ := regexp.Match(StringToken, []byte(tok)); matched { - return &Object{"string", nil, nil, tok}, nil - } - return &Object{"symbol", nil, nil, tok}, nil -} - -func Parse(t *Reader) (*Object, error) { - tok, err := t.ReadToken() - if err != nil { - return nil, err - } - if tok == "(" { - cons, err := ParseCons(t) - if err != nil { - return nil, err - } - return cons, err - } - if tok == ")" { - return nil, errEOP - } - atom, err := ParseAtom(tok, t) - if err != nil { - return nil, err - } - return atom, nil -} - type ExpReader interface { ReadExp() (*Object, error) } From f94fd8d303049d86debcf1de68c3400bc21d2db8 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Mon, 24 Jul 2017 12:52:59 +0900 Subject: [PATCH 009/228] deleted util.go --- parser.go | 22 +++++++++++----------- reader.go | 28 ++++++++++++++++++++++++++++ tokenizer.go | 4 ++-- util.go | 29 ----------------------------- 4 files changed, 41 insertions(+), 42 deletions(-) delete mode 100644 util.go diff --git a/parser.go b/parser.go index 429ce53..2bba37d 100644 --- a/parser.go +++ b/parser.go @@ -10,7 +10,7 @@ import ( var errEOP = errors.New("End Of Parentheses") -func ParseCons(t *Reader) (*Object, error) { +func parseCons(t *Reader) (*Object, error) { car, err := Parse(t) if err == errEOP { return nil, nil @@ -18,14 +18,14 @@ func ParseCons(t *Reader) (*Object, error) { if err != nil { return nil, err } - cdr, err := ParseCons(t) + cdr, err := parseCons(t) if err != nil { return nil, err } return NewCons(car, cdr), nil } -func ParseInteger(tok string) (*Object, error) { +func parseInteger(tok string) (*Object, error) { start := 0 if tok[0] == '+' || tok[0] == '-' { start = 1 @@ -55,7 +55,7 @@ func ParseInteger(tok string) (*Object, error) { return &Object{"integer", nil, nil, num}, nil } -func ParseFloat(tok string) (*Object, error) { +func parseFloat(tok string) (*Object, error) { e := strings.IndexRune(strings.ToUpper(tok), 'E') if e > 0 { num, err := strconv.ParseFloat(tok[:e], 32) @@ -75,7 +75,7 @@ func ParseFloat(tok string) (*Object, error) { return &Object{"float", nil, nil, num}, nil } -func ParseCharacter(tok string) (*Object, error) { +func parseCharacter(tok string) (*Object, error) { if strings.ToLower(tok) == "newline" { return &Object{"character", nil, nil, '\n'}, nil } @@ -88,7 +88,7 @@ func ParseCharacter(tok string) (*Object, error) { return &Object{"character", nil, nil, tok[2]}, nil } -func ParseAtom(tok string, t *Reader) (*Object, error) { +func parseAtom(tok string, t *Reader) (*Object, error) { if matched, _ := regexp.Match(MacroToken, []byte(tok)); matched { cdr, err := Parse(t) if err != nil { @@ -97,21 +97,21 @@ func ParseAtom(tok string, t *Reader) (*Object, error) { return NewCons(&Object{"symbol", nil, nil, tok}, NewCons(cdr, nil)), nil } if matched, _ := regexp.Match(IntegerToken, []byte(tok)); matched { - n, err := ParseInteger(tok) + n, err := parseInteger(tok) if err != nil { return nil, err } return n, nil } if matched, _ := regexp.Match(FloatToken, []byte(tok)); matched { - f, err := ParseFloat(tok) + f, err := parseFloat(tok) if err != nil { return nil, err } return f, nil } if matched, _ := regexp.Match(CharacterToken, []byte(tok)); matched { - c, err := ParseCharacter(tok) + c, err := parseCharacter(tok) if err != nil { return nil, err } @@ -129,7 +129,7 @@ func Parse(t *Reader) (*Object, error) { return nil, err } if tok == "(" { - cons, err := ParseCons(t) + cons, err := parseCons(t) if err != nil { return nil, err } @@ -138,7 +138,7 @@ func Parse(t *Reader) (*Object, error) { if tok == ")" { return nil, errEOP } - atom, err := ParseAtom(tok, t) + atom, err := parseAtom(tok, t) if err != nil { return nil, err } diff --git a/reader.go b/reader.go index e47a381..30fe343 100644 --- a/reader.go +++ b/reader.go @@ -1,5 +1,33 @@ package main +import "io" + +type Reader struct { + err error + ru rune + sz int + rr io.RuneReader +} + +func NewReader(r io.RuneReader) *Reader { + b := new(Reader) + b.rr = r + b.ru, b.sz, b.err = b.rr.ReadRune() + return b +} + +func (tr *Reader) PeekRune() (rune, int, error) { + return tr.ru, tr.sz, tr.err +} + +func (tr *Reader) ReadRune() (rune, int, error) { + r := tr.ru + s := tr.sz + e := tr.err + tr.ru, tr.sz, tr.err = tr.rr.ReadRune() + return r, s, e +} + type ExpReader interface { ReadExp() (*Object, error) } diff --git a/tokenizer.go b/tokenizer.go index ddde331..ecb4cbc 100644 --- a/tokenizer.go +++ b/tokenizer.go @@ -9,7 +9,7 @@ type TokenReader interface { ReadToken() (rune, int, error) } -func NewMatcher(src ...string) *regexp.Regexp { +func concatMatcher(src ...string) *regexp.Regexp { return regexp.MustCompile("^(?:" + strings.Join(src, ")$|^(?:") + ")$") } @@ -21,7 +21,7 @@ var StringToken = "\"(?:\\\\\"|[^\"])*\"?" var SymbolToken = "[<>/*=?_!$%[\\]^{}~a-zA-Z][<>/*=?_!$%[\\]^{}~0-9a-zA-Z]*|\\|(?:\\\\\\||[^|])*\\|?" var ParenthesesToken = "\\(|\\)" -var token = NewMatcher( +var token = concatMatcher( MacroToken, IntegerToken, FloatToken, diff --git a/util.go b/util.go deleted file mode 100644 index 1bff765..0000000 --- a/util.go +++ /dev/null @@ -1,29 +0,0 @@ -package main - -import "io" - -type Reader struct { - err error - ru rune - sz int - rr io.RuneReader -} - -func NewReader(r io.RuneReader) *Reader { - b := new(Reader) - b.rr = r - b.ru, b.sz, b.err = b.rr.ReadRune() - return b -} - -func (tr *Reader) PeekRune() (rune, int, error) { - return tr.ru, tr.sz, tr.err -} - -func (tr *Reader) ReadRune() (rune, int, error) { - r := tr.ru - s := tr.sz - e := tr.err - tr.ru, tr.sz, tr.err = tr.rr.ReadRune() - return r, s, e -} From c7f47d644413c910b289a9fb199ccaea55a10624 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Mon, 24 Jul 2017 13:06:52 +0900 Subject: [PATCH 010/228] update test example --- main.go | 2 +- parser.go | 48 ++++++++++++++++++++++++------------------------ 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/main.go b/main.go index 35b269b..0c53195 100644 --- a/main.go +++ b/main.go @@ -8,7 +8,7 @@ import ( ) func main() { - src := "(display #\\a) (println 10)" + src := "(display #\\a) (println '10)" r := NewReader(strings.NewReader(src)) for exp, err := r.ReadExp(); err != io.EOF; exp, err = r.ReadExp() { pp.Print(exp) diff --git a/parser.go b/parser.go index 2bba37d..811c9e9 100644 --- a/parser.go +++ b/parser.go @@ -10,22 +10,7 @@ import ( var errEOP = errors.New("End Of Parentheses") -func parseCons(t *Reader) (*Object, error) { - car, err := Parse(t) - if err == errEOP { - return nil, nil - } - if err != nil { - return nil, err - } - cdr, err := parseCons(t) - if err != nil { - return nil, err - } - return NewCons(car, cdr), nil -} - -func parseInteger(tok string) (*Object, error) { +func ParseInteger(tok string) (*Object, error) { start := 0 if tok[0] == '+' || tok[0] == '-' { start = 1 @@ -55,7 +40,7 @@ func parseInteger(tok string) (*Object, error) { return &Object{"integer", nil, nil, num}, nil } -func parseFloat(tok string) (*Object, error) { +func ParseFloat(tok string) (*Object, error) { e := strings.IndexRune(strings.ToUpper(tok), 'E') if e > 0 { num, err := strconv.ParseFloat(tok[:e], 32) @@ -75,7 +60,7 @@ func parseFloat(tok string) (*Object, error) { return &Object{"float", nil, nil, num}, nil } -func parseCharacter(tok string) (*Object, error) { +func ParseCharacter(tok string) (*Object, error) { if strings.ToLower(tok) == "newline" { return &Object{"character", nil, nil, '\n'}, nil } @@ -88,7 +73,7 @@ func parseCharacter(tok string) (*Object, error) { return &Object{"character", nil, nil, tok[2]}, nil } -func parseAtom(tok string, t *Reader) (*Object, error) { +func ParseAtom(tok string, t *Reader) (*Object, error) { if matched, _ := regexp.Match(MacroToken, []byte(tok)); matched { cdr, err := Parse(t) if err != nil { @@ -97,21 +82,21 @@ func parseAtom(tok string, t *Reader) (*Object, error) { return NewCons(&Object{"symbol", nil, nil, tok}, NewCons(cdr, nil)), nil } if matched, _ := regexp.Match(IntegerToken, []byte(tok)); matched { - n, err := parseInteger(tok) + n, err := ParseInteger(tok) if err != nil { return nil, err } return n, nil } if matched, _ := regexp.Match(FloatToken, []byte(tok)); matched { - f, err := parseFloat(tok) + f, err := ParseFloat(tok) if err != nil { return nil, err } return f, nil } if matched, _ := regexp.Match(CharacterToken, []byte(tok)); matched { - c, err := parseCharacter(tok) + c, err := ParseCharacter(tok) if err != nil { return nil, err } @@ -123,13 +108,28 @@ func parseAtom(tok string, t *Reader) (*Object, error) { return &Object{"symbol", nil, nil, tok}, nil } +func ParseCons(t *Reader) (*Object, error) { + car, err := Parse(t) + if err == errEOP { + return nil, nil + } + if err != nil { + return nil, err + } + cdr, err := ParseCons(t) + if err != nil { + return nil, err + } + return NewCons(car, cdr), nil +} + func Parse(t *Reader) (*Object, error) { tok, err := t.ReadToken() if err != nil { return nil, err } if tok == "(" { - cons, err := parseCons(t) + cons, err := ParseCons(t) if err != nil { return nil, err } @@ -138,7 +138,7 @@ func Parse(t *Reader) (*Object, error) { if tok == ")" { return nil, errEOP } - atom, err := parseAtom(tok, t) + atom, err := ParseAtom(tok, t) if err != nil { return nil, err } From edc3866b09e035ede6267323024819cf777d5d5c Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Mon, 24 Jul 2017 14:26:41 +0900 Subject: [PATCH 011/228] added new syntax for dot cons --- main.go | 2 +- tokenizer.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/main.go b/main.go index 0c53195..3f63e43 100644 --- a/main.go +++ b/main.go @@ -8,7 +8,7 @@ import ( ) func main() { - src := "(display #\\a) (println '10)" + src := "(display . print)" r := NewReader(strings.NewReader(src)) for exp, err := r.ReadExp(); err != io.EOF; exp, err = r.ReadExp() { pp.Print(exp) diff --git a/tokenizer.go b/tokenizer.go index ecb4cbc..2ff60d5 100644 --- a/tokenizer.go +++ b/tokenizer.go @@ -19,7 +19,7 @@ var FloatToken = "[+-]?[[:digit:]]+(?:.[[:digit:]]+|[eE][+-]?[[:digit:]]+|.[[:di var CharacterToken = "#\\\\?|#\\\\(?:[[:alpha:]]+|[[:graph:]])" var StringToken = "\"(?:\\\\\"|[^\"])*\"?" var SymbolToken = "[<>/*=?_!$%[\\]^{}~a-zA-Z][<>/*=?_!$%[\\]^{}~0-9a-zA-Z]*|\\|(?:\\\\\\||[^|])*\\|?" -var ParenthesesToken = "\\(|\\)" +var ParenthesesToken = "\\.|\\(|\\)" var token = concatMatcher( MacroToken, From 1b12818d363697b067bf2e9e1d745c2dc5a4b766 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Mon, 24 Jul 2017 16:16:05 +0900 Subject: [PATCH 012/228] added array syntax --- main.go | 2 +- parser.go | 61 ++++++++++++++++++++++++++++++++++++++++++++++------ tokenizer.go | 2 +- 3 files changed, 56 insertions(+), 9 deletions(-) diff --git a/main.go b/main.go index 3f63e43..ae20589 100644 --- a/main.go +++ b/main.go @@ -8,7 +8,7 @@ import ( ) func main() { - src := "(display . print)" + src := "#3a(1 2 3)" r := NewReader(strings.NewReader(src)) for exp, err := r.ReadExp(); err != io.EOF; exp, err = r.ReadExp() { pp.Print(exp) diff --git a/parser.go b/parser.go index 811c9e9..b4be23b 100644 --- a/parser.go +++ b/parser.go @@ -9,6 +9,7 @@ import ( ) var errEOP = errors.New("End Of Parentheses") +var errDOT = errors.New("Dot Cons") func ParseInteger(tok string) (*Object, error) { start := 0 @@ -73,36 +74,69 @@ func ParseCharacter(tok string) (*Object, error) { return &Object{"character", nil, nil, tok[2]}, nil } +func ParseArray(tok string) (*Object, error) { + a := &Object{"symbol", nil, nil, "array"} + d := &Object{"integer", nil, nil, 0} + i := strings.IndexRune(strings.ToLower(tok), 'a') + if i == 1 { + d.Val = 1 + } else { + v, err := strconv.Atoi(tok[1:i]) + if err != nil { + return nil, err + } + d.Val = v + } + return NewCons(a, NewCons(d, NewCons(nil, nil))), nil +} + +func ParseMacro(tok string, t *Reader) (*Object, error) { + cdr, err := Parse(t) + if err != nil { + return nil, err + } + if matched, _ := regexp.MatchString("#[[:digit]]*[aA]", tok); matched { + a, err := ParseArray(tok) + if err != nil { + return nil, err + } + a.Cdr.Cdr.Car = cdr + return a, nil + } + m := &Object{"symbol", nil, nil, tok} + return NewCons(m, NewCons(cdr, nil)), nil +} + func ParseAtom(tok string, t *Reader) (*Object, error) { - if matched, _ := regexp.Match(MacroToken, []byte(tok)); matched { - cdr, err := Parse(t) + if matched, _ := regexp.MatchString(MacroToken, tok); matched { + m, err := ParseMacro(tok, t) if err != nil { return nil, err } - return NewCons(&Object{"symbol", nil, nil, tok}, NewCons(cdr, nil)), nil + return m, nil } - if matched, _ := regexp.Match(IntegerToken, []byte(tok)); matched { + if matched, _ := regexp.MatchString(IntegerToken, tok); matched { n, err := ParseInteger(tok) if err != nil { return nil, err } return n, nil } - if matched, _ := regexp.Match(FloatToken, []byte(tok)); matched { + if matched, _ := regexp.MatchString(FloatToken, tok); matched { f, err := ParseFloat(tok) if err != nil { return nil, err } return f, nil } - if matched, _ := regexp.Match(CharacterToken, []byte(tok)); matched { + if matched, _ := regexp.MatchString(CharacterToken, tok); matched { c, err := ParseCharacter(tok) if err != nil { return nil, err } return c, nil } - if matched, _ := regexp.Match(StringToken, []byte(tok)); matched { + if matched, _ := regexp.MatchString(StringToken, tok); matched { return &Object{"string", nil, nil, tok}, nil } return &Object{"symbol", nil, nil, tok}, nil @@ -113,6 +147,16 @@ func ParseCons(t *Reader) (*Object, error) { if err == errEOP { return nil, nil } + if err == errDOT { + cdr, err := Parse(t) + if err != nil { + return nil, err + } + if _, err := Parse(t); err != errEOP { + return nil, errors.New("Invalid syntax") + } + return cdr, nil + } if err != nil { return nil, err } @@ -138,6 +182,9 @@ func Parse(t *Reader) (*Object, error) { if tok == ")" { return nil, errEOP } + if tok == "." { + return nil, errDOT + } atom, err := ParseAtom(tok, t) if err != nil { return nil, err diff --git a/tokenizer.go b/tokenizer.go index 2ff60d5..02fb839 100644 --- a/tokenizer.go +++ b/tokenizer.go @@ -13,7 +13,7 @@ func concatMatcher(src ...string) *regexp.Regexp { return regexp.MustCompile("^(?:" + strings.Join(src, ")$|^(?:") + ")$") } -var MacroToken = ",@|,|'|`" +var MacroToken = "#[[:digit:]]*[aA]?|,@|,|'|`" var IntegerToken = "[+-]?[[:digit:]]+|#[bB][01]+|#[oO][0-7]+|#[xX][[:xdigit:]]+" var FloatToken = "[+-]?[[:digit:]]+(?:.[[:digit:]]+|[eE][+-]?[[:digit:]]+|.[[:digit:]]+[eE][+-]?[[:digit:]]+)" var CharacterToken = "#\\\\?|#\\\\(?:[[:alpha:]]+|[[:graph:]])" From f6c85162be6c8a4d857e0f37aa8c18c59707d9c4 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Mon, 24 Jul 2017 16:37:12 +0900 Subject: [PATCH 013/228] change macro symbol name --- main.go | 2 +- parser.go | 50 ++++++++++++++++++++++++++------------------------ 2 files changed, 27 insertions(+), 25 deletions(-) diff --git a/main.go b/main.go index ae20589..dd257ca 100644 --- a/main.go +++ b/main.go @@ -8,7 +8,7 @@ import ( ) func main() { - src := "#3a(1 2 3)" + src := "'#3a(1 2 3)" r := NewReader(strings.NewReader(src)) for exp, err := r.ReadExp(); err != io.EOF; exp, err = r.ReadExp() { pp.Print(exp) diff --git a/parser.go b/parser.go index b4be23b..dd5e231 100644 --- a/parser.go +++ b/parser.go @@ -74,36 +74,38 @@ func ParseCharacter(tok string) (*Object, error) { return &Object{"character", nil, nil, tok[2]}, nil } -func ParseArray(tok string) (*Object, error) { - a := &Object{"symbol", nil, nil, "array"} - d := &Object{"integer", nil, nil, 0} - i := strings.IndexRune(strings.ToLower(tok), 'a') - if i == 1 { - d.Val = 1 - } else { - v, err := strconv.Atoi(tok[1:i]) - if err != nil { - return nil, err - } - d.Val = v - } - return NewCons(a, NewCons(d, NewCons(nil, nil))), nil -} - func ParseMacro(tok string, t *Reader) (*Object, error) { cdr, err := Parse(t) if err != nil { return nil, err } - if matched, _ := regexp.MatchString("#[[:digit]]*[aA]", tok); matched { - a, err := ParseArray(tok) - if err != nil { - return nil, err + n := tok + if m, _ := regexp.MatchString("#[[:digit:]]*[aA]", tok); m { + s := &Object{"symbol", nil, nil, "array"} + d := &Object{"integer", nil, nil, 0} + i := strings.IndexRune(strings.ToLower(tok), 'a') + if i == 1 { + d.Val = 1 + } else { + v, err := strconv.Atoi(tok[1:i]) + if err != nil { + return nil, err + } + d.Val = v } - a.Cdr.Cdr.Car = cdr - return a, nil - } - m := &Object{"symbol", nil, nil, tok} + return NewCons(s, NewCons(d, NewCons(cdr, nil))), nil + } + switch tok { + case ",@": + n = "commaat" + case ",": + n = "comma" + case "'": + n = "quote" + case "`": + n = "backquote" + } + m := &Object{"symbol", nil, nil, n} return NewCons(m, NewCons(cdr, nil)), nil } From c89a35a4c9100628c6d22117548770337fabd1aa Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Mon, 24 Jul 2017 23:23:55 +0900 Subject: [PATCH 014/228] added test for tokenizer --- object.go | 3 +++ parser.go | 41 ++++++++++++++++++++++++----------------- tokenizer.go | 38 +++++++++++++++++++------------------- tokenizer_test.go | 16 ++++++++++++++++ 4 files changed, 62 insertions(+), 36 deletions(-) create mode 100644 tokenizer_test.go diff --git a/object.go b/object.go index 23f69ac..2066be4 100644 --- a/object.go +++ b/object.go @@ -8,6 +8,9 @@ type Object struct { } func NewCons(car *Object, cdr *Object) *Object { + if cdr == nil || cdr.Type == "list" { + return &Object{"list", car, cdr, nil} + } return &Object{"cons", car, cdr, nil} } diff --git a/parser.go b/parser.go index dd5e231..89d7c5a 100644 --- a/parser.go +++ b/parser.go @@ -2,14 +2,15 @@ package main import ( "errors" + "fmt" "math" "regexp" "strconv" "strings" ) -var errEOP = errors.New("End Of Parentheses") -var errDOT = errors.New("Dot Cons") +var EOP = errors.New("End Of Parentheses") +var BOD = errors.New("Begin Of Dot") func ParseInteger(tok string) (*Object, error) { start := 0 @@ -74,7 +75,7 @@ func ParseCharacter(tok string) (*Object, error) { return &Object{"character", nil, nil, tok[2]}, nil } -func ParseMacro(tok string, t *Reader) (*Object, error) { +func ParseMacro(tok string, t TokenReader) (*Object, error) { cdr, err := Parse(t) if err != nil { return nil, err @@ -109,52 +110,58 @@ func ParseMacro(tok string, t *Reader) (*Object, error) { return NewCons(m, NewCons(cdr, nil)), nil } -func ParseAtom(tok string, t *Reader) (*Object, error) { - if matched, _ := regexp.MatchString(MacroToken, tok); matched { +func ParseAtom(tok string, t TokenReader) (*Object, error) { + if matched, _ := regexp.MatchString("^(?:,@?|'|`|#[[:digit:]]*[aA])$", tok); matched { m, err := ParseMacro(tok, t) if err != nil { return nil, err } return m, nil } - if matched, _ := regexp.MatchString(IntegerToken, tok); matched { + if matched, _ := regexp.MatchString("^(?:[+-]?(?:[[:digit:]]+|#[bB][01]+|#[oO][0-7]+|#[xX][[:xdigit:]]+))$", tok); matched { n, err := ParseInteger(tok) if err != nil { return nil, err } return n, nil } - if matched, _ := regexp.MatchString(FloatToken, tok); matched { + if matched, _ := regexp.MatchString("^(?:[+-][[:digit:]]+(?:\\.[[:digit:]])?(?:[eE][-+]?[[:digit:]]+))?$", tok); matched { f, err := ParseFloat(tok) if err != nil { return nil, err } return f, nil } - if matched, _ := regexp.MatchString(CharacterToken, tok); matched { + if matched, _ := regexp.MatchString("^(?:#\\\\[[:graph:]]|#\\\\(?:[nN][eE][wW][lL][iI][nN][eE]|[sS][pP][aA][cC][eE]))$", tok); matched { c, err := ParseCharacter(tok) if err != nil { return nil, err } return c, nil } - if matched, _ := regexp.MatchString(StringToken, tok); matched { + if matched, _ := regexp.MatchString("^\".*\"$", tok); matched { return &Object{"string", nil, nil, tok}, nil } - return &Object{"symbol", nil, nil, tok}, nil + if matched, _ := regexp.MatchString("^\\|.*\\|$", tok); matched { + return &Object{"symbol", nil, nil, tok}, nil + } + if matched, _ := regexp.MatchString("[<>/*=?_!$%[\\]^{}~a-zA-Z][<>/*=?_!$%[\\]^{}~0-9a-zA-Z]*", tok); matched { + return &Object{"symbol", nil, nil, strings.ToUpper(tok)}, nil + } + return nil, fmt.Errorf("Sorry, I could not parse %s", tok) } -func ParseCons(t *Reader) (*Object, error) { +func ParseCons(t TokenReader) (*Object, error) { car, err := Parse(t) - if err == errEOP { + if err == EOP { return nil, nil } - if err == errDOT { + if err == BOD { cdr, err := Parse(t) if err != nil { return nil, err } - if _, err := Parse(t); err != errEOP { + if _, err := Parse(t); err != EOP { return nil, errors.New("Invalid syntax") } return cdr, nil @@ -169,7 +176,7 @@ func ParseCons(t *Reader) (*Object, error) { return NewCons(car, cdr), nil } -func Parse(t *Reader) (*Object, error) { +func Parse(t TokenReader) (*Object, error) { tok, err := t.ReadToken() if err != nil { return nil, err @@ -182,10 +189,10 @@ func Parse(t *Reader) (*Object, error) { return cons, err } if tok == ")" { - return nil, errEOP + return nil, EOP } if tok == "." { - return nil, errDOT + return nil, BOD } atom, err := ParseAtom(tok, t) if err != nil { diff --git a/tokenizer.go b/tokenizer.go index 02fb839..b1ef98e 100644 --- a/tokenizer.go +++ b/tokenizer.go @@ -6,35 +6,35 @@ import ( ) type TokenReader interface { - ReadToken() (rune, int, error) + ReadToken() (string, error) } func concatMatcher(src ...string) *regexp.Regexp { return regexp.MustCompile("^(?:" + strings.Join(src, ")$|^(?:") + ")$") } -var MacroToken = "#[[:digit:]]*[aA]?|,@|,|'|`" -var IntegerToken = "[+-]?[[:digit:]]+|#[bB][01]+|#[oO][0-7]+|#[xX][[:xdigit:]]+" -var FloatToken = "[+-]?[[:digit:]]+(?:.[[:digit:]]+|[eE][+-]?[[:digit:]]+|.[[:digit:]]+[eE][+-]?[[:digit:]]+)" -var CharacterToken = "#\\\\?|#\\\\(?:[[:alpha:]]+|[[:graph:]])" -var StringToken = "\"(?:\\\\\"|[^\"])*\"?" -var SymbolToken = "[<>/*=?_!$%[\\]^{}~a-zA-Z][<>/*=?_!$%[\\]^{}~0-9a-zA-Z]*|\\|(?:\\\\\\||[^|])*\\|?" -var ParenthesesToken = "\\.|\\(|\\)" +var macro = strings.Join([]string{"#(?:[[:digit:]]+[aA]?)?", ",@?", "'", "`"}, "|") +var integer = strings.Join([]string{"[[:digit:]]+", "[+-][[:digit:]]*", "#(?:[bB][01]*)?", "#(?:[oO][0-7]*)?", "#(?:[xX][[:xdigit:]]*)?"}, "|") +var float = strings.Join([]string{"[[:digit:]]+(?:\\.?[[:digit:]]*(?:[eE](?:[-+]?[[:digit:]]*)?)?)?", "[+-](?:[[:digit:]]+(?:\\.?[[:digit:]]*(?:[eE](?:[-+]?[[:digit:]]*)?)?)?)?"}, "|") +var character = strings.Join([]string{"#(?:\\\\[[:alpha:]]*)?", "#(?:\\\\[[:graph:]]?)?"}, "|") +var str = strings.Join([]string{"\"(?:\\\\\"|[^\"])*\"?"}, "|") +var symbol = strings.Join([]string{"[<>/*=?_!$%[\\]^{}~a-zA-Z][<>/*=?_!$%[\\]^{}~0-9a-zA-Z]*", "\\|(?:\\\\\\||[^|])*\\|?"}, "|") +var parentheses = strings.Join([]string{"\\.", "\\(", "\\)"}, "|") var token = concatMatcher( - MacroToken, - IntegerToken, - FloatToken, - CharacterToken, - StringToken, - SymbolToken, - ParenthesesToken) + macro, + integer, + float, + character, + str, + symbol, + parentheses) -func (tr *Reader) ReadToken() (string, error) { +func (r *Reader) ReadToken() (string, error) { buf := "" for { if buf == "" { - p, _, err := tr.PeekRune() + p, _, err := r.PeekRune() if err != nil { return "", err } @@ -42,7 +42,7 @@ func (tr *Reader) ReadToken() (string, error) { buf = string(p) } } else { - p, _, err := tr.PeekRune() + p, _, err := r.PeekRune() if err != nil { return buf, nil } @@ -51,6 +51,6 @@ func (tr *Reader) ReadToken() (string, error) { } buf += string(p) } - tr.ReadRune() + r.ReadRune() } } diff --git a/tokenizer_test.go b/tokenizer_test.go new file mode 100644 index 0000000..24e4aff --- /dev/null +++ b/tokenizer_test.go @@ -0,0 +1,16 @@ +package main + +import ( + "strings" + "testing" +) + +func TestReadToken(t *testing.T) { + ans := []string{"(", "print", "#\\a", ")", "(", "cons", "'", "a", "'", "(", "1", ".", "1.3E-10", ")", ")"} + re := NewReader(strings.NewReader("(print #\\a) (cons 'a '(1 . 1.3E-10))")) + for _, a := range ans { + if b, err := re.ReadToken(); err != nil || a != b { + t.Errorf("%s is not %s.", b, a) + } + } +} From a0128678014c8cc5dcb0d880d82c0689892b8e8d Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Tue, 25 Jul 2017 10:32:40 +0900 Subject: [PATCH 015/228] Added comments --- object.go | 3 +++ parser.go | 41 +++++++++++++++++++++-------------------- reader.go | 23 +++++++++++++++-------- tokenizer.go | 2 ++ 4 files changed, 41 insertions(+), 28 deletions(-) diff --git a/object.go b/object.go index 2066be4..7c4da8c 100644 --- a/object.go +++ b/object.go @@ -1,5 +1,6 @@ package main +// Object struct type is the struct for the internal representations type Object struct { Type string Car *Object @@ -7,6 +8,7 @@ type Object struct { Val interface{} } +// NewCons creates cons pair from two objects func NewCons(car *Object, cdr *Object) *Object { if cdr == nil || cdr.Type == "list" { return &Object{"list", car, cdr, nil} @@ -14,6 +16,7 @@ func NewCons(car *Object, cdr *Object) *Object { return &Object{"cons", car, cdr, nil} } +// Is is for testing func (o *Object) Is(val interface{}) bool { return o.Val == val } diff --git a/parser.go b/parser.go index 89d7c5a..5339a52 100644 --- a/parser.go +++ b/parser.go @@ -9,10 +9,10 @@ import ( "strings" ) -var EOP = errors.New("End Of Parentheses") -var BOD = errors.New("Begin Of Dot") +var errEOP = errors.New("End Of Parentheses") +var errBOD = errors.New("Begin Of Dot") -func ParseInteger(tok string) (*Object, error) { +func parseInteger(tok string) (*Object, error) { start := 0 if tok[0] == '+' || tok[0] == '-' { start = 1 @@ -42,7 +42,7 @@ func ParseInteger(tok string) (*Object, error) { return &Object{"integer", nil, nil, num}, nil } -func ParseFloat(tok string) (*Object, error) { +func parseFloat(tok string) (*Object, error) { e := strings.IndexRune(strings.ToUpper(tok), 'E') if e > 0 { num, err := strconv.ParseFloat(tok[:e], 32) @@ -62,7 +62,7 @@ func ParseFloat(tok string) (*Object, error) { return &Object{"float", nil, nil, num}, nil } -func ParseCharacter(tok string) (*Object, error) { +func parseCharacter(tok string) (*Object, error) { if strings.ToLower(tok) == "newline" { return &Object{"character", nil, nil, '\n'}, nil } @@ -75,7 +75,7 @@ func ParseCharacter(tok string) (*Object, error) { return &Object{"character", nil, nil, tok[2]}, nil } -func ParseMacro(tok string, t TokenReader) (*Object, error) { +func parseMacro(tok string, t TokenReader) (*Object, error) { cdr, err := Parse(t) if err != nil { return nil, err @@ -110,30 +110,30 @@ func ParseMacro(tok string, t TokenReader) (*Object, error) { return NewCons(m, NewCons(cdr, nil)), nil } -func ParseAtom(tok string, t TokenReader) (*Object, error) { +func parseAtom(tok string, t TokenReader) (*Object, error) { if matched, _ := regexp.MatchString("^(?:,@?|'|`|#[[:digit:]]*[aA])$", tok); matched { - m, err := ParseMacro(tok, t) + m, err := parseMacro(tok, t) if err != nil { return nil, err } return m, nil } if matched, _ := regexp.MatchString("^(?:[+-]?(?:[[:digit:]]+|#[bB][01]+|#[oO][0-7]+|#[xX][[:xdigit:]]+))$", tok); matched { - n, err := ParseInteger(tok) + n, err := parseInteger(tok) if err != nil { return nil, err } return n, nil } if matched, _ := regexp.MatchString("^(?:[+-][[:digit:]]+(?:\\.[[:digit:]])?(?:[eE][-+]?[[:digit:]]+))?$", tok); matched { - f, err := ParseFloat(tok) + f, err := parseFloat(tok) if err != nil { return nil, err } return f, nil } if matched, _ := regexp.MatchString("^(?:#\\\\[[:graph:]]|#\\\\(?:[nN][eE][wW][lL][iI][nN][eE]|[sS][pP][aA][cC][eE]))$", tok); matched { - c, err := ParseCharacter(tok) + c, err := parseCharacter(tok) if err != nil { return nil, err } @@ -151,17 +151,17 @@ func ParseAtom(tok string, t TokenReader) (*Object, error) { return nil, fmt.Errorf("Sorry, I could not parse %s", tok) } -func ParseCons(t TokenReader) (*Object, error) { +func parseCons(t TokenReader) (*Object, error) { car, err := Parse(t) - if err == EOP { + if err == errEOP { return nil, nil } - if err == BOD { + if err == errBOD { cdr, err := Parse(t) if err != nil { return nil, err } - if _, err := Parse(t); err != EOP { + if _, err := Parse(t); err != errEOP { return nil, errors.New("Invalid syntax") } return cdr, nil @@ -169,32 +169,33 @@ func ParseCons(t TokenReader) (*Object, error) { if err != nil { return nil, err } - cdr, err := ParseCons(t) + cdr, err := parseCons(t) if err != nil { return nil, err } return NewCons(car, cdr), nil } +// Parse builds a internal expression from tokens func Parse(t TokenReader) (*Object, error) { tok, err := t.ReadToken() if err != nil { return nil, err } if tok == "(" { - cons, err := ParseCons(t) + cons, err := parseCons(t) if err != nil { return nil, err } return cons, err } if tok == ")" { - return nil, EOP + return nil, errEOP } if tok == "." { - return nil, BOD + return nil, errBOD } - atom, err := ParseAtom(tok, t) + atom, err := parseAtom(tok, t) if err != nil { return nil, err } diff --git a/reader.go b/reader.go index 30fe343..0f96a09 100644 --- a/reader.go +++ b/reader.go @@ -2,6 +2,8 @@ package main import "io" +// Reader is like bufio.Reader but has PeekRune +// which returns a rune without advancing pointer type Reader struct { err error ru rune @@ -9,6 +11,7 @@ type Reader struct { rr io.RuneReader } +// NewReader creates interal reader from io.RuneReader func NewReader(r io.RuneReader) *Reader { b := new(Reader) b.rr = r @@ -16,22 +19,26 @@ func NewReader(r io.RuneReader) *Reader { return b } -func (tr *Reader) PeekRune() (rune, int, error) { - return tr.ru, tr.sz, tr.err +// PeekRune returns a rune without advancing pointer +func (r *Reader) PeekRune() (rune, int, error) { + return r.ru, r.sz, r.err } -func (tr *Reader) ReadRune() (rune, int, error) { - r := tr.ru - s := tr.sz - e := tr.err - tr.ru, tr.sz, tr.err = tr.rr.ReadRune() - return r, s, e +// ReadRune returns a rune with advancing pointer +func (r *Reader) ReadRune() (rune, int, error) { + ru := r.ru + sz := r.sz + err := r.err + r.ru, r.sz, r.err = r.rr.ReadRune() + return ru, sz, err } +// ExpReader interface type is the interface for reading expressions. type ExpReader interface { ReadExp() (*Object, error) } +// ReadExp returns a expression that is a pointer to Object func (r *Reader) ReadExp() (*Object, error) { exp, err := Parse(r) return exp, err diff --git a/tokenizer.go b/tokenizer.go index b1ef98e..fd528a9 100644 --- a/tokenizer.go +++ b/tokenizer.go @@ -5,6 +5,7 @@ import ( "strings" ) +// TokenReader interface type is the interface for reading string with every token type TokenReader interface { ReadToken() (string, error) } @@ -30,6 +31,7 @@ var token = concatMatcher( symbol, parentheses) +// ReadToken returns error or string as token func (r *Reader) ReadToken() (string, error) { buf := "" for { From e39a775745930f6a86eeed980053216415fa6f42 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Tue, 25 Jul 2017 10:32:50 +0900 Subject: [PATCH 016/228] Added test for parser --- parser_test.go | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 parser_test.go diff --git a/parser_test.go b/parser_test.go new file mode 100644 index 0000000..59547a3 --- /dev/null +++ b/parser_test.go @@ -0,0 +1,15 @@ +package main + +import ( + "strings" + "testing" +) + +func TestParse(t *testing.T) { + r := NewReader(strings.NewReader("(print #\\a) (cons 'a '(1 . 1.3E-10))")) + for i := 0; i < 2; i++ { + if _, err := Parse(r); err != nil { + t.Error("Parser couldn't parse") + } + } +} From ffb7e6a6b8a80b844f8b282b1ebe71e8a280ec4d Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Tue, 25 Jul 2017 14:06:54 +0900 Subject: [PATCH 017/228] added parseInteget test --- parser_test.go | 72 +++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 65 insertions(+), 7 deletions(-) diff --git a/parser_test.go b/parser_test.go index 59547a3..b438dba 100644 --- a/parser_test.go +++ b/parser_test.go @@ -1,15 +1,73 @@ package main import ( - "strings" + "reflect" "testing" ) -func TestParse(t *testing.T) { - r := NewReader(strings.NewReader("(print #\\a) (cons 'a '(1 . 1.3E-10))")) - for i := 0; i < 2; i++ { - if _, err := Parse(r); err != nil { - t.Error("Parser couldn't parse") - } +func Test_parseInteger(t *testing.T) { + type args struct { + tok string + } + tests := []struct { + name string + args args + want *Object + wantErr bool + }{ + { + name: "signed", + args: args{"-5"}, + want: &Object{"integer", nil, nil, -5}, + wantErr: false, + }, + { + name: "binary", + args: args{"#B00101"}, + want: &Object{"integer", nil, nil, 5}, + wantErr: false, + }, + { + name: "signed binary", + args: args{"#b-00101"}, + want: &Object{"integer", nil, nil, -5}, + wantErr: false, + }, + { + name: "octal", + args: args{"#o00101"}, + want: &Object{"integer", nil, nil, 65}, + wantErr: false, + }, + { + name: "signed octal", + args: args{"#O-00101"}, + want: &Object{"integer", nil, nil, -65}, + wantErr: false, + }, + { + name: "hexadecimal", + args: args{"#X00101"}, + want: &Object{"integer", nil, nil, 257}, + wantErr: false, + }, + { + name: "signed hexadecimal", + args: args{"#x-00101"}, + want: &Object{"integer", nil, nil, -257}, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := parseInteger(tt.args.tok) + if (err != nil) != tt.wantErr { + t.Errorf("parseInteger() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("parseInteger() = %v, want %v", got, tt.want) + } + }) } } From 8cd3a1f0b1db0ce5d084a17db3171fc6a835f26a Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Tue, 25 Jul 2017 14:07:11 +0900 Subject: [PATCH 018/228] added unit test --- tokenizer_test.go | 45 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 38 insertions(+), 7 deletions(-) diff --git a/tokenizer_test.go b/tokenizer_test.go index 24e4aff..3374e70 100644 --- a/tokenizer_test.go +++ b/tokenizer_test.go @@ -1,16 +1,47 @@ package main import ( + "io" "strings" "testing" ) -func TestReadToken(t *testing.T) { - ans := []string{"(", "print", "#\\a", ")", "(", "cons", "'", "a", "'", "(", "1", ".", "1.3E-10", ")", ")"} - re := NewReader(strings.NewReader("(print #\\a) (cons 'a '(1 . 1.3E-10))")) - for _, a := range ans { - if b, err := re.ReadToken(); err != nil || a != b { - t.Errorf("%s is not %s.", b, a) - } +func TestReader_ReadToken(t *testing.T) { + type fields struct { + err error + ru rune + sz int + rr io.RuneReader + } + tests := []struct { + name string + fields fields + want string + wantErr bool + }{ + { + name: "symbol", + fields: fields{nil, 'd', 8, strings.NewReader("efault")}, + want: "default", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + r := &Reader{ + err: tt.fields.err, + ru: tt.fields.ru, + sz: tt.fields.sz, + rr: tt.fields.rr, + } + got, err := r.ReadToken() + if (err != nil) != tt.wantErr { + t.Errorf("Reader.ReadToken() error = %v, wantErr %v", err, tt.wantErr) + return + } + if got != tt.want { + t.Errorf("Reader.ReadToken() = %v, want %v", got, tt.want) + } + }) } } From fc19a182240b1624d9f2a4bbb1507cc7a7a8299d Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Tue, 25 Jul 2017 14:07:22 +0900 Subject: [PATCH 019/228] Added reference --- parser.go | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/parser.go b/parser.go index 5339a52..a71c6d6 100644 --- a/parser.go +++ b/parser.go @@ -13,6 +13,7 @@ var errEOP = errors.New("End Of Parentheses") var errBOD = errors.New("Begin Of Dot") func parseInteger(tok string) (*Object, error) { + // TODO: http://minejima.jp/ISLispHyperDraft/islisp-v23.html#integer_class start := 0 if tok[0] == '+' || tok[0] == '-' { start = 1 @@ -26,20 +27,30 @@ func parseInteger(tok string) (*Object, error) { } else if tok[start+1] == 'x' || tok[start+1] == 'X' { base = 16 } + if tok[start+2] == '+' || tok[start+2] == '-' { + num, err := strconv.ParseInt(tok[start+3:], base, 32) + if err != nil { + return nil, err + } + if tok[start+2] == '-' { + num = -num + } + return &Object{"integer", nil, nil, int(num)}, nil + } num, err := strconv.ParseInt(tok[start+2:], base, 32) if err != nil { return nil, err } - if tok[0] == '-' { - num = -num - } - return &Object{"integer", nil, nil, num}, nil + return &Object{"integer", nil, nil, int(num)}, nil } - num, err := strconv.ParseInt(tok, 10, 32) + num, err := strconv.ParseInt(tok[start:], 10, 32) if err != nil { return nil, err } - return &Object{"integer", nil, nil, num}, nil + if tok[0] == '-' { + num = -num + } + return &Object{"integer", nil, nil, int(num)}, nil } func parseFloat(tok string) (*Object, error) { @@ -88,11 +99,11 @@ func parseMacro(tok string, t TokenReader) (*Object, error) { if i == 1 { d.Val = 1 } else { - v, err := strconv.Atoi(tok[1:i]) + v, err := strconv.ParseInt(tok[1:i], 10, 32) if err != nil { return nil, err } - d.Val = v + d.Val = int(v) } return NewCons(s, NewCons(d, NewCons(cdr, nil))), nil } From 26e9677ff2bd1f67f7484d8835016a3a2fd821c5 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Tue, 25 Jul 2017 14:21:47 +0900 Subject: [PATCH 020/228] added parseFloat test --- parser_test.go | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/parser_test.go b/parser_test.go index b438dba..c961527 100644 --- a/parser_test.go +++ b/parser_test.go @@ -15,6 +15,12 @@ func Test_parseInteger(t *testing.T) { want *Object wantErr bool }{ + { + name: "default", + args: args{"5"}, + want: &Object{"integer", nil, nil, 5}, + wantErr: false, + }, { name: "signed", args: args{"-5"}, @@ -71,3 +77,58 @@ func Test_parseInteger(t *testing.T) { }) } } + +func Test_parseFloat(t *testing.T) { + type args struct { + tok string + } + tests := []struct { + name string + args args + want *Object + wantErr bool + }{ + { + name: "default", + args: args{"5.0"}, + want: &Object{"float", nil, nil, 5.0}, + wantErr: false, + }, + { + name: "signed", + args: args{"-5.0"}, + want: &Object{"float", nil, nil, -5.0}, + wantErr: false, + }, + { + name: "exponential", + args: args{"-5.0E3"}, + want: &Object{"float", nil, nil, -5.0 * 1000}, + wantErr: false, + }, + { + name: "signed exponential", + args: args{"5.0E-3"}, + want: &Object{"float", nil, nil, 5.0 * 1.0 / 1000.0}, + wantErr: false, + }, + { + name: "without point", + args: args{"5E-3"}, + want: &Object{"float", nil, nil, 5.0 * 1.0 / 1000.0}, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := parseFloat(tt.args.tok) + if (err != nil) != tt.wantErr { + t.Errorf("parseFloat() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("parseFloat() = %v, want %v", got, tt.want) + } + }) + } +} From 3336bb4ddb10f4ad3d1c36a81b00ba44147190f2 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Tue, 25 Jul 2017 15:57:15 +0900 Subject: [PATCH 021/228] Added test for character --- parser_test.go | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/parser_test.go b/parser_test.go index c961527..e11b44e 100644 --- a/parser_test.go +++ b/parser_test.go @@ -132,3 +132,52 @@ func Test_parseFloat(t *testing.T) { }) } } + +func Test_parseCharacter(t *testing.T) { + type args struct { + tok string + } + tests := []struct { + name string + args args + want *Object + wantErr bool + }{ + { + name: "default", + args: args{"#\\a"}, + want: &Object{"character", nil, nil, 'a'}, + wantErr: false, + }, + { + name: "newline", + args: args{"#\\newline"}, + want: &Object{"character", nil, nil, '\n'}, + wantErr: false, + }, + { + name: "space", + args: args{"#\\space"}, + want: &Object{"character", nil, nil, ' '}, + wantErr: false, + }, + { + name: "invalid character name", + args: args{"#\\foo"}, + want: nil, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := parseCharacter(tt.args.tok) + if (err != nil) != tt.wantErr { + t.Errorf("parseCharacter() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("parseCharacter() = %v, want %v", got, tt.want) + } + }) + } +} From 26e51247d7f1b34ee8eef011e063c04849e52884 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Tue, 25 Jul 2017 15:57:48 +0900 Subject: [PATCH 022/228] change binary expression --- parser.go | 11 ++++++----- tokenizer.go | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/parser.go b/parser.go index a71c6d6..e9e9323 100644 --- a/parser.go +++ b/parser.go @@ -14,6 +14,7 @@ var errBOD = errors.New("Begin Of Dot") func parseInteger(tok string) (*Object, error) { // TODO: http://minejima.jp/ISLispHyperDraft/islisp-v23.html#integer_class + start := 0 if tok[0] == '+' || tok[0] == '-' { start = 1 @@ -74,16 +75,16 @@ func parseFloat(tok string) (*Object, error) { } func parseCharacter(tok string) (*Object, error) { - if strings.ToLower(tok) == "newline" { + if strings.ToLower(tok[2:]) == "newline" { return &Object{"character", nil, nil, '\n'}, nil } - if strings.ToLower(tok) == "space" { + if strings.ToLower(tok[2:]) == "space" { return &Object{"character", nil, nil, ' '}, nil } if len(tok) != 3 { return nil, errors.New("Invalid character name") } - return &Object{"character", nil, nil, tok[2]}, nil + return &Object{"character", nil, nil, rune(tok[2])}, nil } func parseMacro(tok string, t TokenReader) (*Object, error) { @@ -129,7 +130,7 @@ func parseAtom(tok string, t TokenReader) (*Object, error) { } return m, nil } - if matched, _ := regexp.MatchString("^(?:[+-]?(?:[[:digit:]]+|#[bB][01]+|#[oO][0-7]+|#[xX][[:xdigit:]]+))$", tok); matched { + if matched, _ := regexp.MatchString("^(?:[+-]?[[:digit:]]+|#[bB][+-]?[01]+|#[oO][0-7]+|#[xX][+-]?[[:xdigit:]]+)$", tok); matched { n, err := parseInteger(tok) if err != nil { return nil, err @@ -143,7 +144,7 @@ func parseAtom(tok string, t TokenReader) (*Object, error) { } return f, nil } - if matched, _ := regexp.MatchString("^(?:#\\\\[[:graph:]]|#\\\\(?:[nN][eE][wW][lL][iI][nN][eE]|[sS][pP][aA][cC][eE]))$", tok); matched { + if matched, _ := regexp.MatchString("^(?:#\\\\[[:graph:]]|#\\\\[[:alpha:]]+$", tok); matched { c, err := parseCharacter(tok) if err != nil { return nil, err diff --git a/tokenizer.go b/tokenizer.go index fd528a9..a3d77b9 100644 --- a/tokenizer.go +++ b/tokenizer.go @@ -15,7 +15,7 @@ func concatMatcher(src ...string) *regexp.Regexp { } var macro = strings.Join([]string{"#(?:[[:digit:]]+[aA]?)?", ",@?", "'", "`"}, "|") -var integer = strings.Join([]string{"[[:digit:]]+", "[+-][[:digit:]]*", "#(?:[bB][01]*)?", "#(?:[oO][0-7]*)?", "#(?:[xX][[:xdigit:]]*)?"}, "|") +var integer = strings.Join([]string{"[[:digit:]]+", "[+-][[:digit:]]*", "#(?:[bB][+-]?[01]*)?", "#(?:[oO][+-]?[0-7]*)?", "#(?:[xX][+-]?[[:xdigit:]]*)?"}, "|") var float = strings.Join([]string{"[[:digit:]]+(?:\\.?[[:digit:]]*(?:[eE](?:[-+]?[[:digit:]]*)?)?)?", "[+-](?:[[:digit:]]+(?:\\.?[[:digit:]]*(?:[eE](?:[-+]?[[:digit:]]*)?)?)?)?"}, "|") var character = strings.Join([]string{"#(?:\\\\[[:alpha:]]*)?", "#(?:\\\\[[:graph:]]?)?"}, "|") var str = strings.Join([]string{"\"(?:\\\\\"|[^\"])*\"?"}, "|") From 6fb70eabf8b6516908af90cba4fcef3064bb0b53 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Tue, 25 Jul 2017 17:21:48 +0900 Subject: [PATCH 023/228] Added test for parseAtom --- parser.go | 36 ++++++------ parser_test.go | 154 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 172 insertions(+), 18 deletions(-) diff --git a/parser.go b/parser.go index e9e9323..e416cd0 100644 --- a/parser.go +++ b/parser.go @@ -57,17 +57,17 @@ func parseInteger(tok string) (*Object, error) { func parseFloat(tok string) (*Object, error) { e := strings.IndexRune(strings.ToUpper(tok), 'E') if e > 0 { - num, err := strconv.ParseFloat(tok[:e], 32) + num, err := strconv.ParseFloat(tok[:e], 64) if err != nil { return nil, err } - exp, err := strconv.ParseFloat(tok[e+1:], 32) + exp, err := strconv.ParseFloat(tok[e+1:], 64) if err != nil { return nil, err } return &Object{"float", nil, nil, num * math.Pow(10.0, exp)}, nil } - num, err := strconv.ParseFloat(tok, 32) + num, err := strconv.ParseFloat(tok, 64) if err != nil { return nil, err } @@ -122,42 +122,35 @@ func parseMacro(tok string, t TokenReader) (*Object, error) { return NewCons(m, NewCons(cdr, nil)), nil } -func parseAtom(tok string, t TokenReader) (*Object, error) { - if matched, _ := regexp.MatchString("^(?:,@?|'|`|#[[:digit:]]*[aA])$", tok); matched { - m, err := parseMacro(tok, t) - if err != nil { - return nil, err - } - return m, nil - } - if matched, _ := regexp.MatchString("^(?:[+-]?[[:digit:]]+|#[bB][+-]?[01]+|#[oO][0-7]+|#[xX][+-]?[[:xdigit:]]+)$", tok); matched { +func parseAtom(tok string) (*Object, error) { + if mat, _ := regexp.MatchString("^(?:[+-]?[[:digit:]]+|#[bB][+-]?[01]+|#[oO][+-]?[0-7]+|#[xX][+-]?[[:xdigit:]]+)$", tok); mat { n, err := parseInteger(tok) if err != nil { return nil, err } return n, nil } - if matched, _ := regexp.MatchString("^(?:[+-][[:digit:]]+(?:\\.[[:digit:]])?(?:[eE][-+]?[[:digit:]]+))?$", tok); matched { + if mat, _ := regexp.MatchString("^(?:[+-]?[[:digit:]]+(?:\\.[[:digit:]]+)?(?:[eE][-+]?[[:digit:]]+)?)?$", tok); mat { f, err := parseFloat(tok) if err != nil { return nil, err } return f, nil } - if matched, _ := regexp.MatchString("^(?:#\\\\[[:graph:]]|#\\\\[[:alpha:]]+$", tok); matched { + if mat, _ := regexp.MatchString("^(?:#\\\\[[:graph:]]|#\\\\[[:alpha:]]+)$", tok); mat { c, err := parseCharacter(tok) if err != nil { return nil, err } return c, nil } - if matched, _ := regexp.MatchString("^\".*\"$", tok); matched { + if mat, _ := regexp.MatchString("^\".*\"$", tok); mat { return &Object{"string", nil, nil, tok}, nil } - if matched, _ := regexp.MatchString("^\\|.*\\|$", tok); matched { + if mat, _ := regexp.MatchString("^\\|.*\\|$", tok); mat { return &Object{"symbol", nil, nil, tok}, nil } - if matched, _ := regexp.MatchString("[<>/*=?_!$%[\\]^{}~a-zA-Z][<>/*=?_!$%[\\]^{}~0-9a-zA-Z]*", tok); matched { + if mat, _ := regexp.MatchString("[<>/*=?_!$%[\\\\]^{}~a-zA-Z][<>/*=?_!$%[\\]^{}~0-9a-zA-Z]*", tok); mat { return &Object{"symbol", nil, nil, strings.ToUpper(tok)}, nil } return nil, fmt.Errorf("Sorry, I could not parse %s", tok) @@ -207,7 +200,14 @@ func Parse(t TokenReader) (*Object, error) { if tok == "." { return nil, errBOD } - atom, err := parseAtom(tok, t) + if mat, _ := regexp.MatchString("^(?:,@?|'|`|#[[:digit:]]*[aA])$", tok); mat { + m, err := parseMacro(tok, t) + if err != nil { + return nil, err + } + return m, nil + } + atom, err := parseAtom(tok) if err != nil { return nil, err } diff --git a/parser_test.go b/parser_test.go index e11b44e..0336e16 100644 --- a/parser_test.go +++ b/parser_test.go @@ -181,3 +181,157 @@ func Test_parseCharacter(t *testing.T) { }) } } + +func Test_parseAtom(t *testing.T) { + type args struct { + tok string + } + tests := []struct { + name string + args args + want *Object + wantErr bool + }{ + // + // Float + // + { + name: "default", + args: args{"5.0"}, + want: &Object{"float", nil, nil, 5.0}, + wantErr: false, + }, + { + name: "signed", + args: args{"-5.0"}, + want: &Object{"float", nil, nil, -5.0}, + wantErr: false, + }, + { + name: "exponential", + args: args{"-5.0E3"}, + want: &Object{"float", nil, nil, -5.0 * 1000}, + wantErr: false, + }, + { + name: "signed exponential", + args: args{"5.0E-3"}, + want: &Object{"float", nil, nil, 5.0 * 1.0 / 1000.0}, + wantErr: false, + }, + { + name: "without point", + args: args{"5E-3"}, + want: &Object{"float", nil, nil, 5.0 * 1.0 / 1000.0}, + wantErr: false, + }, + { + name: "invalid case", + args: args{"3E-3.0"}, + want: nil, + wantErr: true, + }, + { + name: "without point", + args: args{"5E-"}, + want: nil, + wantErr: true, + }, + // + // Integer + // + { + name: "default", + args: args{"5"}, + want: &Object{"integer", nil, nil, 5}, + wantErr: false, + }, + { + name: "signed", + args: args{"-5"}, + want: &Object{"integer", nil, nil, -5}, + wantErr: false, + }, + { + name: "binary", + args: args{"#B00101"}, + want: &Object{"integer", nil, nil, 5}, + wantErr: false, + }, + { + name: "signed binary", + args: args{"#b-00101"}, + want: &Object{"integer", nil, nil, -5}, + wantErr: false, + }, + { + name: "octal", + args: args{"#o00101"}, + want: &Object{"integer", nil, nil, 65}, + wantErr: false, + }, + { + name: "signed octal", + args: args{"#O-00101"}, + want: &Object{"integer", nil, nil, -65}, + wantErr: false, + }, + { + name: "hexadecimal", + args: args{"#X00101"}, + want: &Object{"integer", nil, nil, 257}, + wantErr: false, + }, + { + name: "signed hexadecimal", + args: args{"#x-00101"}, + want: &Object{"integer", nil, nil, -257}, + wantErr: false, + }, + { + name: "invalid binary", + args: args{"-#x00101"}, + want: nil, + wantErr: true, + }, + // + // Character + // + { + name: "default", + args: args{"#\\a"}, + want: &Object{"character", nil, nil, 'a'}, + wantErr: false, + }, + { + name: "newline", + args: args{"#\\newline"}, + want: &Object{"character", nil, nil, '\n'}, + wantErr: false, + }, + { + name: "space", + args: args{"#\\space"}, + want: &Object{"character", nil, nil, ' '}, + wantErr: false, + }, + { + name: "invalid character name", + args: args{"#\\foo"}, + want: nil, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := parseAtom(tt.args.tok) + if (err != nil) != tt.wantErr { + t.Errorf("parseAtom() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("parseAtom() = %v, want %v", got, tt.want) + } + }) + } +} From caf222b424e6977cffe29acb5c5dac36436ffe56 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Tue, 25 Jul 2017 17:24:42 +0900 Subject: [PATCH 024/228] Eval local variable --- eval.go | 31 +++++++++++++++++++++++++++++++ eval_test.go | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+) create mode 100644 eval.go create mode 100644 eval_test.go diff --git a/eval.go b/eval.go new file mode 100644 index 0000000..4c481c5 --- /dev/null +++ b/eval.go @@ -0,0 +1,31 @@ +package main + +import ( + "errors" + "fmt" +) + +type Env struct { + Fun map[string]func(*Object) (*Object, error) + Var map[string]*Object +} + +func NewEnv() *Env { + env := new(Env) + env.Fun = map[string]func(*Object) (*Object, error){} + env.Var = map[string]*Object{} + return env +} + +func Eval(obj *Object, local *Env, global *Env) (*Object, error) { + if obj.Type == "symbol" { + if val, ok := local.Var[obj.Val.(string)]; ok { + return val, nil + } + if val, ok := global.Var[obj.Val.(string)]; ok { + return val, nil + } + return nil, fmt.Errorf("%s is not defined", obj.Val) + } + return nil, errors.New("I have no ideas") +} diff --git a/eval_test.go b/eval_test.go new file mode 100644 index 0000000..df25fca --- /dev/null +++ b/eval_test.go @@ -0,0 +1,39 @@ +package main + +import ( + "reflect" + "testing" +) + +func TestEval(t *testing.T) { + type args struct { + obj *Object + local *Env + global *Env + } + tests := []struct { + name string + args args + want *Object + wantErr bool + }{ + { + name: "local variable", + args: args{&Object{"symbol", nil, nil, "PI"}, &Env{nil, map[string]*Object{"PI": &Object{"float", nil, nil, 3.14}}}, nil}, + want: &Object{"float", nil, nil, 3.14}, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := Eval(tt.args.obj, tt.args.local, tt.args.global) + if (err != nil) != tt.wantErr { + t.Errorf("Eval() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("Eval() = %v, want %v", got, tt.want) + } + }) + } +} From dfea76ce9ce8ecf039c22b67ea82720684a4d209 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Tue, 25 Jul 2017 17:42:25 +0900 Subject: [PATCH 025/228] Changed function arguments --- eval.go | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/eval.go b/eval.go index 4c481c5..aa69c23 100644 --- a/eval.go +++ b/eval.go @@ -6,19 +6,23 @@ import ( ) type Env struct { - Fun map[string]func(*Object) (*Object, error) + Fun map[string]func(*Object, *Env, *Env) (*Object, error) Var map[string]*Object } func NewEnv() *Env { env := new(Env) - env.Fun = map[string]func(*Object) (*Object, error){} + env.Fun = map[string]func(*Object, *Env, *Env) (*Object, error){} env.Var = map[string]*Object{} return env } func Eval(obj *Object, local *Env, global *Env) (*Object, error) { - if obj.Type == "symbol" { + if obj == nil { + return nil, nil + } + switch obj.Type { + case "symbol": if val, ok := local.Var[obj.Val.(string)]; ok { return val, nil } @@ -26,6 +30,10 @@ func Eval(obj *Object, local *Env, global *Env) (*Object, error) { return val, nil } return nil, fmt.Errorf("%s is not defined", obj.Val) + case "list": + // funcall + case "integer", "float", "character", "string": + return obj, nil } return nil, errors.New("I have no ideas") } From 0113e82de3e20cd3cc1c23a179349b58d7209a06 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Wed, 26 Jul 2017 10:18:36 +0900 Subject: [PATCH 026/228] rewrited parser --- parser.go | 157 +++++++++++++++--------------------------- parser_test.go | 181 +------------------------------------------------ 2 files changed, 56 insertions(+), 282 deletions(-) diff --git a/parser.go b/parser.go index e416cd0..d1ca56f 100644 --- a/parser.go +++ b/parser.go @@ -12,81 +12,67 @@ import ( var errEOP = errors.New("End Of Parentheses") var errBOD = errors.New("Begin Of Dot") -func parseInteger(tok string) (*Object, error) { - // TODO: http://minejima.jp/ISLispHyperDraft/islisp-v23.html#integer_class - - start := 0 - if tok[0] == '+' || tok[0] == '-' { - start = 1 - } - if tok[start] == '#' { - base := 10 - if tok[start+1] == 'b' || tok[start+1] == 'B' { - base = 2 - } else if tok[start+1] == 'o' || tok[start+1] == 'O' { - base = 8 - } else if tok[start+1] == 'x' || tok[start+1] == 'X' { - base = 16 - } - if tok[start+2] == '+' || tok[start+2] == '-' { - num, err := strconv.ParseInt(tok[start+3:], base, 32) - if err != nil { - return nil, err - } - if tok[start+2] == '-' { - num = -num - } - return &Object{"integer", nil, nil, int(num)}, nil - } - num, err := strconv.ParseInt(tok[start+2:], base, 32) - if err != nil { - return nil, err - } - return &Object{"integer", nil, nil, int(num)}, nil - } - num, err := strconv.ParseInt(tok[start:], 10, 32) - if err != nil { - return nil, err - } - if tok[0] == '-' { - num = -num +func parseAtom(tok string) (*Object, error) { + // + // integer + // + if m, _ := regexp.MatchString("^[-+]?[[:digit:]]+$", tok); m { + n, _ := strconv.ParseInt(tok, 10, 64) + return &Object{"integer", nil, nil, int(n)}, nil + } + if r := regexp.MustCompile("^#[bB]([-+]?[01]+)$").FindStringSubmatch(tok); len(r) >= 2 { + n, _ := strconv.ParseInt(r[1], 2, 64) + return &Object{"integer", nil, nil, int(n)}, nil + } + if r := regexp.MustCompile("^#[oO]([-+]?[0-7]+)$").FindStringSubmatch(tok); len(r) >= 2 { + n, _ := strconv.ParseInt(r[1], 8, 64) + return &Object{"integer", nil, nil, int(n)}, nil + } + if r := regexp.MustCompile("^#[xX]([-+]?[[:xdigit:]]+)$").FindStringSubmatch(tok); len(r) >= 2 { + n, _ := strconv.ParseInt(r[1], 16, 64) + return &Object{"integer", nil, nil, int(n)}, nil + } + // + // float + // + if m, _ := regexp.MatchString("^[-+]?[[:digit:]]+\\.[[:digit:]]$", tok); m { + n, _ := strconv.ParseFloat(tok, 64) + return &Object{"float", nil, nil, n}, nil + } + if r := regexp.MustCompile("^([-+]?[[:digit:]]+(?:\\.[[:digit:]]+)?)[eE]([-+]?[[:digit:]]+)$").FindStringSubmatch(tok); len(r) >= 3 { + n, _ := strconv.ParseFloat(r[1], 64) + e, _ := strconv.ParseInt(r[2], 10, 64) + return &Object{"float", nil, nil, n * math.Pow10(int(e))}, nil + } + // + // character + // + if m, _ := regexp.MatchString("^#\\\\newline$", tok); m { + return &Object{"character", nil, nil, '\n'}, nil } - return &Object{"integer", nil, nil, int(num)}, nil -} - -func parseFloat(tok string) (*Object, error) { - e := strings.IndexRune(strings.ToUpper(tok), 'E') - if e > 0 { - num, err := strconv.ParseFloat(tok[:e], 64) - if err != nil { - return nil, err - } - exp, err := strconv.ParseFloat(tok[e+1:], 64) - if err != nil { - return nil, err - } - return &Object{"float", nil, nil, num * math.Pow(10.0, exp)}, nil + if m, _ := regexp.MatchString("^#\\\\space$", tok); m { + return &Object{"character", nil, nil, ' '}, nil } - num, err := strconv.ParseFloat(tok, 64) - if err != nil { - return nil, err + if r := regexp.MustCompile("^#\\\\([[:graph:]])$").FindStringSubmatch(tok); len(r) >= 2 { + return &Object{"character", nil, nil, rune(r[1][0])}, nil } - return &Object{"float", nil, nil, num}, nil -} - -func parseCharacter(tok string) (*Object, error) { - if strings.ToLower(tok[2:]) == "newline" { - return &Object{"character", nil, nil, '\n'}, nil + // + // string + // + if m, _ := regexp.MatchString("^\".*\"$", tok); m { + return &Object{"string", nil, nil, tok}, nil } - if strings.ToLower(tok[2:]) == "space" { - return &Object{"character", nil, nil, ' '}, nil + // + // symbol + // + if m, _ := regexp.MatchString("^\\|.*\\|$", tok); m { + return &Object{"symbol", nil, nil, tok}, nil } - if len(tok) != 3 { - return nil, errors.New("Invalid character name") + if m, _ := regexp.MatchString("[<>/*=?_!$%[\\\\]^{}~a-zA-Z][<>/*=?_!$%[\\]^{}~0-9a-zA-Z]*", tok); m { + return &Object{"symbol", nil, nil, strings.ToUpper(tok)}, nil } - return &Object{"character", nil, nil, rune(tok[2])}, nil + return nil, fmt.Errorf("Sorry, I could not parse %s", tok) } - func parseMacro(tok string, t TokenReader) (*Object, error) { cdr, err := Parse(t) if err != nil { @@ -121,41 +107,6 @@ func parseMacro(tok string, t TokenReader) (*Object, error) { m := &Object{"symbol", nil, nil, n} return NewCons(m, NewCons(cdr, nil)), nil } - -func parseAtom(tok string) (*Object, error) { - if mat, _ := regexp.MatchString("^(?:[+-]?[[:digit:]]+|#[bB][+-]?[01]+|#[oO][+-]?[0-7]+|#[xX][+-]?[[:xdigit:]]+)$", tok); mat { - n, err := parseInteger(tok) - if err != nil { - return nil, err - } - return n, nil - } - if mat, _ := regexp.MatchString("^(?:[+-]?[[:digit:]]+(?:\\.[[:digit:]]+)?(?:[eE][-+]?[[:digit:]]+)?)?$", tok); mat { - f, err := parseFloat(tok) - if err != nil { - return nil, err - } - return f, nil - } - if mat, _ := regexp.MatchString("^(?:#\\\\[[:graph:]]|#\\\\[[:alpha:]]+)$", tok); mat { - c, err := parseCharacter(tok) - if err != nil { - return nil, err - } - return c, nil - } - if mat, _ := regexp.MatchString("^\".*\"$", tok); mat { - return &Object{"string", nil, nil, tok}, nil - } - if mat, _ := regexp.MatchString("^\\|.*\\|$", tok); mat { - return &Object{"symbol", nil, nil, tok}, nil - } - if mat, _ := regexp.MatchString("[<>/*=?_!$%[\\\\]^{}~a-zA-Z][<>/*=?_!$%[\\]^{}~0-9a-zA-Z]*", tok); mat { - return &Object{"symbol", nil, nil, strings.ToUpper(tok)}, nil - } - return nil, fmt.Errorf("Sorry, I could not parse %s", tok) -} - func parseCons(t TokenReader) (*Object, error) { car, err := Parse(t) if err == errEOP { diff --git a/parser_test.go b/parser_test.go index 0336e16..5e7171b 100644 --- a/parser_test.go +++ b/parser_test.go @@ -5,183 +5,6 @@ import ( "testing" ) -func Test_parseInteger(t *testing.T) { - type args struct { - tok string - } - tests := []struct { - name string - args args - want *Object - wantErr bool - }{ - { - name: "default", - args: args{"5"}, - want: &Object{"integer", nil, nil, 5}, - wantErr: false, - }, - { - name: "signed", - args: args{"-5"}, - want: &Object{"integer", nil, nil, -5}, - wantErr: false, - }, - { - name: "binary", - args: args{"#B00101"}, - want: &Object{"integer", nil, nil, 5}, - wantErr: false, - }, - { - name: "signed binary", - args: args{"#b-00101"}, - want: &Object{"integer", nil, nil, -5}, - wantErr: false, - }, - { - name: "octal", - args: args{"#o00101"}, - want: &Object{"integer", nil, nil, 65}, - wantErr: false, - }, - { - name: "signed octal", - args: args{"#O-00101"}, - want: &Object{"integer", nil, nil, -65}, - wantErr: false, - }, - { - name: "hexadecimal", - args: args{"#X00101"}, - want: &Object{"integer", nil, nil, 257}, - wantErr: false, - }, - { - name: "signed hexadecimal", - args: args{"#x-00101"}, - want: &Object{"integer", nil, nil, -257}, - wantErr: false, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, err := parseInteger(tt.args.tok) - if (err != nil) != tt.wantErr { - t.Errorf("parseInteger() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !reflect.DeepEqual(got, tt.want) { - t.Errorf("parseInteger() = %v, want %v", got, tt.want) - } - }) - } -} - -func Test_parseFloat(t *testing.T) { - type args struct { - tok string - } - tests := []struct { - name string - args args - want *Object - wantErr bool - }{ - { - name: "default", - args: args{"5.0"}, - want: &Object{"float", nil, nil, 5.0}, - wantErr: false, - }, - { - name: "signed", - args: args{"-5.0"}, - want: &Object{"float", nil, nil, -5.0}, - wantErr: false, - }, - { - name: "exponential", - args: args{"-5.0E3"}, - want: &Object{"float", nil, nil, -5.0 * 1000}, - wantErr: false, - }, - { - name: "signed exponential", - args: args{"5.0E-3"}, - want: &Object{"float", nil, nil, 5.0 * 1.0 / 1000.0}, - wantErr: false, - }, - { - name: "without point", - args: args{"5E-3"}, - want: &Object{"float", nil, nil, 5.0 * 1.0 / 1000.0}, - wantErr: false, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, err := parseFloat(tt.args.tok) - if (err != nil) != tt.wantErr { - t.Errorf("parseFloat() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !reflect.DeepEqual(got, tt.want) { - t.Errorf("parseFloat() = %v, want %v", got, tt.want) - } - }) - } -} - -func Test_parseCharacter(t *testing.T) { - type args struct { - tok string - } - tests := []struct { - name string - args args - want *Object - wantErr bool - }{ - { - name: "default", - args: args{"#\\a"}, - want: &Object{"character", nil, nil, 'a'}, - wantErr: false, - }, - { - name: "newline", - args: args{"#\\newline"}, - want: &Object{"character", nil, nil, '\n'}, - wantErr: false, - }, - { - name: "space", - args: args{"#\\space"}, - want: &Object{"character", nil, nil, ' '}, - wantErr: false, - }, - { - name: "invalid character name", - args: args{"#\\foo"}, - want: nil, - wantErr: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, err := parseCharacter(tt.args.tok) - if (err != nil) != tt.wantErr { - t.Errorf("parseCharacter() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !reflect.DeepEqual(got, tt.want) { - t.Errorf("parseCharacter() = %v, want %v", got, tt.want) - } - }) - } -} - func Test_parseAtom(t *testing.T) { type args struct { tok string @@ -260,8 +83,8 @@ func Test_parseAtom(t *testing.T) { }, { name: "signed binary", - args: args{"#b-00101"}, - want: &Object{"integer", nil, nil, -5}, + args: args{"#b+00101"}, + want: &Object{"integer", nil, nil, 5}, wantErr: false, }, { From 4c1f2fb34ae57d5c8fc13ed6a21281fdef860e59 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Wed, 26 Jul 2017 23:21:53 +0900 Subject: [PATCH 027/228] Added function call in Eval --- eval.go | 42 ++++++++++++++++++++++++++++++++++++++---- eval_test.go | 18 +++++++++++++++++- function.go | 45 +++++++++++++++++++++++++++++++++++++++++++++ object.go | 17 +++++++++++++++++ parser.go | 6 +++--- parser_test.go | 2 +- 6 files changed, 121 insertions(+), 9 deletions(-) create mode 100644 function.go diff --git a/eval.go b/eval.go index aa69c23..bd2e3be 100644 --- a/eval.go +++ b/eval.go @@ -5,18 +5,22 @@ import ( "fmt" ) +// Env struct is the struct for keeping functions and variables type Env struct { - Fun map[string]func(*Object, *Env, *Env) (*Object, error) + Mac map[string]Function + Fun map[string]Function Var map[string]*Object } +// NewEnv creates new environment func NewEnv() *Env { env := new(Env) - env.Fun = map[string]func(*Object, *Env, *Env) (*Object, error){} + env.Fun = map[string]Function{} env.Var = map[string]*Object{} return env } +// Eval evaluates any objects func Eval(obj *Object, local *Env, global *Env) (*Object, error) { if obj == nil { return nil, nil @@ -29,9 +33,39 @@ func Eval(obj *Object, local *Env, global *Env) (*Object, error) { if val, ok := global.Var[obj.Val.(string)]; ok { return val, nil } - return nil, fmt.Errorf("%s is not defined", obj.Val) + return nil, fmt.Errorf("%v is not defined", obj.Val) case "list": - // funcall + if obj.Car.Type != "symbol" { + return nil, fmt.Errorf("%v is not a function", obj.Car.Val) + } + args, err := CopyList(obj.Cdr) + if err != nil { + return nil, err + } + cdr := args + for cdr != nil { + car, err := Eval(cdr.Car, local, global) + if err != nil { + return nil, err + } + args.Car = car + cdr = cdr.Cdr + } + if fun, ok := local.Fun[obj.Car.Val.(string)]; ok { + ret, err := fun.Apply(args, global) + if err != nil { + return nil, err + } + return ret, nil + } + if fun, ok := global.Fun[obj.Car.Val.(string)]; ok { + ret, err := fun.Apply(args, global) + if err != nil { + return nil, err + } + return ret, nil + } + return nil, fmt.Errorf("%v is not defined", obj.Val) case "integer", "float", "character", "string": return obj, nil } diff --git a/eval_test.go b/eval_test.go index df25fca..4cd2ef7 100644 --- a/eval_test.go +++ b/eval_test.go @@ -2,10 +2,20 @@ package main import ( "reflect" + "strings" "testing" ) +func read(s string) *Object { + e, _ := Parse(NewReader(strings.NewReader(s))) + return e +} + func TestEval(t *testing.T) { + testEnv := NewEnv() + testEnv.Fun["INC"] = &NativeFunction{func(args *Object, global *Env) (*Object, error) { + return &Object{"integer", nil, nil, args.Car.Val.(int) + 1}, nil + }} type args struct { obj *Object local *Env @@ -19,10 +29,16 @@ func TestEval(t *testing.T) { }{ { name: "local variable", - args: args{&Object{"symbol", nil, nil, "PI"}, &Env{nil, map[string]*Object{"PI": &Object{"float", nil, nil, 3.14}}}, nil}, + args: args{read("PI"), &Env{nil, nil, map[string]*Object{"PI": read("3.14")}}, nil}, want: &Object{"float", nil, nil, 3.14}, wantErr: false, }, + { + name: "function call", + args: args{read("(inc (inc 1))"), NewEnv(), testEnv}, + want: &Object{"integer", nil, nil, 3}, + wantErr: false, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/function.go b/function.go new file mode 100644 index 0000000..e95e946 --- /dev/null +++ b/function.go @@ -0,0 +1,45 @@ +package main + +// Function interaface type is the interface for calling function with arguments +type Function interface { + Apply(*Object, *Env) (*Object, error) +} + +// NativeFunction struct type is the strcut for calling function written in go +type NativeFunction struct { + raw func(*Object, *Env) (*Object, error) +} + +// Apply call function f with args in global +func (f *NativeFunction) Apply(args *Object, global *Env) (*Object, error) { + a, err := f.raw(args, global) + return a, err +} + +// NormalFunction struct type is the strcut for calling function written by user +type NormalFunction struct { + Args *Object + Body *Object +} + +// Apply call function f with args in global +func (f *NormalFunction) Apply(args *Object, global *Env) (*Object, error) { + local := NewEnv() + v := f.Args + a := args + for v != nil && a != nil { + local.Var[v.Car.Val.(string)] = a.Car + v = v.Cdr + a = a.Cdr + } + b := f.Body + var r *Object + for b != nil { + b, err := Eval(b.Car, local, global) + if err != nil { + return nil, err + } + b = b.Cdr + } + return r, nil +} diff --git a/object.go b/object.go index 7c4da8c..daa8667 100644 --- a/object.go +++ b/object.go @@ -1,5 +1,7 @@ package main +import "errors" + // Object struct type is the struct for the internal representations type Object struct { Type string @@ -20,3 +22,18 @@ func NewCons(car *Object, cdr *Object) *Object { func (o *Object) Is(val interface{}) bool { return o.Val == val } + +// CopyList create a clone list +func CopyList(list *Object) (*Object, error) { + if list == nil { + return nil, nil + } + if list.Type != "list" { + return nil, errors.New("not a list") + } + cdr, err := CopyList(list.Cdr) + if err != nil { + return nil, err + } + return NewCons(list.Car, cdr), nil +} diff --git a/parser.go b/parser.go index d1ca56f..25fbb3c 100644 --- a/parser.go +++ b/parser.go @@ -35,7 +35,7 @@ func parseAtom(tok string) (*Object, error) { // // float // - if m, _ := regexp.MatchString("^[-+]?[[:digit:]]+\\.[[:digit:]]$", tok); m { + if m, _ := regexp.MatchString("^[-+]?[[:digit:]]+\\.[[:digit:]]+$", tok); m { n, _ := strconv.ParseFloat(tok, 64) return &Object{"float", nil, nil, n}, nil } @@ -68,7 +68,7 @@ func parseAtom(tok string) (*Object, error) { if m, _ := regexp.MatchString("^\\|.*\\|$", tok); m { return &Object{"symbol", nil, nil, tok}, nil } - if m, _ := regexp.MatchString("[<>/*=?_!$%[\\\\]^{}~a-zA-Z][<>/*=?_!$%[\\]^{}~0-9a-zA-Z]*", tok); m { + if m, _ := regexp.MatchString("^[<>/*=?_!$%[\\]^{}~a-zA-Z][<>/*=?_!$%[\\]^{}~0-9a-zA-Z]*$", tok); m { return &Object{"symbol", nil, nil, strings.ToUpper(tok)}, nil } return nil, fmt.Errorf("Sorry, I could not parse %s", tok) @@ -118,7 +118,7 @@ func parseCons(t TokenReader) (*Object, error) { return nil, err } if _, err := Parse(t); err != errEOP { - return nil, errors.New("Invalid syntax") + return nil, err } return cdr, nil } diff --git a/parser_test.go b/parser_test.go index 5e7171b..c566da7 100644 --- a/parser_test.go +++ b/parser_test.go @@ -20,7 +20,7 @@ func Test_parseAtom(t *testing.T) { // { name: "default", - args: args{"5.0"}, + args: args{"3.14"}, want: &Object{"float", nil, nil, 5.0}, wantErr: false, }, From 5c0cabb2554fafe402eff2cdafe9fbc78c6a8894 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Thu, 27 Jul 2017 12:23:13 +0900 Subject: [PATCH 028/228] Added nil literal --- parser.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/parser.go b/parser.go index 25fbb3c..a171e25 100644 --- a/parser.go +++ b/parser.go @@ -65,6 +65,12 @@ func parseAtom(tok string) (*Object, error) { // // symbol // + if "nil" == strings.ToLower(tok) { + return nil, nil + } + if r := regexp.MustCompile("^:([<>/*=?_!$%[\\]^{}~0-9a-zA-Z]+)$").FindStringSubmatch(tok); len(r) >= 2 { + return &Object{"keyword", nil, nil, r[1]}, nil + } if m, _ := regexp.MatchString("^\\|.*\\|$", tok); m { return &Object{"symbol", nil, nil, tok}, nil } From d3eeb57cf164fdfd06db0159d47f801e08e04099 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Thu, 27 Jul 2017 12:23:51 +0900 Subject: [PATCH 029/228] Added local environment in arguments --- eval.go | 47 +++++++++++++++++++++++++++++++++++++---------- eval_test.go | 4 ++-- function.go | 10 +++++----- 3 files changed, 44 insertions(+), 17 deletions(-) diff --git a/eval.go b/eval.go index bd2e3be..aed2a4e 100644 --- a/eval.go +++ b/eval.go @@ -7,6 +7,7 @@ import ( // Env struct is the struct for keeping functions and variables type Env struct { + Frm map[string]Function Mac map[string]Function Fun map[string]Function Var map[string]*Object @@ -15,6 +16,8 @@ type Env struct { // NewEnv creates new environment func NewEnv() *Env { env := new(Env) + env.Frm = map[string]Function{} + env.Mac = map[string]Function{} env.Fun = map[string]Function{} env.Var = map[string]*Object{} return env @@ -38,28 +41,52 @@ func Eval(obj *Object, local *Env, global *Env) (*Object, error) { if obj.Car.Type != "symbol" { return nil, fmt.Errorf("%v is not a function", obj.Car.Val) } - args, err := CopyList(obj.Cdr) - if err != nil { - return nil, err - } - cdr := args - for cdr != nil { - car, err := Eval(cdr.Car, local, global) + args := obj.Cdr + /* + if frm, ok := global.Frm[obj.Car.Val.(string)]; ok { + ret, err := frm.Apply(args, local, global) + if err != nil { + return nil, err + } + ret, err = Eval(ret, local, global) + if err != nil { + return nil, err + } + return ret, nil + } + if mac, ok := global.Mac[obj.Car.Val.(string)]; ok { + ret, err := mac.Apply(args, NewEnv(), global) + if err != nil { + return nil, err + } + ret, err = Eval(ret, local, global) + if err != nil { + return nil, err + } + return ret, nil + } + */ + cdr := NewCons(nil, nil) + tmp := cdr + for args != nil { + car, err := Eval(args.Car, local, global) if err != nil { return nil, err } - args.Car = car + cdr.Car = car cdr = cdr.Cdr + args = args.Cdr } + args = tmp if fun, ok := local.Fun[obj.Car.Val.(string)]; ok { - ret, err := fun.Apply(args, global) + ret, err := fun.Apply(args, NewEnv(), global) if err != nil { return nil, err } return ret, nil } if fun, ok := global.Fun[obj.Car.Val.(string)]; ok { - ret, err := fun.Apply(args, global) + ret, err := fun.Apply(args, NewEnv(), global) if err != nil { return nil, err } diff --git a/eval_test.go b/eval_test.go index 4cd2ef7..a17b872 100644 --- a/eval_test.go +++ b/eval_test.go @@ -13,7 +13,7 @@ func read(s string) *Object { func TestEval(t *testing.T) { testEnv := NewEnv() - testEnv.Fun["INC"] = &NativeFunction{func(args *Object, global *Env) (*Object, error) { + testEnv.Fun["INC"] = &NativeFunction{func(args *Object, local *Env, global *Env) (*Object, error) { return &Object{"integer", nil, nil, args.Car.Val.(int) + 1}, nil }} type args struct { @@ -29,7 +29,7 @@ func TestEval(t *testing.T) { }{ { name: "local variable", - args: args{read("PI"), &Env{nil, nil, map[string]*Object{"PI": read("3.14")}}, nil}, + args: args{read("PI"), &Env{nil, nil, nil, map[string]*Object{"PI": read("3.14")}}, nil}, want: &Object{"float", nil, nil, 3.14}, wantErr: false, }, diff --git a/function.go b/function.go index e95e946..3f1ac03 100644 --- a/function.go +++ b/function.go @@ -2,17 +2,17 @@ package main // Function interaface type is the interface for calling function with arguments type Function interface { - Apply(*Object, *Env) (*Object, error) + Apply(*Object, *Env, *Env) (*Object, error) } // NativeFunction struct type is the strcut for calling function written in go type NativeFunction struct { - raw func(*Object, *Env) (*Object, error) + raw func(*Object, *Env, *Env) (*Object, error) } // Apply call function f with args in global -func (f *NativeFunction) Apply(args *Object, global *Env) (*Object, error) { - a, err := f.raw(args, global) +func (f *NativeFunction) Apply(args *Object, local *Env, global *Env) (*Object, error) { + a, err := f.raw(args, local, global) return a, err } @@ -23,7 +23,7 @@ type NormalFunction struct { } // Apply call function f with args in global -func (f *NormalFunction) Apply(args *Object, global *Env) (*Object, error) { +func (f *NormalFunction) Apply(args *Object, _ *Env, global *Env) (*Object, error) { local := NewEnv() v := f.Args a := args From ee619e8566f1c7c5b6881c9acb9815f41c1470e6 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Thu, 27 Jul 2017 12:24:20 +0900 Subject: [PATCH 030/228] Added Copy object method --- object.go | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/object.go b/object.go index daa8667..a5935d0 100644 --- a/object.go +++ b/object.go @@ -1,7 +1,5 @@ package main -import "errors" - // Object struct type is the struct for the internal representations type Object struct { Type string @@ -23,17 +21,10 @@ func (o *Object) Is(val interface{}) bool { return o.Val == val } -// CopyList create a clone list -func CopyList(list *Object) (*Object, error) { - if list == nil { - return nil, nil - } - if list.Type != "list" { - return nil, errors.New("not a list") - } - cdr, err := CopyList(list.Cdr) - if err != nil { - return nil, err +// Copy creates a clone of Object +func (o *Object) Copy() *Object { + if o == nil { + return nil } - return NewCons(list.Car, cdr), nil + return &Object{o.Type, o.Car.Copy(), o.Cdr.Copy(), o.Val} } From 4630f87da024789fa915b75dc1c6f947cbfbfe69 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Thu, 27 Jul 2017 15:37:58 +0900 Subject: [PATCH 031/228] Splited into some packages --- eval.go | 100 ------------------ function.go | 45 -------- main.go | 16 --- object.go | 30 ------ reader.go | 45 -------- reader/expression/expression.go | 18 ++++ parser.go => reader/parser/parser.go | 60 ++++++----- .../parser/parser_test.go | 39 +++---- tokenizer.go => reader/tokenizer/tokenizer.go | 39 ++++++- .../tokenizer/tokenizer_test.go | 2 +- runtime/class/class.go | 36 +++++++ runtime/environment.go | 19 ++++ runtime/eval.go | 29 +++++ eval_test.go => runtime/eval_test.go | 29 +++-- runtime/object/object.go | 24 +++++ 15 files changed, 230 insertions(+), 301 deletions(-) delete mode 100644 eval.go delete mode 100644 function.go delete mode 100644 main.go delete mode 100644 object.go delete mode 100644 reader.go create mode 100644 reader/expression/expression.go rename parser.go => reader/parser/parser.go (64%) rename parser_test.go => reader/parser/parser_test.go (67%) rename tokenizer.go => reader/tokenizer/tokenizer.go (62%) rename tokenizer_test.go => reader/tokenizer/tokenizer_test.go (97%) create mode 100644 runtime/class/class.go create mode 100644 runtime/environment.go create mode 100644 runtime/eval.go rename eval_test.go => runtime/eval_test.go (50%) create mode 100644 runtime/object/object.go diff --git a/eval.go b/eval.go deleted file mode 100644 index aed2a4e..0000000 --- a/eval.go +++ /dev/null @@ -1,100 +0,0 @@ -package main - -import ( - "errors" - "fmt" -) - -// Env struct is the struct for keeping functions and variables -type Env struct { - Frm map[string]Function - Mac map[string]Function - Fun map[string]Function - Var map[string]*Object -} - -// NewEnv creates new environment -func NewEnv() *Env { - env := new(Env) - env.Frm = map[string]Function{} - env.Mac = map[string]Function{} - env.Fun = map[string]Function{} - env.Var = map[string]*Object{} - return env -} - -// Eval evaluates any objects -func Eval(obj *Object, local *Env, global *Env) (*Object, error) { - if obj == nil { - return nil, nil - } - switch obj.Type { - case "symbol": - if val, ok := local.Var[obj.Val.(string)]; ok { - return val, nil - } - if val, ok := global.Var[obj.Val.(string)]; ok { - return val, nil - } - return nil, fmt.Errorf("%v is not defined", obj.Val) - case "list": - if obj.Car.Type != "symbol" { - return nil, fmt.Errorf("%v is not a function", obj.Car.Val) - } - args := obj.Cdr - /* - if frm, ok := global.Frm[obj.Car.Val.(string)]; ok { - ret, err := frm.Apply(args, local, global) - if err != nil { - return nil, err - } - ret, err = Eval(ret, local, global) - if err != nil { - return nil, err - } - return ret, nil - } - if mac, ok := global.Mac[obj.Car.Val.(string)]; ok { - ret, err := mac.Apply(args, NewEnv(), global) - if err != nil { - return nil, err - } - ret, err = Eval(ret, local, global) - if err != nil { - return nil, err - } - return ret, nil - } - */ - cdr := NewCons(nil, nil) - tmp := cdr - for args != nil { - car, err := Eval(args.Car, local, global) - if err != nil { - return nil, err - } - cdr.Car = car - cdr = cdr.Cdr - args = args.Cdr - } - args = tmp - if fun, ok := local.Fun[obj.Car.Val.(string)]; ok { - ret, err := fun.Apply(args, NewEnv(), global) - if err != nil { - return nil, err - } - return ret, nil - } - if fun, ok := global.Fun[obj.Car.Val.(string)]; ok { - ret, err := fun.Apply(args, NewEnv(), global) - if err != nil { - return nil, err - } - return ret, nil - } - return nil, fmt.Errorf("%v is not defined", obj.Val) - case "integer", "float", "character", "string": - return obj, nil - } - return nil, errors.New("I have no ideas") -} diff --git a/function.go b/function.go deleted file mode 100644 index 3f1ac03..0000000 --- a/function.go +++ /dev/null @@ -1,45 +0,0 @@ -package main - -// Function interaface type is the interface for calling function with arguments -type Function interface { - Apply(*Object, *Env, *Env) (*Object, error) -} - -// NativeFunction struct type is the strcut for calling function written in go -type NativeFunction struct { - raw func(*Object, *Env, *Env) (*Object, error) -} - -// Apply call function f with args in global -func (f *NativeFunction) Apply(args *Object, local *Env, global *Env) (*Object, error) { - a, err := f.raw(args, local, global) - return a, err -} - -// NormalFunction struct type is the strcut for calling function written by user -type NormalFunction struct { - Args *Object - Body *Object -} - -// Apply call function f with args in global -func (f *NormalFunction) Apply(args *Object, _ *Env, global *Env) (*Object, error) { - local := NewEnv() - v := f.Args - a := args - for v != nil && a != nil { - local.Var[v.Car.Val.(string)] = a.Car - v = v.Cdr - a = a.Cdr - } - b := f.Body - var r *Object - for b != nil { - b, err := Eval(b.Car, local, global) - if err != nil { - return nil, err - } - b = b.Cdr - } - return r, nil -} diff --git a/main.go b/main.go deleted file mode 100644 index dd257ca..0000000 --- a/main.go +++ /dev/null @@ -1,16 +0,0 @@ -package main - -import ( - "io" - "strings" - - "github.com/k0kubun/pp" -) - -func main() { - src := "'#3a(1 2 3)" - r := NewReader(strings.NewReader(src)) - for exp, err := r.ReadExp(); err != io.EOF; exp, err = r.ReadExp() { - pp.Print(exp) - } -} diff --git a/object.go b/object.go deleted file mode 100644 index a5935d0..0000000 --- a/object.go +++ /dev/null @@ -1,30 +0,0 @@ -package main - -// Object struct type is the struct for the internal representations -type Object struct { - Type string - Car *Object - Cdr *Object - Val interface{} -} - -// NewCons creates cons pair from two objects -func NewCons(car *Object, cdr *Object) *Object { - if cdr == nil || cdr.Type == "list" { - return &Object{"list", car, cdr, nil} - } - return &Object{"cons", car, cdr, nil} -} - -// Is is for testing -func (o *Object) Is(val interface{}) bool { - return o.Val == val -} - -// Copy creates a clone of Object -func (o *Object) Copy() *Object { - if o == nil { - return nil - } - return &Object{o.Type, o.Car.Copy(), o.Cdr.Copy(), o.Val} -} diff --git a/reader.go b/reader.go deleted file mode 100644 index 0f96a09..0000000 --- a/reader.go +++ /dev/null @@ -1,45 +0,0 @@ -package main - -import "io" - -// Reader is like bufio.Reader but has PeekRune -// which returns a rune without advancing pointer -type Reader struct { - err error - ru rune - sz int - rr io.RuneReader -} - -// NewReader creates interal reader from io.RuneReader -func NewReader(r io.RuneReader) *Reader { - b := new(Reader) - b.rr = r - b.ru, b.sz, b.err = b.rr.ReadRune() - return b -} - -// PeekRune returns a rune without advancing pointer -func (r *Reader) PeekRune() (rune, int, error) { - return r.ru, r.sz, r.err -} - -// ReadRune returns a rune with advancing pointer -func (r *Reader) ReadRune() (rune, int, error) { - ru := r.ru - sz := r.sz - err := r.err - r.ru, r.sz, r.err = r.rr.ReadRune() - return ru, sz, err -} - -// ExpReader interface type is the interface for reading expressions. -type ExpReader interface { - ReadExp() (*Object, error) -} - -// ReadExp returns a expression that is a pointer to Object -func (r *Reader) ReadExp() (*Object, error) { - exp, err := Parse(r) - return exp, err -} diff --git a/reader/expression/expression.go b/reader/expression/expression.go new file mode 100644 index 0000000..6c55788 --- /dev/null +++ b/reader/expression/expression.go @@ -0,0 +1,18 @@ +package expression + +import ( + "github.com/ta2gch/gazelle/reader/parser" + "github.com/ta2gch/gazelle/reader/tokenizer" + "github.com/ta2gch/gazelle/runtime" +) + +// ExpReader interface type is the interface for reading expressions. +type ExpReader struct { + tokenizer.TokenReader +} + +// ReadExp returns a expression that is a pointer to Object +func (r *ExpReader) ReadExp() (*runtime.Object, error) { + exp, err := parser.Parse(r) + return exp, err +} diff --git a/parser.go b/reader/parser/parser.go similarity index 64% rename from parser.go rename to reader/parser/parser.go index a171e25..63348f7 100644 --- a/parser.go +++ b/reader/parser/parser.go @@ -1,4 +1,4 @@ -package main +package parser import ( "errors" @@ -7,60 +7,72 @@ import ( "regexp" "strconv" "strings" + + "github.com/ta2gch/gazelle/reader/tokenizer" + "github.com/ta2gch/gazelle/runtime/class" + "github.com/ta2gch/gazelle/runtime/object" ) var errEOP = errors.New("End Of Parentheses") var errBOD = errors.New("Begin Of Dot") -func parseAtom(tok string) (*Object, error) { +// cons creates cons pair from two objects +func cons(car *object.Object, cdr *object.Object) *object.Object { + if cdr == nil || cdr.Class == class.List { + return &object.Object{class.List, car, cdr, nil} + } + return &object.Object{class.Cons, car, cdr, nil} +} + +func parseAtom(tok string) (*object.Object, error) { // // integer // if m, _ := regexp.MatchString("^[-+]?[[:digit:]]+$", tok); m { n, _ := strconv.ParseInt(tok, 10, 64) - return &Object{"integer", nil, nil, int(n)}, nil + return &object.Object{class.Integer, nil, nil, int(n)}, nil } if r := regexp.MustCompile("^#[bB]([-+]?[01]+)$").FindStringSubmatch(tok); len(r) >= 2 { n, _ := strconv.ParseInt(r[1], 2, 64) - return &Object{"integer", nil, nil, int(n)}, nil + return &object.Object{class.Integer, nil, nil, int(n)}, nil } if r := regexp.MustCompile("^#[oO]([-+]?[0-7]+)$").FindStringSubmatch(tok); len(r) >= 2 { n, _ := strconv.ParseInt(r[1], 8, 64) - return &Object{"integer", nil, nil, int(n)}, nil + return &object.Object{class.Integer, nil, nil, int(n)}, nil } if r := regexp.MustCompile("^#[xX]([-+]?[[:xdigit:]]+)$").FindStringSubmatch(tok); len(r) >= 2 { n, _ := strconv.ParseInt(r[1], 16, 64) - return &Object{"integer", nil, nil, int(n)}, nil + return &object.Object{class.Integer, nil, nil, int(n)}, nil } // // float // if m, _ := regexp.MatchString("^[-+]?[[:digit:]]+\\.[[:digit:]]+$", tok); m { n, _ := strconv.ParseFloat(tok, 64) - return &Object{"float", nil, nil, n}, nil + return &object.Object{class.Float, nil, nil, n}, nil } if r := regexp.MustCompile("^([-+]?[[:digit:]]+(?:\\.[[:digit:]]+)?)[eE]([-+]?[[:digit:]]+)$").FindStringSubmatch(tok); len(r) >= 3 { n, _ := strconv.ParseFloat(r[1], 64) e, _ := strconv.ParseInt(r[2], 10, 64) - return &Object{"float", nil, nil, n * math.Pow10(int(e))}, nil + return &object.Object{class.Float, nil, nil, n * math.Pow10(int(e))}, nil } // // character // if m, _ := regexp.MatchString("^#\\\\newline$", tok); m { - return &Object{"character", nil, nil, '\n'}, nil + return &object.Object{class.Character, nil, nil, '\n'}, nil } if m, _ := regexp.MatchString("^#\\\\space$", tok); m { - return &Object{"character", nil, nil, ' '}, nil + return &object.Object{class.Character, nil, nil, ' '}, nil } if r := regexp.MustCompile("^#\\\\([[:graph:]])$").FindStringSubmatch(tok); len(r) >= 2 { - return &Object{"character", nil, nil, rune(r[1][0])}, nil + return &object.Object{class.Character, nil, nil, rune(r[1][0])}, nil } // // string // if m, _ := regexp.MatchString("^\".*\"$", tok); m { - return &Object{"string", nil, nil, tok}, nil + return &object.Object{class.String, nil, nil, tok}, nil } // // symbol @@ -69,25 +81,25 @@ func parseAtom(tok string) (*Object, error) { return nil, nil } if r := regexp.MustCompile("^:([<>/*=?_!$%[\\]^{}~0-9a-zA-Z]+)$").FindStringSubmatch(tok); len(r) >= 2 { - return &Object{"keyword", nil, nil, r[1]}, nil + return &object.Object{class.Symbol, nil, nil, r[1]}, nil } if m, _ := regexp.MatchString("^\\|.*\\|$", tok); m { - return &Object{"symbol", nil, nil, tok}, nil + return &object.Object{class.Symbol, nil, nil, tok}, nil } if m, _ := regexp.MatchString("^[<>/*=?_!$%[\\]^{}~a-zA-Z][<>/*=?_!$%[\\]^{}~0-9a-zA-Z]*$", tok); m { - return &Object{"symbol", nil, nil, strings.ToUpper(tok)}, nil + return &object.Object{class.Symbol, nil, nil, strings.ToUpper(tok)}, nil } return nil, fmt.Errorf("Sorry, I could not parse %s", tok) } -func parseMacro(tok string, t TokenReader) (*Object, error) { +func parseMacro(tok string, t *tokenizer.TokenReader) (*object.Object, error) { cdr, err := Parse(t) if err != nil { return nil, err } n := tok if m, _ := regexp.MatchString("#[[:digit:]]*[aA]", tok); m { - s := &Object{"symbol", nil, nil, "array"} - d := &Object{"integer", nil, nil, 0} + s := &object.Object{class.Symbol, nil, nil, "array"} + d := &object.Object{class.Integer, nil, nil, 0} i := strings.IndexRune(strings.ToLower(tok), 'a') if i == 1 { d.Val = 1 @@ -98,7 +110,7 @@ func parseMacro(tok string, t TokenReader) (*Object, error) { } d.Val = int(v) } - return NewCons(s, NewCons(d, NewCons(cdr, nil))), nil + return cons(s, cons(d, cons(cdr, nil))), nil } switch tok { case ",@": @@ -110,10 +122,10 @@ func parseMacro(tok string, t TokenReader) (*Object, error) { case "`": n = "backquote" } - m := &Object{"symbol", nil, nil, n} - return NewCons(m, NewCons(cdr, nil)), nil + m := &object.Object{class.Symbol, nil, nil, n} + return cons(m, cons(cdr, nil)), nil } -func parseCons(t TokenReader) (*Object, error) { +func parseCons(t *tokenizer.TokenReader) (*object.Object, error) { car, err := Parse(t) if err == errEOP { return nil, nil @@ -135,11 +147,11 @@ func parseCons(t TokenReader) (*Object, error) { if err != nil { return nil, err } - return NewCons(car, cdr), nil + return cons(car, cdr), nil } // Parse builds a internal expression from tokens -func Parse(t TokenReader) (*Object, error) { +func Parse(t *tokenizer.TokenReader) (*object.Object, error) { tok, err := t.ReadToken() if err != nil { return nil, err diff --git a/parser_test.go b/reader/parser/parser_test.go similarity index 67% rename from parser_test.go rename to reader/parser/parser_test.go index c566da7..0ed6f31 100644 --- a/parser_test.go +++ b/reader/parser/parser_test.go @@ -1,8 +1,11 @@ -package main +package parser import ( "reflect" "testing" + + "github.com/ta2gch/gazelle/runtime/class" + "github.com/ta2gch/gazelle/runtime/object" ) func Test_parseAtom(t *testing.T) { @@ -12,7 +15,7 @@ func Test_parseAtom(t *testing.T) { tests := []struct { name string args args - want *Object + want *object.Object wantErr bool }{ // @@ -21,31 +24,31 @@ func Test_parseAtom(t *testing.T) { { name: "default", args: args{"3.14"}, - want: &Object{"float", nil, nil, 5.0}, + want: &object.Object{class.Float, nil, nil, 3.14}, wantErr: false, }, { name: "signed", args: args{"-5.0"}, - want: &Object{"float", nil, nil, -5.0}, + want: &object.Object{class.Float, nil, nil, -5.0}, wantErr: false, }, { name: "exponential", args: args{"-5.0E3"}, - want: &Object{"float", nil, nil, -5.0 * 1000}, + want: &object.Object{class.Float, nil, nil, -5.0 * 1000}, wantErr: false, }, { name: "signed exponential", args: args{"5.0E-3"}, - want: &Object{"float", nil, nil, 5.0 * 1.0 / 1000.0}, + want: &object.Object{class.Float, nil, nil, 5.0 * 1.0 / 1000.0}, wantErr: false, }, { name: "without point", args: args{"5E-3"}, - want: &Object{"float", nil, nil, 5.0 * 1.0 / 1000.0}, + want: &object.Object{class.Float, nil, nil, 5.0 * 1.0 / 1000.0}, wantErr: false, }, { @@ -66,49 +69,49 @@ func Test_parseAtom(t *testing.T) { { name: "default", args: args{"5"}, - want: &Object{"integer", nil, nil, 5}, + want: &object.Object{class.Integer, nil, nil, 5}, wantErr: false, }, { name: "signed", args: args{"-5"}, - want: &Object{"integer", nil, nil, -5}, + want: &object.Object{class.Integer, nil, nil, -5}, wantErr: false, }, { name: "binary", args: args{"#B00101"}, - want: &Object{"integer", nil, nil, 5}, + want: &object.Object{class.Integer, nil, nil, 5}, wantErr: false, }, { name: "signed binary", args: args{"#b+00101"}, - want: &Object{"integer", nil, nil, 5}, + want: &object.Object{class.Integer, nil, nil, 5}, wantErr: false, }, { name: "octal", args: args{"#o00101"}, - want: &Object{"integer", nil, nil, 65}, + want: &object.Object{class.Integer, nil, nil, 65}, wantErr: false, }, { name: "signed octal", args: args{"#O-00101"}, - want: &Object{"integer", nil, nil, -65}, + want: &object.Object{class.Integer, nil, nil, -65}, wantErr: false, }, { name: "hexadecimal", args: args{"#X00101"}, - want: &Object{"integer", nil, nil, 257}, + want: &object.Object{class.Integer, nil, nil, 257}, wantErr: false, }, { name: "signed hexadecimal", args: args{"#x-00101"}, - want: &Object{"integer", nil, nil, -257}, + want: &object.Object{class.Integer, nil, nil, -257}, wantErr: false, }, { @@ -123,19 +126,19 @@ func Test_parseAtom(t *testing.T) { { name: "default", args: args{"#\\a"}, - want: &Object{"character", nil, nil, 'a'}, + want: &object.Object{class.Character, nil, nil, 'a'}, wantErr: false, }, { name: "newline", args: args{"#\\newline"}, - want: &Object{"character", nil, nil, '\n'}, + want: &object.Object{class.Character, nil, nil, '\n'}, wantErr: false, }, { name: "space", args: args{"#\\space"}, - want: &Object{"character", nil, nil, ' '}, + want: &object.Object{class.Character, nil, nil, ' '}, wantErr: false, }, { diff --git a/tokenizer.go b/reader/tokenizer/tokenizer.go similarity index 62% rename from tokenizer.go rename to reader/tokenizer/tokenizer.go index a3d77b9..ee9845e 100644 --- a/tokenizer.go +++ b/reader/tokenizer/tokenizer.go @@ -1,13 +1,42 @@ -package main +package tokenizer import ( + "io" "regexp" "strings" ) -// TokenReader interface type is the interface for reading string with every token -type TokenReader interface { - ReadToken() (string, error) +// TokenReader interface type is the interface +// for reading string with every token +// Reader is like bufio.Reader but has PeekRune +// which returns a rune without advancing pointer +type TokenReader struct { + err error + ru rune + sz int + rr io.RuneReader +} + +// NewReader creates interal reader from io.RuneReader +func NewTokenReader(r io.RuneReader) *TokenReader { + b := new(TokenReader) + b.rr = r + b.ru, b.sz, b.err = r.ReadRune() + return b +} + +// PeekRune returns a rune without advancing pointer +func (r *TokenReader) PeekRune() (rune, int, error) { + return r.ru, r.sz, r.err +} + +// ReadRune returns a rune with advancing pointer +func (r *TokenReader) ReadRune() (rune, int, error) { + ru := r.ru + sz := r.sz + err := r.err + r.ru, r.sz, r.err = r.rr.ReadRune() + return ru, sz, err } func concatMatcher(src ...string) *regexp.Regexp { @@ -32,7 +61,7 @@ var token = concatMatcher( parentheses) // ReadToken returns error or string as token -func (r *Reader) ReadToken() (string, error) { +func (r *TokenReader) ReadToken() (string, error) { buf := "" for { if buf == "" { diff --git a/tokenizer_test.go b/reader/tokenizer/tokenizer_test.go similarity index 97% rename from tokenizer_test.go rename to reader/tokenizer/tokenizer_test.go index 3374e70..5e21b5a 100644 --- a/tokenizer_test.go +++ b/reader/tokenizer/tokenizer_test.go @@ -1,4 +1,4 @@ -package main +package tokenizer import ( "io" diff --git a/runtime/class/class.go b/runtime/class/class.go new file mode 100644 index 0000000..77c0bf2 --- /dev/null +++ b/runtime/class/class.go @@ -0,0 +1,36 @@ +package class + +type Class struct { + Parents []*Class + name string +} + +var Object = &Class{[]*Class{}, ""} +var BuiltInClass = &Class{[]*Class{Object}, ""} +var StandardClass = &Class{[]*Class{Object}, ""} +var ArithmeticError = &Class{[]*Class{Object}, ""} +var FloatingPointUnderflow = &Class{[]*Class{Object}, ""} +var SimpleError = &Class{[]*Class{Object}, ""} + +var BasicArray = &Class{[]*Class{Object}, ""} +var BasicArrayStar = &Class{[]*Class{BasicArray}, ""} +var GeneralArrayStar = &Class{[]*Class{BasicArrayStar}, ""} +var BasicVector = &Class{[]*Class{BasicArray}, ""} +var GeneraVector = &Class{[]*Class{BasicVector}, ""} +var String = &Class{[]*Class{BasicVector}, ""} + +var Function = &Class{[]*Class{Object}, ""} +var GenericFunction = &Class{[]*Class{Function}, ""} +var StandardGenericFunction = &Class{[]*Class{GenericFunction}, ""} + +var Character = &Class{[]*Class{Object}, ""} + +var Number = &Class{[]*Class{Object}, ""} +var Integer = &Class{[]*Class{Number}, ""} +var Float = &Class{[]*Class{Number}, ""} + +var Symbol = &Class{[]*Class{Object}, ""} + +var List = &Class{[]*Class{Object}, ""} +var Cons = &Class{[]*Class{List}, ""} +var Null = &Class{[]*Class{List}, ""} diff --git a/runtime/environment.go b/runtime/environment.go new file mode 100644 index 0000000..5dc8a1f --- /dev/null +++ b/runtime/environment.go @@ -0,0 +1,19 @@ +package runtime + +import ( + "github.com/ta2gch/gazelle/runtime/object" +) + +// Env struct is the struct for keeping functions and variables +type Env struct { + Fun map[string]*object.Object + Var map[string]*object.Object +} + +// NewEnv creates new environment +func NewEnv() *Env { + env := new(Env) + env.Fun = map[string]*object.Object{} + env.Var = map[string]*object.Object{} + return env +} diff --git a/runtime/eval.go b/runtime/eval.go new file mode 100644 index 0000000..ba19364 --- /dev/null +++ b/runtime/eval.go @@ -0,0 +1,29 @@ +package runtime + +import ( + "errors" + "fmt" + + "github.com/ta2gch/gazelle/runtime/class" + "github.com/ta2gch/gazelle/runtime/object" +) + +// Eval evaluates any objects +func Eval(obj *object.Object, local *Env, global *Env) (*object.Object, error) { + if obj == nil { + return nil, nil + } + switch obj.Class { + case class.Symbol: + if val, ok := local.Var[obj.Val.(string)]; ok { + return val, nil + } + if val, ok := global.Var[obj.Val.(string)]; ok { + return val, nil + } + return nil, fmt.Errorf("%v is not defined", obj.Val) + case class.Integer, class.Float, class.Character, class.String: + return obj, nil + } + return nil, errors.New("I have no ideas") +} diff --git a/eval_test.go b/runtime/eval_test.go similarity index 50% rename from eval_test.go rename to runtime/eval_test.go index a17b872..85fee2e 100644 --- a/eval_test.go +++ b/runtime/eval_test.go @@ -1,42 +1,37 @@ -package main +package runtime import ( "reflect" "strings" "testing" + + "github.com/ta2gch/gazelle/reader/parser" + "github.com/ta2gch/gazelle/reader/tokenizer" + "github.com/ta2gch/gazelle/runtime/class" + "github.com/ta2gch/gazelle/runtime/object" ) -func read(s string) *Object { - e, _ := Parse(NewReader(strings.NewReader(s))) +func read(s string) *object.Object { + e, _ := parser.Parse(tokenizer.NewTokenReader(strings.NewReader(s))) return e } func TestEval(t *testing.T) { - testEnv := NewEnv() - testEnv.Fun["INC"] = &NativeFunction{func(args *Object, local *Env, global *Env) (*Object, error) { - return &Object{"integer", nil, nil, args.Car.Val.(int) + 1}, nil - }} type args struct { - obj *Object + obj *object.Object local *Env global *Env } tests := []struct { name string args args - want *Object + want *object.Object wantErr bool }{ { name: "local variable", - args: args{read("PI"), &Env{nil, nil, nil, map[string]*Object{"PI": read("3.14")}}, nil}, - want: &Object{"float", nil, nil, 3.14}, - wantErr: false, - }, - { - name: "function call", - args: args{read("(inc (inc 1))"), NewEnv(), testEnv}, - want: &Object{"integer", nil, nil, 3}, + args: args{read("PI"), &Env{nil, map[string]*object.Object{"PI": read("3.14")}}, nil}, + want: &object.Object{class.Float, nil, nil, 3.14}, wantErr: false, }, } diff --git a/runtime/object/object.go b/runtime/object/object.go new file mode 100644 index 0000000..d0af431 --- /dev/null +++ b/runtime/object/object.go @@ -0,0 +1,24 @@ +package object + +import "github.com/ta2gch/gazelle/runtime/class" + +// Object struct type is the struct for the internal representations +type Object struct { + Class *class.Class + Car *Object + Cdr *Object + Val interface{} +} + +// Is is for testing +func (o *Object) Is(val interface{}) bool { + return o.Val == val +} + +// Copy creates a clone of Object +func (o *Object) Copy() *Object { + if o == nil { + return nil + } + return &Object{o.Class, o.Car.Copy(), o.Cdr.Copy(), o.Val} +} From c7b2ded2834e6b2f90a41c0be5679133b3befba7 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Thu, 27 Jul 2017 15:59:30 +0900 Subject: [PATCH 032/228] Changed cons structure --- reader/parser/parser.go | 36 ++++++++++++++++++------------------ reader/parser/parser_test.go | 32 ++++++++++++++++---------------- runtime/eval_test.go | 2 +- runtime/object/object.go | 21 +++++++-------------- 4 files changed, 42 insertions(+), 49 deletions(-) diff --git a/reader/parser/parser.go b/reader/parser/parser.go index 63348f7..3cf46b2 100644 --- a/reader/parser/parser.go +++ b/reader/parser/parser.go @@ -19,9 +19,9 @@ var errBOD = errors.New("Begin Of Dot") // cons creates cons pair from two objects func cons(car *object.Object, cdr *object.Object) *object.Object { if cdr == nil || cdr.Class == class.List { - return &object.Object{class.List, car, cdr, nil} + return &object.Object{class.List, &object.Cons{car, cdr}} } - return &object.Object{class.Cons, car, cdr, nil} + return &object.Object{class.Cons, &object.Cons{car, cdr}} } func parseAtom(tok string) (*object.Object, error) { @@ -30,49 +30,49 @@ func parseAtom(tok string) (*object.Object, error) { // if m, _ := regexp.MatchString("^[-+]?[[:digit:]]+$", tok); m { n, _ := strconv.ParseInt(tok, 10, 64) - return &object.Object{class.Integer, nil, nil, int(n)}, nil + return &object.Object{class.Integer, int(n)}, nil } if r := regexp.MustCompile("^#[bB]([-+]?[01]+)$").FindStringSubmatch(tok); len(r) >= 2 { n, _ := strconv.ParseInt(r[1], 2, 64) - return &object.Object{class.Integer, nil, nil, int(n)}, nil + return &object.Object{class.Integer, int(n)}, nil } if r := regexp.MustCompile("^#[oO]([-+]?[0-7]+)$").FindStringSubmatch(tok); len(r) >= 2 { n, _ := strconv.ParseInt(r[1], 8, 64) - return &object.Object{class.Integer, nil, nil, int(n)}, nil + return &object.Object{class.Integer, int(n)}, nil } if r := regexp.MustCompile("^#[xX]([-+]?[[:xdigit:]]+)$").FindStringSubmatch(tok); len(r) >= 2 { n, _ := strconv.ParseInt(r[1], 16, 64) - return &object.Object{class.Integer, nil, nil, int(n)}, nil + return &object.Object{class.Integer, int(n)}, nil } // // float // if m, _ := regexp.MatchString("^[-+]?[[:digit:]]+\\.[[:digit:]]+$", tok); m { n, _ := strconv.ParseFloat(tok, 64) - return &object.Object{class.Float, nil, nil, n}, nil + return &object.Object{class.Float, n}, nil } if r := regexp.MustCompile("^([-+]?[[:digit:]]+(?:\\.[[:digit:]]+)?)[eE]([-+]?[[:digit:]]+)$").FindStringSubmatch(tok); len(r) >= 3 { n, _ := strconv.ParseFloat(r[1], 64) e, _ := strconv.ParseInt(r[2], 10, 64) - return &object.Object{class.Float, nil, nil, n * math.Pow10(int(e))}, nil + return &object.Object{class.Float, n * math.Pow10(int(e))}, nil } // // character // if m, _ := regexp.MatchString("^#\\\\newline$", tok); m { - return &object.Object{class.Character, nil, nil, '\n'}, nil + return &object.Object{class.Character, '\n'}, nil } if m, _ := regexp.MatchString("^#\\\\space$", tok); m { - return &object.Object{class.Character, nil, nil, ' '}, nil + return &object.Object{class.Character, ' '}, nil } if r := regexp.MustCompile("^#\\\\([[:graph:]])$").FindStringSubmatch(tok); len(r) >= 2 { - return &object.Object{class.Character, nil, nil, rune(r[1][0])}, nil + return &object.Object{class.Character, rune(r[1][0])}, nil } // // string // if m, _ := regexp.MatchString("^\".*\"$", tok); m { - return &object.Object{class.String, nil, nil, tok}, nil + return &object.Object{class.String, tok}, nil } // // symbol @@ -81,13 +81,13 @@ func parseAtom(tok string) (*object.Object, error) { return nil, nil } if r := regexp.MustCompile("^:([<>/*=?_!$%[\\]^{}~0-9a-zA-Z]+)$").FindStringSubmatch(tok); len(r) >= 2 { - return &object.Object{class.Symbol, nil, nil, r[1]}, nil + return &object.Object{class.Symbol, r[1]}, nil } if m, _ := regexp.MatchString("^\\|.*\\|$", tok); m { - return &object.Object{class.Symbol, nil, nil, tok}, nil + return &object.Object{class.Symbol, tok}, nil } if m, _ := regexp.MatchString("^[<>/*=?_!$%[\\]^{}~a-zA-Z][<>/*=?_!$%[\\]^{}~0-9a-zA-Z]*$", tok); m { - return &object.Object{class.Symbol, nil, nil, strings.ToUpper(tok)}, nil + return &object.Object{class.Symbol, strings.ToUpper(tok)}, nil } return nil, fmt.Errorf("Sorry, I could not parse %s", tok) } @@ -98,8 +98,8 @@ func parseMacro(tok string, t *tokenizer.TokenReader) (*object.Object, error) { } n := tok if m, _ := regexp.MatchString("#[[:digit:]]*[aA]", tok); m { - s := &object.Object{class.Symbol, nil, nil, "array"} - d := &object.Object{class.Integer, nil, nil, 0} + s := &object.Object{class.Symbol, "array"} + d := &object.Object{class.Integer, 0} i := strings.IndexRune(strings.ToLower(tok), 'a') if i == 1 { d.Val = 1 @@ -122,7 +122,7 @@ func parseMacro(tok string, t *tokenizer.TokenReader) (*object.Object, error) { case "`": n = "backquote" } - m := &object.Object{class.Symbol, nil, nil, n} + m := &object.Object{class.Symbol, n} return cons(m, cons(cdr, nil)), nil } func parseCons(t *tokenizer.TokenReader) (*object.Object, error) { diff --git a/reader/parser/parser_test.go b/reader/parser/parser_test.go index 0ed6f31..5742ddd 100644 --- a/reader/parser/parser_test.go +++ b/reader/parser/parser_test.go @@ -24,31 +24,31 @@ func Test_parseAtom(t *testing.T) { { name: "default", args: args{"3.14"}, - want: &object.Object{class.Float, nil, nil, 3.14}, + want: &object.Object{class.Float, 3.14}, wantErr: false, }, { name: "signed", args: args{"-5.0"}, - want: &object.Object{class.Float, nil, nil, -5.0}, + want: &object.Object{class.Float, -5.0}, wantErr: false, }, { name: "exponential", args: args{"-5.0E3"}, - want: &object.Object{class.Float, nil, nil, -5.0 * 1000}, + want: &object.Object{class.Float, -5.0 * 1000}, wantErr: false, }, { name: "signed exponential", args: args{"5.0E-3"}, - want: &object.Object{class.Float, nil, nil, 5.0 * 1.0 / 1000.0}, + want: &object.Object{class.Float, 5.0 * 1.0 / 1000.0}, wantErr: false, }, { name: "without point", args: args{"5E-3"}, - want: &object.Object{class.Float, nil, nil, 5.0 * 1.0 / 1000.0}, + want: &object.Object{class.Float, 5.0 * 1.0 / 1000.0}, wantErr: false, }, { @@ -69,49 +69,49 @@ func Test_parseAtom(t *testing.T) { { name: "default", args: args{"5"}, - want: &object.Object{class.Integer, nil, nil, 5}, + want: &object.Object{class.Integer, 5}, wantErr: false, }, { name: "signed", args: args{"-5"}, - want: &object.Object{class.Integer, nil, nil, -5}, + want: &object.Object{class.Integer, -5}, wantErr: false, }, { name: "binary", args: args{"#B00101"}, - want: &object.Object{class.Integer, nil, nil, 5}, + want: &object.Object{class.Integer, 5}, wantErr: false, }, { name: "signed binary", args: args{"#b+00101"}, - want: &object.Object{class.Integer, nil, nil, 5}, + want: &object.Object{class.Integer, 5}, wantErr: false, }, { name: "octal", args: args{"#o00101"}, - want: &object.Object{class.Integer, nil, nil, 65}, + want: &object.Object{class.Integer, 65}, wantErr: false, }, { name: "signed octal", args: args{"#O-00101"}, - want: &object.Object{class.Integer, nil, nil, -65}, + want: &object.Object{class.Integer, -65}, wantErr: false, }, { name: "hexadecimal", args: args{"#X00101"}, - want: &object.Object{class.Integer, nil, nil, 257}, + want: &object.Object{class.Integer, 257}, wantErr: false, }, { name: "signed hexadecimal", args: args{"#x-00101"}, - want: &object.Object{class.Integer, nil, nil, -257}, + want: &object.Object{class.Integer, -257}, wantErr: false, }, { @@ -126,19 +126,19 @@ func Test_parseAtom(t *testing.T) { { name: "default", args: args{"#\\a"}, - want: &object.Object{class.Character, nil, nil, 'a'}, + want: &object.Object{class.Character, 'a'}, wantErr: false, }, { name: "newline", args: args{"#\\newline"}, - want: &object.Object{class.Character, nil, nil, '\n'}, + want: &object.Object{class.Character, '\n'}, wantErr: false, }, { name: "space", args: args{"#\\space"}, - want: &object.Object{class.Character, nil, nil, ' '}, + want: &object.Object{class.Character, ' '}, wantErr: false, }, { diff --git a/runtime/eval_test.go b/runtime/eval_test.go index 85fee2e..d646527 100644 --- a/runtime/eval_test.go +++ b/runtime/eval_test.go @@ -31,7 +31,7 @@ func TestEval(t *testing.T) { { name: "local variable", args: args{read("PI"), &Env{nil, map[string]*object.Object{"PI": read("3.14")}}, nil}, - want: &object.Object{class.Float, nil, nil, 3.14}, + want: &object.Object{class.Float, 3.14}, wantErr: false, }, } diff --git a/runtime/object/object.go b/runtime/object/object.go index d0af431..fcaef59 100644 --- a/runtime/object/object.go +++ b/runtime/object/object.go @@ -1,24 +1,17 @@ package object -import "github.com/ta2gch/gazelle/runtime/class" +import ( + "github.com/ta2gch/gazelle/runtime/class" +) // Object struct type is the struct for the internal representations type Object struct { Class *class.Class - Car *Object - Cdr *Object Val interface{} } -// Is is for testing -func (o *Object) Is(val interface{}) bool { - return o.Val == val -} - -// Copy creates a clone of Object -func (o *Object) Copy() *Object { - if o == nil { - return nil - } - return &Object{o.Class, o.Car.Copy(), o.Cdr.Copy(), o.Val} +// Cons is a pair of pointers to Object +type Cons struct { + Car *Object + Cdr *Object } From 3bb3c6649d10f62cbc0702d8482e27ed2af0b8e3 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Thu, 27 Jul 2017 16:00:15 +0900 Subject: [PATCH 033/228] remove ExpReader --- reader/expression/expression.go | 18 ------------------ 1 file changed, 18 deletions(-) delete mode 100644 reader/expression/expression.go diff --git a/reader/expression/expression.go b/reader/expression/expression.go deleted file mode 100644 index 6c55788..0000000 --- a/reader/expression/expression.go +++ /dev/null @@ -1,18 +0,0 @@ -package expression - -import ( - "github.com/ta2gch/gazelle/reader/parser" - "github.com/ta2gch/gazelle/reader/tokenizer" - "github.com/ta2gch/gazelle/runtime" -) - -// ExpReader interface type is the interface for reading expressions. -type ExpReader struct { - tokenizer.TokenReader -} - -// ReadExp returns a expression that is a pointer to Object -func (r *ExpReader) ReadExp() (*runtime.Object, error) { - exp, err := parser.Parse(r) - return exp, err -} From 84b132910cbcf676be0b6d792248cddc4a8776f7 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Thu, 27 Jul 2017 16:39:24 +0900 Subject: [PATCH 034/228] Renamed Cons to Cell --- reader/parser/parser.go | 47 ++++++++++++++++++------------------ reader/parser/parser_test.go | 35 +++++++++++++-------------- runtime/class/instance.go | 13 ++++++++++ runtime/environment.go | 10 ++++---- runtime/eval.go | 19 ++++++++++++--- runtime/eval_test.go | 11 ++++----- runtime/function.go | 18 ++++++++++++++ runtime/object/object.go | 17 ------------- 8 files changed, 97 insertions(+), 73 deletions(-) create mode 100644 runtime/class/instance.go create mode 100644 runtime/function.go delete mode 100644 runtime/object/object.go diff --git a/reader/parser/parser.go b/reader/parser/parser.go index 3cf46b2..1dad2d1 100644 --- a/reader/parser/parser.go +++ b/reader/parser/parser.go @@ -10,69 +10,68 @@ import ( "github.com/ta2gch/gazelle/reader/tokenizer" "github.com/ta2gch/gazelle/runtime/class" - "github.com/ta2gch/gazelle/runtime/object" ) var errEOP = errors.New("End Of Parentheses") var errBOD = errors.New("Begin Of Dot") // cons creates cons pair from two objects -func cons(car *object.Object, cdr *object.Object) *object.Object { +func cons(car *class.Instance, cdr *class.Instance) *class.Instance { if cdr == nil || cdr.Class == class.List { - return &object.Object{class.List, &object.Cons{car, cdr}} + return &class.Instance{class.List, &class.Cell{car, cdr}} } - return &object.Object{class.Cons, &object.Cons{car, cdr}} + return &class.Instance{class.Cons, &class.Cell{car, cdr}} } -func parseAtom(tok string) (*object.Object, error) { +func parseAtom(tok string) (*class.Instance, error) { // // integer // if m, _ := regexp.MatchString("^[-+]?[[:digit:]]+$", tok); m { n, _ := strconv.ParseInt(tok, 10, 64) - return &object.Object{class.Integer, int(n)}, nil + return &class.Instance{class.Integer, int(n)}, nil } if r := regexp.MustCompile("^#[bB]([-+]?[01]+)$").FindStringSubmatch(tok); len(r) >= 2 { n, _ := strconv.ParseInt(r[1], 2, 64) - return &object.Object{class.Integer, int(n)}, nil + return &class.Instance{class.Integer, int(n)}, nil } if r := regexp.MustCompile("^#[oO]([-+]?[0-7]+)$").FindStringSubmatch(tok); len(r) >= 2 { n, _ := strconv.ParseInt(r[1], 8, 64) - return &object.Object{class.Integer, int(n)}, nil + return &class.Instance{class.Integer, int(n)}, nil } if r := regexp.MustCompile("^#[xX]([-+]?[[:xdigit:]]+)$").FindStringSubmatch(tok); len(r) >= 2 { n, _ := strconv.ParseInt(r[1], 16, 64) - return &object.Object{class.Integer, int(n)}, nil + return &class.Instance{class.Integer, int(n)}, nil } // // float // if m, _ := regexp.MatchString("^[-+]?[[:digit:]]+\\.[[:digit:]]+$", tok); m { n, _ := strconv.ParseFloat(tok, 64) - return &object.Object{class.Float, n}, nil + return &class.Instance{class.Float, n}, nil } if r := regexp.MustCompile("^([-+]?[[:digit:]]+(?:\\.[[:digit:]]+)?)[eE]([-+]?[[:digit:]]+)$").FindStringSubmatch(tok); len(r) >= 3 { n, _ := strconv.ParseFloat(r[1], 64) e, _ := strconv.ParseInt(r[2], 10, 64) - return &object.Object{class.Float, n * math.Pow10(int(e))}, nil + return &class.Instance{class.Float, n * math.Pow10(int(e))}, nil } // // character // if m, _ := regexp.MatchString("^#\\\\newline$", tok); m { - return &object.Object{class.Character, '\n'}, nil + return &class.Instance{class.Character, '\n'}, nil } if m, _ := regexp.MatchString("^#\\\\space$", tok); m { - return &object.Object{class.Character, ' '}, nil + return &class.Instance{class.Character, ' '}, nil } if r := regexp.MustCompile("^#\\\\([[:graph:]])$").FindStringSubmatch(tok); len(r) >= 2 { - return &object.Object{class.Character, rune(r[1][0])}, nil + return &class.Instance{class.Character, rune(r[1][0])}, nil } // // string // if m, _ := regexp.MatchString("^\".*\"$", tok); m { - return &object.Object{class.String, tok}, nil + return &class.Instance{class.String, tok}, nil } // // symbol @@ -81,25 +80,25 @@ func parseAtom(tok string) (*object.Object, error) { return nil, nil } if r := regexp.MustCompile("^:([<>/*=?_!$%[\\]^{}~0-9a-zA-Z]+)$").FindStringSubmatch(tok); len(r) >= 2 { - return &object.Object{class.Symbol, r[1]}, nil + return &class.Instance{class.Symbol, r[1]}, nil } if m, _ := regexp.MatchString("^\\|.*\\|$", tok); m { - return &object.Object{class.Symbol, tok}, nil + return &class.Instance{class.Symbol, tok}, nil } if m, _ := regexp.MatchString("^[<>/*=?_!$%[\\]^{}~a-zA-Z][<>/*=?_!$%[\\]^{}~0-9a-zA-Z]*$", tok); m { - return &object.Object{class.Symbol, strings.ToUpper(tok)}, nil + return &class.Instance{class.Symbol, strings.ToUpper(tok)}, nil } return nil, fmt.Errorf("Sorry, I could not parse %s", tok) } -func parseMacro(tok string, t *tokenizer.TokenReader) (*object.Object, error) { +func parseMacro(tok string, t *tokenizer.TokenReader) (*class.Instance, error) { cdr, err := Parse(t) if err != nil { return nil, err } n := tok if m, _ := regexp.MatchString("#[[:digit:]]*[aA]", tok); m { - s := &object.Object{class.Symbol, "array"} - d := &object.Object{class.Integer, 0} + s := &class.Instance{class.Symbol, "array"} + d := &class.Instance{class.Integer, 0} i := strings.IndexRune(strings.ToLower(tok), 'a') if i == 1 { d.Val = 1 @@ -122,10 +121,10 @@ func parseMacro(tok string, t *tokenizer.TokenReader) (*object.Object, error) { case "`": n = "backquote" } - m := &object.Object{class.Symbol, n} + m := &class.Instance{class.Symbol, n} return cons(m, cons(cdr, nil)), nil } -func parseCons(t *tokenizer.TokenReader) (*object.Object, error) { +func parseCons(t *tokenizer.TokenReader) (*class.Instance, error) { car, err := Parse(t) if err == errEOP { return nil, nil @@ -151,7 +150,7 @@ func parseCons(t *tokenizer.TokenReader) (*object.Object, error) { } // Parse builds a internal expression from tokens -func Parse(t *tokenizer.TokenReader) (*object.Object, error) { +func Parse(t *tokenizer.TokenReader) (*class.Instance, error) { tok, err := t.ReadToken() if err != nil { return nil, err diff --git a/reader/parser/parser_test.go b/reader/parser/parser_test.go index 5742ddd..eaf3994 100644 --- a/reader/parser/parser_test.go +++ b/reader/parser/parser_test.go @@ -5,7 +5,6 @@ import ( "testing" "github.com/ta2gch/gazelle/runtime/class" - "github.com/ta2gch/gazelle/runtime/object" ) func Test_parseAtom(t *testing.T) { @@ -15,7 +14,7 @@ func Test_parseAtom(t *testing.T) { tests := []struct { name string args args - want *object.Object + want *class.Instance wantErr bool }{ // @@ -24,31 +23,31 @@ func Test_parseAtom(t *testing.T) { { name: "default", args: args{"3.14"}, - want: &object.Object{class.Float, 3.14}, + want: &class.Instance{class.Float, 3.14}, wantErr: false, }, { name: "signed", args: args{"-5.0"}, - want: &object.Object{class.Float, -5.0}, + want: &class.Instance{class.Float, -5.0}, wantErr: false, }, { name: "exponential", args: args{"-5.0E3"}, - want: &object.Object{class.Float, -5.0 * 1000}, + want: &class.Instance{class.Float, -5.0 * 1000}, wantErr: false, }, { name: "signed exponential", args: args{"5.0E-3"}, - want: &object.Object{class.Float, 5.0 * 1.0 / 1000.0}, + want: &class.Instance{class.Float, 5.0 * 1.0 / 1000.0}, wantErr: false, }, { name: "without point", args: args{"5E-3"}, - want: &object.Object{class.Float, 5.0 * 1.0 / 1000.0}, + want: &class.Instance{class.Float, 5.0 * 1.0 / 1000.0}, wantErr: false, }, { @@ -69,49 +68,49 @@ func Test_parseAtom(t *testing.T) { { name: "default", args: args{"5"}, - want: &object.Object{class.Integer, 5}, + want: &class.Instance{class.Integer, 5}, wantErr: false, }, { name: "signed", args: args{"-5"}, - want: &object.Object{class.Integer, -5}, + want: &class.Instance{class.Integer, -5}, wantErr: false, }, { name: "binary", args: args{"#B00101"}, - want: &object.Object{class.Integer, 5}, + want: &class.Instance{class.Integer, 5}, wantErr: false, }, { name: "signed binary", args: args{"#b+00101"}, - want: &object.Object{class.Integer, 5}, + want: &class.Instance{class.Integer, 5}, wantErr: false, }, { name: "octal", args: args{"#o00101"}, - want: &object.Object{class.Integer, 65}, + want: &class.Instance{class.Integer, 65}, wantErr: false, }, { name: "signed octal", args: args{"#O-00101"}, - want: &object.Object{class.Integer, -65}, + want: &class.Instance{class.Integer, -65}, wantErr: false, }, { name: "hexadecimal", args: args{"#X00101"}, - want: &object.Object{class.Integer, 257}, + want: &class.Instance{class.Integer, 257}, wantErr: false, }, { name: "signed hexadecimal", args: args{"#x-00101"}, - want: &object.Object{class.Integer, -257}, + want: &class.Instance{class.Integer, -257}, wantErr: false, }, { @@ -126,19 +125,19 @@ func Test_parseAtom(t *testing.T) { { name: "default", args: args{"#\\a"}, - want: &object.Object{class.Character, 'a'}, + want: &class.Instance{class.Character, 'a'}, wantErr: false, }, { name: "newline", args: args{"#\\newline"}, - want: &object.Object{class.Character, '\n'}, + want: &class.Instance{class.Character, '\n'}, wantErr: false, }, { name: "space", args: args{"#\\space"}, - want: &object.Object{class.Character, ' '}, + want: &class.Instance{class.Character, ' '}, wantErr: false, }, { diff --git a/runtime/class/instance.go b/runtime/class/instance.go new file mode 100644 index 0000000..8aec066 --- /dev/null +++ b/runtime/class/instance.go @@ -0,0 +1,13 @@ +package class + +// Instance struct type is the struct for the internal representations +type Instance struct { + Class *Class + Val interface{} +} + +// Cell is a pair of pointers to Object +type Cell struct { + Car *Instance + Cdr *Instance +} diff --git a/runtime/environment.go b/runtime/environment.go index 5dc8a1f..893d075 100644 --- a/runtime/environment.go +++ b/runtime/environment.go @@ -1,19 +1,19 @@ package runtime import ( - "github.com/ta2gch/gazelle/runtime/object" + "github.com/ta2gch/gazelle/runtime/class" ) // Env struct is the struct for keeping functions and variables type Env struct { - Fun map[string]*object.Object - Var map[string]*object.Object + Fun map[string]*class.Instance + Var map[string]*class.Instance } // NewEnv creates new environment func NewEnv() *Env { env := new(Env) - env.Fun = map[string]*object.Object{} - env.Var = map[string]*object.Object{} + env.Fun = map[string]*class.Instance{} + env.Var = map[string]*class.Instance{} return env } diff --git a/runtime/eval.go b/runtime/eval.go index ba19364..3aee1f3 100644 --- a/runtime/eval.go +++ b/runtime/eval.go @@ -5,11 +5,10 @@ import ( "fmt" "github.com/ta2gch/gazelle/runtime/class" - "github.com/ta2gch/gazelle/runtime/object" ) -// Eval evaluates any objects -func Eval(obj *object.Object, local *Env, global *Env) (*object.Object, error) { +// Eval evaluates any classs +func Eval(obj *class.Instance, local *Env, global *Env) (*class.Instance, error) { if obj == nil { return nil, nil } @@ -22,6 +21,20 @@ func Eval(obj *object.Object, local *Env, global *Env) (*object.Object, error) { return val, nil } return nil, fmt.Errorf("%v is not defined", obj.Val) + case class.List: + if obj.Val.(class.Cell).Car.Class != class.Symbol { + return nil, fmt.Errorf("%v is not a symbol", obj.Val) + } + if f, ok := local.Fun[obj.Val.(class.Cell).Car.Val.(string)]; ok { + // TODO: Evaluate each arguments + r, err := f.Val.(Function).Apply(obj.Val.(class.Cell).Cdr, global) + return r, err + } + if f, ok := global.Fun[obj.Val.(class.Cell).Car.Val.(string)]; ok { + // TODO: Evaluate each arguments + r, err := f.Val.(Function).Apply(obj.Val.(class.Cell).Cdr, global) + return r, err + } case class.Integer, class.Float, class.Character, class.String: return obj, nil } diff --git a/runtime/eval_test.go b/runtime/eval_test.go index d646527..c9b445a 100644 --- a/runtime/eval_test.go +++ b/runtime/eval_test.go @@ -8,30 +8,29 @@ import ( "github.com/ta2gch/gazelle/reader/parser" "github.com/ta2gch/gazelle/reader/tokenizer" "github.com/ta2gch/gazelle/runtime/class" - "github.com/ta2gch/gazelle/runtime/object" ) -func read(s string) *object.Object { +func read(s string) *class.Instance { e, _ := parser.Parse(tokenizer.NewTokenReader(strings.NewReader(s))) return e } func TestEval(t *testing.T) { type args struct { - obj *object.Object + obj *class.Instance local *Env global *Env } tests := []struct { name string args args - want *object.Object + want *class.Instance wantErr bool }{ { name: "local variable", - args: args{read("PI"), &Env{nil, map[string]*object.Object{"PI": read("3.14")}}, nil}, - want: &object.Object{class.Float, 3.14}, + args: args{read("PI"), &Env{nil, map[string]*class.Instance{"PI": read("3.14")}}, nil}, + want: &class.Instance{class.Float, 3.14}, wantErr: false, }, } diff --git a/runtime/function.go b/runtime/function.go new file mode 100644 index 0000000..75d4e5a --- /dev/null +++ b/runtime/function.go @@ -0,0 +1,18 @@ +package runtime + +import ( + "github.com/ta2gch/gazelle/runtime/class" +) + +type Function interface { + Apply(args *class.Instance, global *Env) (*class.Instance, error) +} + +type NativeFunction struct { + fun func(*class.Instance, *Env) (*class.Instance, error) +} + +func (f NativeFunction) Apply(args *class.Instance, global *Env) (*class.Instance, error) { + obj, err := f.fun(args, global) + return obj, err +} diff --git a/runtime/object/object.go b/runtime/object/object.go deleted file mode 100644 index fcaef59..0000000 --- a/runtime/object/object.go +++ /dev/null @@ -1,17 +0,0 @@ -package object - -import ( - "github.com/ta2gch/gazelle/runtime/class" -) - -// Object struct type is the struct for the internal representations -type Object struct { - Class *class.Class - Val interface{} -} - -// Cons is a pair of pointers to Object -type Cons struct { - Car *Object - Cdr *Object -} From ed9fdb7e61e5cf4f98b24ebb43174f9f3d58f44e Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Thu, 27 Jul 2017 17:09:24 +0900 Subject: [PATCH 035/228] Renamed package name runtime to core --- core/class/class.go | 38 +++++++++++++++++++++++++++++ {runtime => core}/class/instance.go | 0 {runtime => core}/environment.go | 7 ++++-- {runtime => core}/eval.go | 4 +-- {runtime => core}/eval_test.go | 4 +-- {runtime => core}/function.go | 4 +-- reader/parser/parser.go | 2 +- reader/parser/parser_test.go | 2 +- runtime/class/class.go | 36 --------------------------- 9 files changed, 51 insertions(+), 46 deletions(-) create mode 100644 core/class/class.go rename {runtime => core}/class/instance.go (100%) rename {runtime => core}/environment.go (74%) rename {runtime => core}/eval.go (94%) rename {runtime => core}/eval_test.go (94%) rename {runtime => core}/function.go (85%) delete mode 100644 runtime/class/class.go diff --git a/core/class/class.go b/core/class/class.go new file mode 100644 index 0000000..8bb4945 --- /dev/null +++ b/core/class/class.go @@ -0,0 +1,38 @@ +package class + +type Class struct { + Parents []*Class + name string +} + +func (c *Class) ToString() string { + return c.name +} + +func NewClass(parent *Class, name string) *Class { + return &Class{[]*Class{parent}, name} +} + +var Object = &Class{[]*Class{}, ""} +var BuiltInClass = NewClass(Object, "") +var StandardClass = NewClass(Object, "") +var ArithmeticError = NewClass(Object, "") +var FloatingPointUnderflow = NewClass(Object, "") +var SimpleError = NewClass(Object, "") +var BasicArray = NewClass(Object, "") +var BasicArrayStar = NewClass(BasicArray, "") +var GeneralArrayStar = NewClass(BasicArrayStar, "") +var BasicVector = NewClass(BasicArray, "") +var GeneraVector = NewClass(BasicVector, "") +var String = NewClass(BasicVector, "") +var Function = NewClass(Object, "") +var GenericFunction = NewClass(Function, "") +var StandardGenericFunction = NewClass(GenericFunction, "") +var Character = NewClass(Object, "") +var Number = NewClass(Object, "") +var Integer = NewClass(Number, "") +var Float = NewClass(Number, "") +var Symbol = NewClass(Object, "") +var List = NewClass(Object, "") +var Cons = NewClass(List, "") +var Null = NewClass(List, "") diff --git a/runtime/class/instance.go b/core/class/instance.go similarity index 100% rename from runtime/class/instance.go rename to core/class/instance.go diff --git a/runtime/environment.go b/core/environment.go similarity index 74% rename from runtime/environment.go rename to core/environment.go index 893d075..18ee8f8 100644 --- a/runtime/environment.go +++ b/core/environment.go @@ -1,7 +1,7 @@ -package runtime +package core import ( - "github.com/ta2gch/gazelle/runtime/class" + "github.com/ta2gch/gazelle/core/class" ) // Env struct is the struct for keeping functions and variables @@ -17,3 +17,6 @@ func NewEnv() *Env { env.Var = map[string]*class.Instance{} return env } + +// TopLevel is a global environment +var TopLevel = NewEnv() diff --git a/runtime/eval.go b/core/eval.go similarity index 94% rename from runtime/eval.go rename to core/eval.go index 3aee1f3..f78b383 100644 --- a/runtime/eval.go +++ b/core/eval.go @@ -1,10 +1,10 @@ -package runtime +package core import ( "errors" "fmt" - "github.com/ta2gch/gazelle/runtime/class" + "github.com/ta2gch/gazelle/core/class" ) // Eval evaluates any classs diff --git a/runtime/eval_test.go b/core/eval_test.go similarity index 94% rename from runtime/eval_test.go rename to core/eval_test.go index c9b445a..d6f4559 100644 --- a/runtime/eval_test.go +++ b/core/eval_test.go @@ -1,4 +1,4 @@ -package runtime +package core import ( "reflect" @@ -7,7 +7,7 @@ import ( "github.com/ta2gch/gazelle/reader/parser" "github.com/ta2gch/gazelle/reader/tokenizer" - "github.com/ta2gch/gazelle/runtime/class" + "github.com/ta2gch/gazelle/core/class" ) func read(s string) *class.Instance { diff --git a/runtime/function.go b/core/function.go similarity index 85% rename from runtime/function.go rename to core/function.go index 75d4e5a..c739b74 100644 --- a/runtime/function.go +++ b/core/function.go @@ -1,7 +1,7 @@ -package runtime +package core import ( - "github.com/ta2gch/gazelle/runtime/class" + "github.com/ta2gch/gazelle/core/class" ) type Function interface { diff --git a/reader/parser/parser.go b/reader/parser/parser.go index 1dad2d1..0e9eba3 100644 --- a/reader/parser/parser.go +++ b/reader/parser/parser.go @@ -8,8 +8,8 @@ import ( "strconv" "strings" + "github.com/ta2gch/gazelle/core/class" "github.com/ta2gch/gazelle/reader/tokenizer" - "github.com/ta2gch/gazelle/runtime/class" ) var errEOP = errors.New("End Of Parentheses") diff --git a/reader/parser/parser_test.go b/reader/parser/parser_test.go index eaf3994..3829f41 100644 --- a/reader/parser/parser_test.go +++ b/reader/parser/parser_test.go @@ -4,7 +4,7 @@ import ( "reflect" "testing" - "github.com/ta2gch/gazelle/runtime/class" + "github.com/ta2gch/gazelle/core/class" ) func Test_parseAtom(t *testing.T) { diff --git a/runtime/class/class.go b/runtime/class/class.go deleted file mode 100644 index 77c0bf2..0000000 --- a/runtime/class/class.go +++ /dev/null @@ -1,36 +0,0 @@ -package class - -type Class struct { - Parents []*Class - name string -} - -var Object = &Class{[]*Class{}, ""} -var BuiltInClass = &Class{[]*Class{Object}, ""} -var StandardClass = &Class{[]*Class{Object}, ""} -var ArithmeticError = &Class{[]*Class{Object}, ""} -var FloatingPointUnderflow = &Class{[]*Class{Object}, ""} -var SimpleError = &Class{[]*Class{Object}, ""} - -var BasicArray = &Class{[]*Class{Object}, ""} -var BasicArrayStar = &Class{[]*Class{BasicArray}, ""} -var GeneralArrayStar = &Class{[]*Class{BasicArrayStar}, ""} -var BasicVector = &Class{[]*Class{BasicArray}, ""} -var GeneraVector = &Class{[]*Class{BasicVector}, ""} -var String = &Class{[]*Class{BasicVector}, ""} - -var Function = &Class{[]*Class{Object}, ""} -var GenericFunction = &Class{[]*Class{Function}, ""} -var StandardGenericFunction = &Class{[]*Class{GenericFunction}, ""} - -var Character = &Class{[]*Class{Object}, ""} - -var Number = &Class{[]*Class{Object}, ""} -var Integer = &Class{[]*Class{Number}, ""} -var Float = &Class{[]*Class{Number}, ""} - -var Symbol = &Class{[]*Class{Object}, ""} - -var List = &Class{[]*Class{Object}, ""} -var Cons = &Class{[]*Class{List}, ""} -var Null = &Class{[]*Class{List}, ""} From 864eece710446a1c9c4f818e2bcd4ec38d613d8a Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Thu, 27 Jul 2017 22:25:26 +0900 Subject: [PATCH 036/228] Added New reciever --- core/class/class.go | 50 +++++++++++++++++++----------------- core/eval_test.go | 6 ++--- reader/parser/parser.go | 36 +++++++++++++------------- reader/parser/parser_test.go | 32 +++++++++++------------ 4 files changed, 64 insertions(+), 60 deletions(-) diff --git a/core/class/class.go b/core/class/class.go index 8bb4945..32169fe 100644 --- a/core/class/class.go +++ b/core/class/class.go @@ -9,30 +9,34 @@ func (c *Class) ToString() string { return c.name } -func NewClass(parent *Class, name string) *Class { +func (c *Class) New(val interface{}, rest ...interface{}) *Instance { + return &Instance{c, val} +} + +func defclass(parent *Class, name string) *Class { return &Class{[]*Class{parent}, name} } var Object = &Class{[]*Class{}, ""} -var BuiltInClass = NewClass(Object, "") -var StandardClass = NewClass(Object, "") -var ArithmeticError = NewClass(Object, "") -var FloatingPointUnderflow = NewClass(Object, "") -var SimpleError = NewClass(Object, "") -var BasicArray = NewClass(Object, "") -var BasicArrayStar = NewClass(BasicArray, "") -var GeneralArrayStar = NewClass(BasicArrayStar, "") -var BasicVector = NewClass(BasicArray, "") -var GeneraVector = NewClass(BasicVector, "") -var String = NewClass(BasicVector, "") -var Function = NewClass(Object, "") -var GenericFunction = NewClass(Function, "") -var StandardGenericFunction = NewClass(GenericFunction, "") -var Character = NewClass(Object, "") -var Number = NewClass(Object, "") -var Integer = NewClass(Number, "") -var Float = NewClass(Number, "") -var Symbol = NewClass(Object, "") -var List = NewClass(Object, "") -var Cons = NewClass(List, "") -var Null = NewClass(List, "") +var BuiltInClass = defclass(Object, "") +var StandardClass = defclass(Object, "") +var ArithmeticError = defclass(Object, "") +var FloatingPointUnderflow = defclass(Object, "") +var SimpleError = defclass(Object, "") +var BasicArray = defclass(Object, "") +var BasicArrayStar = defclass(BasicArray, "") +var GeneralArrayStar = defclass(BasicArrayStar, "") +var BasicVector = defclass(BasicArray, "") +var GeneraVector = defclass(BasicVector, "") +var String = defclass(BasicVector, "") +var Function = defclass(Object, "") +var GenericFunction = defclass(Function, "") +var StandardGenericFunction = defclass(GenericFunction, "") +var Character = defclass(Object, "") +var Number = defclass(Object, "") +var Integer = defclass(Number, "") +var Float = defclass(Number, "") +var Symbol = defclass(Object, "") +var List = defclass(Object, "") +var Cons = defclass(List, "") +var Null = defclass(List, "") diff --git a/core/eval_test.go b/core/eval_test.go index d6f4559..1062935 100644 --- a/core/eval_test.go +++ b/core/eval_test.go @@ -5,9 +5,9 @@ import ( "strings" "testing" + "github.com/ta2gch/gazelle/core/class" "github.com/ta2gch/gazelle/reader/parser" "github.com/ta2gch/gazelle/reader/tokenizer" - "github.com/ta2gch/gazelle/core/class" ) func read(s string) *class.Instance { @@ -29,8 +29,8 @@ func TestEval(t *testing.T) { }{ { name: "local variable", - args: args{read("PI"), &Env{nil, map[string]*class.Instance{"PI": read("3.14")}}, nil}, - want: &class.Instance{class.Float, 3.14}, + args: args{read("PI"), &Env{nil, map[string]*class.Instance{"PI": class.Float.New(3.14)}}, nil}, + want: class.Float.New(3.14), wantErr: false, }, } diff --git a/reader/parser/parser.go b/reader/parser/parser.go index 0e9eba3..b07eab8 100644 --- a/reader/parser/parser.go +++ b/reader/parser/parser.go @@ -18,9 +18,9 @@ var errBOD = errors.New("Begin Of Dot") // cons creates cons pair from two objects func cons(car *class.Instance, cdr *class.Instance) *class.Instance { if cdr == nil || cdr.Class == class.List { - return &class.Instance{class.List, &class.Cell{car, cdr}} + return class.List.New(&class.Cell{car, cdr}) } - return &class.Instance{class.Cons, &class.Cell{car, cdr}} + return class.Cons.New(&class.Cell{car, cdr}) } func parseAtom(tok string) (*class.Instance, error) { @@ -29,49 +29,49 @@ func parseAtom(tok string) (*class.Instance, error) { // if m, _ := regexp.MatchString("^[-+]?[[:digit:]]+$", tok); m { n, _ := strconv.ParseInt(tok, 10, 64) - return &class.Instance{class.Integer, int(n)}, nil + return class.Integer.New(int(n)), nil } if r := regexp.MustCompile("^#[bB]([-+]?[01]+)$").FindStringSubmatch(tok); len(r) >= 2 { n, _ := strconv.ParseInt(r[1], 2, 64) - return &class.Instance{class.Integer, int(n)}, nil + return class.Integer.New(int(n)), nil } if r := regexp.MustCompile("^#[oO]([-+]?[0-7]+)$").FindStringSubmatch(tok); len(r) >= 2 { n, _ := strconv.ParseInt(r[1], 8, 64) - return &class.Instance{class.Integer, int(n)}, nil + return class.Integer.New(int(n)), nil } if r := regexp.MustCompile("^#[xX]([-+]?[[:xdigit:]]+)$").FindStringSubmatch(tok); len(r) >= 2 { n, _ := strconv.ParseInt(r[1], 16, 64) - return &class.Instance{class.Integer, int(n)}, nil + return class.Integer.New(int(n)), nil } // // float // if m, _ := regexp.MatchString("^[-+]?[[:digit:]]+\\.[[:digit:]]+$", tok); m { n, _ := strconv.ParseFloat(tok, 64) - return &class.Instance{class.Float, n}, nil + return class.Float.New(n), nil } if r := regexp.MustCompile("^([-+]?[[:digit:]]+(?:\\.[[:digit:]]+)?)[eE]([-+]?[[:digit:]]+)$").FindStringSubmatch(tok); len(r) >= 3 { n, _ := strconv.ParseFloat(r[1], 64) e, _ := strconv.ParseInt(r[2], 10, 64) - return &class.Instance{class.Float, n * math.Pow10(int(e))}, nil + return class.Float.New(n * math.Pow10(int(e))), nil } // // character // if m, _ := regexp.MatchString("^#\\\\newline$", tok); m { - return &class.Instance{class.Character, '\n'}, nil + return class.Character.New('\n'), nil } if m, _ := regexp.MatchString("^#\\\\space$", tok); m { - return &class.Instance{class.Character, ' '}, nil + return class.Character.New(' '), nil } if r := regexp.MustCompile("^#\\\\([[:graph:]])$").FindStringSubmatch(tok); len(r) >= 2 { - return &class.Instance{class.Character, rune(r[1][0])}, nil + return class.Character.New(rune(r[1][0])), nil } // // string // if m, _ := regexp.MatchString("^\".*\"$", tok); m { - return &class.Instance{class.String, tok}, nil + return class.String.New(tok), nil } // // symbol @@ -80,13 +80,13 @@ func parseAtom(tok string) (*class.Instance, error) { return nil, nil } if r := regexp.MustCompile("^:([<>/*=?_!$%[\\]^{}~0-9a-zA-Z]+)$").FindStringSubmatch(tok); len(r) >= 2 { - return &class.Instance{class.Symbol, r[1]}, nil + return class.Symbol.New(r[1]), nil } if m, _ := regexp.MatchString("^\\|.*\\|$", tok); m { - return &class.Instance{class.Symbol, tok}, nil + return class.Symbol.New(tok), nil } if m, _ := regexp.MatchString("^[<>/*=?_!$%[\\]^{}~a-zA-Z][<>/*=?_!$%[\\]^{}~0-9a-zA-Z]*$", tok); m { - return &class.Instance{class.Symbol, strings.ToUpper(tok)}, nil + return class.Symbol.New(strings.ToUpper(tok)), nil } return nil, fmt.Errorf("Sorry, I could not parse %s", tok) } @@ -97,8 +97,8 @@ func parseMacro(tok string, t *tokenizer.TokenReader) (*class.Instance, error) { } n := tok if m, _ := regexp.MatchString("#[[:digit:]]*[aA]", tok); m { - s := &class.Instance{class.Symbol, "array"} - d := &class.Instance{class.Integer, 0} + s := class.Symbol.New("array") + d := class.Integer.New(0) i := strings.IndexRune(strings.ToLower(tok), 'a') if i == 1 { d.Val = 1 @@ -121,7 +121,7 @@ func parseMacro(tok string, t *tokenizer.TokenReader) (*class.Instance, error) { case "`": n = "backquote" } - m := &class.Instance{class.Symbol, n} + m := class.Symbol.New(n) return cons(m, cons(cdr, nil)), nil } func parseCons(t *tokenizer.TokenReader) (*class.Instance, error) { diff --git a/reader/parser/parser_test.go b/reader/parser/parser_test.go index 3829f41..4e45e0a 100644 --- a/reader/parser/parser_test.go +++ b/reader/parser/parser_test.go @@ -23,31 +23,31 @@ func Test_parseAtom(t *testing.T) { { name: "default", args: args{"3.14"}, - want: &class.Instance{class.Float, 3.14}, + want: class.Float.New(3.14), wantErr: false, }, { name: "signed", args: args{"-5.0"}, - want: &class.Instance{class.Float, -5.0}, + want: class.Float.New(-5.0), wantErr: false, }, { name: "exponential", args: args{"-5.0E3"}, - want: &class.Instance{class.Float, -5.0 * 1000}, + want: class.Float.New(-5.0 * 1000), wantErr: false, }, { name: "signed exponential", args: args{"5.0E-3"}, - want: &class.Instance{class.Float, 5.0 * 1.0 / 1000.0}, + want: class.Float.New(5.0 * 1.0 / 1000.0), wantErr: false, }, { name: "without point", args: args{"5E-3"}, - want: &class.Instance{class.Float, 5.0 * 1.0 / 1000.0}, + want: class.Float.New(5.0 * 1.0 / 1000.0), wantErr: false, }, { @@ -68,49 +68,49 @@ func Test_parseAtom(t *testing.T) { { name: "default", args: args{"5"}, - want: &class.Instance{class.Integer, 5}, + want: class.Integer.New(5), wantErr: false, }, { name: "signed", args: args{"-5"}, - want: &class.Instance{class.Integer, -5}, + want: class.Integer.New(-5), wantErr: false, }, { name: "binary", args: args{"#B00101"}, - want: &class.Instance{class.Integer, 5}, + want: class.Integer.New(5), wantErr: false, }, { name: "signed binary", args: args{"#b+00101"}, - want: &class.Instance{class.Integer, 5}, + want: class.Integer.New(5), wantErr: false, }, { name: "octal", args: args{"#o00101"}, - want: &class.Instance{class.Integer, 65}, + want: class.Integer.New(65), wantErr: false, }, { name: "signed octal", args: args{"#O-00101"}, - want: &class.Instance{class.Integer, -65}, + want: class.Integer.New(-65), wantErr: false, }, { name: "hexadecimal", args: args{"#X00101"}, - want: &class.Instance{class.Integer, 257}, + want: class.Integer.New(257), wantErr: false, }, { name: "signed hexadecimal", args: args{"#x-00101"}, - want: &class.Instance{class.Integer, -257}, + want: class.Integer.New(-257), wantErr: false, }, { @@ -125,19 +125,19 @@ func Test_parseAtom(t *testing.T) { { name: "default", args: args{"#\\a"}, - want: &class.Instance{class.Character, 'a'}, + want: class.Character.New('a'), wantErr: false, }, { name: "newline", args: args{"#\\newline"}, - want: &class.Instance{class.Character, '\n'}, + want: class.Character.New('\n'), wantErr: false, }, { name: "space", args: args{"#\\space"}, - want: &class.Instance{class.Character, ' '}, + want: class.Character.New(' '), wantErr: false, }, { From 36ac4a8b1895031e904ee48c307026df7d116e2f Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Fri, 28 Jul 2017 12:44:38 +0900 Subject: [PATCH 037/228] Added cons package --- core/class/cons/cons.go | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 core/class/cons/cons.go diff --git a/core/class/cons/cons.go b/core/class/cons/cons.go new file mode 100644 index 0000000..678fdb7 --- /dev/null +++ b/core/class/cons/cons.go @@ -0,0 +1,31 @@ +package cons + +import ( + "fmt" + + "github.com/ta2gch/gazelle/core/class" +) + +// Cell is a pair of pointers to Object +type Cell struct { + Car *class.Instance + Cdr *class.Instance +} + +func New(car *class.Instance, cdr *class.Instance) *class.Instance { + return class.Cons.New(&Cell{car, cdr}) +} + +func Car(i *class.Instance) (*class.Instance, error) { + if i == nil || i.Class() != class.Cons && i.Class() != class.List { + return nil, fmt.Errorf("%v is not a member of ", i.Class().ToString()) + } + return i.Value().(Cell).Car, nil +} + +func Cdr(i *class.Instance) (*class.Instance, error) { + if i == nil || i.Class() != class.Cons && i.Class() != class.List { + return nil, fmt.Errorf("%v is not a member of ", i.Class().ToString()) + } + return i.Value().(Cell).Cdr, nil +} From 0554e3794768430466a6753340ac03cb7146e77d Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Fri, 28 Jul 2017 12:45:16 +0900 Subject: [PATCH 038/228] Made Instance be readonly --- core/class/instance.go | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/core/class/instance.go b/core/class/instance.go index 8aec066..5fe087c 100644 --- a/core/class/instance.go +++ b/core/class/instance.go @@ -2,12 +2,20 @@ package class // Instance struct type is the struct for the internal representations type Instance struct { - Class *Class - Val interface{} + class *Class + value interface{} } -// Cell is a pair of pointers to Object -type Cell struct { - Car *Instance - Cdr *Instance +func (i *Instance) Class() *Class { + if i == nil { + return Null + } + return i.class +} + +func (i *Instance) Value() interface{} { + if i == nil { + return Null + } + return i.value } From 5c99e191fe3b3755f57562f9dd7ce0388bd4d54f Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Fri, 28 Jul 2017 12:45:54 +0900 Subject: [PATCH 039/228] Added NewClass function --- core/class/class.go | 54 ++++++++++++++++++++++----------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/core/class/class.go b/core/class/class.go index 32169fe..cb39ffa 100644 --- a/core/class/class.go +++ b/core/class/class.go @@ -5,38 +5,38 @@ type Class struct { name string } -func (c *Class) ToString() string { - return c.name +func (class *Class) ToString() string { + return class.name } -func (c *Class) New(val interface{}, rest ...interface{}) *Instance { - return &Instance{c, val} +func (class *Class) New(value interface{}) *Instance { + return &Instance{class, value} } -func defclass(parent *Class, name string) *Class { +func NewClass(parent *Class, name string) *Class { return &Class{[]*Class{parent}, name} } var Object = &Class{[]*Class{}, ""} -var BuiltInClass = defclass(Object, "") -var StandardClass = defclass(Object, "") -var ArithmeticError = defclass(Object, "") -var FloatingPointUnderflow = defclass(Object, "") -var SimpleError = defclass(Object, "") -var BasicArray = defclass(Object, "") -var BasicArrayStar = defclass(BasicArray, "") -var GeneralArrayStar = defclass(BasicArrayStar, "") -var BasicVector = defclass(BasicArray, "") -var GeneraVector = defclass(BasicVector, "") -var String = defclass(BasicVector, "") -var Function = defclass(Object, "") -var GenericFunction = defclass(Function, "") -var StandardGenericFunction = defclass(GenericFunction, "") -var Character = defclass(Object, "") -var Number = defclass(Object, "") -var Integer = defclass(Number, "") -var Float = defclass(Number, "") -var Symbol = defclass(Object, "") -var List = defclass(Object, "") -var Cons = defclass(List, "") -var Null = defclass(List, "") +var BuiltInClass = NewClass(Object, "") +var StandardClass = NewClass(Object, "") +var ArithmeticError = NewClass(Object, "") +var FloatingPointUnderflow = NewClass(Object, "") +var SimpleError = NewClass(Object, "") +var BasicArray = NewClass(Object, "") +var BasicArrayStar = NewClass(BasicArray, "") +var GeneralArrayStar = NewClass(BasicArrayStar, "") +var BasicVector = NewClass(BasicArray, "") +var GeneraVector = NewClass(BasicVector, "") +var String = NewClass(BasicVector, "") +var Function = NewClass(Object, "") +var GenericFunction = NewClass(Function, "") +var StandardGenericFunction = NewClass(GenericFunction, "") +var Character = NewClass(Object, "") +var Number = NewClass(Object, "") +var Integer = NewClass(Number, "") +var Float = NewClass(Number, "") +var Symbol = NewClass(Object, "") +var List = NewClass(Object, "") +var Cons = NewClass(List, "") +var Null = NewClass(List, "") From c388d361c76464be89e5504886de9b967c32127e Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Fri, 28 Jul 2017 12:46:12 +0900 Subject: [PATCH 040/228] Added function package --- core/class/function/function.go | 52 +++++++++++++++++++++++++++++++++ core/function.go | 18 ------------ 2 files changed, 52 insertions(+), 18 deletions(-) create mode 100644 core/class/function/function.go delete mode 100644 core/function.go diff --git a/core/class/function/function.go b/core/class/function/function.go new file mode 100644 index 0000000..53fcafc --- /dev/null +++ b/core/class/function/function.go @@ -0,0 +1,52 @@ +package function + +import ( + "fmt" + + "github.com/ta2gch/gazelle/core/class" + "github.com/ta2gch/gazelle/core/environment" +) + +type Function interface { + apply(args *class.Instance, global *environment.Env) (*class.Instance, error) +} + +func Apply(fun *class.Instance, args *class.Instance, global *environment.Env) (*class.Instance, error) { + if fun.Class() != class.Function { + return nil, fmt.Errorf("%v is not ", fun.Class().ToString()) + } + obj, err := fun.Value().(Function).apply(args, global) + if err != nil { + return nil, err + } + return obj, nil +} + +type NativeFunction struct { + fun func(*class.Instance, *environment.Env) (*class.Instance, error) +} + +func (f NativeFunction) apply(args *class.Instance, global *environment.Env) (*class.Instance, error) { + obj, err := f.fun(args, global) + if err != nil { + return nil, err + } + return obj, nil +} + +func NewNativeFunction(fun func(*class.Instance, *environment.Env) (*class.Instance, error)) *class.Instance { + return class.Function.New(&NativeFunction{fun}) +} + +type DefaultFunction struct { + args *class.Instance + body *class.Instance +} + +/* +func (f *DefaultFunction) Apply(args *class.Instance, global *Env) (*class.Instance, error) { + // Assign args to local environment + // Eval each body + // return evaluate result +}z +*/ diff --git a/core/function.go b/core/function.go deleted file mode 100644 index c739b74..0000000 --- a/core/function.go +++ /dev/null @@ -1,18 +0,0 @@ -package core - -import ( - "github.com/ta2gch/gazelle/core/class" -) - -type Function interface { - Apply(args *class.Instance, global *Env) (*class.Instance, error) -} - -type NativeFunction struct { - fun func(*class.Instance, *Env) (*class.Instance, error) -} - -func (f NativeFunction) Apply(args *class.Instance, global *Env) (*class.Instance, error) { - obj, err := f.fun(args, global) - return obj, err -} From 3d3ad1cd5c4a36dc6d7cdf1646e17470b9ea483d Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Fri, 28 Jul 2017 12:46:25 +0900 Subject: [PATCH 041/228] Added environment package --- core/{ => environment}/environment.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) rename core/{ => environment}/environment.go (79%) diff --git a/core/environment.go b/core/environment/environment.go similarity index 79% rename from core/environment.go rename to core/environment/environment.go index 18ee8f8..1944547 100644 --- a/core/environment.go +++ b/core/environment/environment.go @@ -1,4 +1,4 @@ -package core +package environment import ( "github.com/ta2gch/gazelle/core/class" @@ -10,8 +10,8 @@ type Env struct { Var map[string]*class.Instance } -// NewEnv creates new environment -func NewEnv() *Env { +// New creates new environment +func New() *Env { env := new(Env) env.Fun = map[string]*class.Instance{} env.Var = map[string]*class.Instance{} @@ -19,4 +19,4 @@ func NewEnv() *Env { } // TopLevel is a global environment -var TopLevel = NewEnv() +var TopLevel = New() From 9ab810cb75269cac9ac361d4ea665c6206cb3ed0 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Fri, 28 Jul 2017 12:46:48 +0900 Subject: [PATCH 042/228] Updated reader --- reader/parser/parser.go | 30 +++++++++++------------------- reader/tokenizer/tokenizer.go | 4 ++-- 2 files changed, 13 insertions(+), 21 deletions(-) diff --git a/reader/parser/parser.go b/reader/parser/parser.go index b07eab8..a7da716 100644 --- a/reader/parser/parser.go +++ b/reader/parser/parser.go @@ -9,20 +9,13 @@ import ( "strings" "github.com/ta2gch/gazelle/core/class" + "github.com/ta2gch/gazelle/core/class/cons" "github.com/ta2gch/gazelle/reader/tokenizer" ) var errEOP = errors.New("End Of Parentheses") var errBOD = errors.New("Begin Of Dot") -// cons creates cons pair from two objects -func cons(car *class.Instance, cdr *class.Instance) *class.Instance { - if cdr == nil || cdr.Class == class.List { - return class.List.New(&class.Cell{car, cdr}) - } - return class.Cons.New(&class.Cell{car, cdr}) -} - func parseAtom(tok string) (*class.Instance, error) { // // integer @@ -98,18 +91,17 @@ func parseMacro(tok string, t *tokenizer.TokenReader) (*class.Instance, error) { n := tok if m, _ := regexp.MatchString("#[[:digit:]]*[aA]", tok); m { s := class.Symbol.New("array") - d := class.Integer.New(0) i := strings.IndexRune(strings.ToLower(tok), 'a') if i == 1 { - d.Val = 1 - } else { - v, err := strconv.ParseInt(tok[1:i], 10, 32) - if err != nil { - return nil, err - } - d.Val = int(v) + d := class.Integer.New(1) + return cons.New(s, cons.New(d, cons.New(cdr, nil))), nil + } + v, err := strconv.ParseInt(tok[1:i], 10, 32) + if err != nil { + return nil, err } - return cons(s, cons(d, cons(cdr, nil))), nil + d := class.Integer.New(int(v)) + return cons.New(s, cons.New(d, cons.New(cdr, nil))), nil } switch tok { case ",@": @@ -122,7 +114,7 @@ func parseMacro(tok string, t *tokenizer.TokenReader) (*class.Instance, error) { n = "backquote" } m := class.Symbol.New(n) - return cons(m, cons(cdr, nil)), nil + return cons.New(m, cons.New(cdr, nil)), nil } func parseCons(t *tokenizer.TokenReader) (*class.Instance, error) { car, err := Parse(t) @@ -146,7 +138,7 @@ func parseCons(t *tokenizer.TokenReader) (*class.Instance, error) { if err != nil { return nil, err } - return cons(car, cdr), nil + return cons.New(car, cdr), nil } // Parse builds a internal expression from tokens diff --git a/reader/tokenizer/tokenizer.go b/reader/tokenizer/tokenizer.go index ee9845e..7780ed7 100644 --- a/reader/tokenizer/tokenizer.go +++ b/reader/tokenizer/tokenizer.go @@ -17,8 +17,8 @@ type TokenReader struct { rr io.RuneReader } -// NewReader creates interal reader from io.RuneReader -func NewTokenReader(r io.RuneReader) *TokenReader { +// New creates interal reader from io.RuneReader +func New(r io.RuneReader) *TokenReader { b := new(TokenReader) b.rr = r b.ru, b.sz, b.err = r.ReadRune() From 0a65b552b75dc977767fb214bc0d31ddf8bb86a1 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Fri, 28 Jul 2017 13:18:00 +0900 Subject: [PATCH 043/228] Used Null class --- core/class/cons/cons.go | 15 +++++++++------ core/class/instance.go | 7 ++----- reader/parser/parser.go | 4 ++-- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/core/class/cons/cons.go b/core/class/cons/cons.go index 678fdb7..2a69dec 100644 --- a/core/class/cons/cons.go +++ b/core/class/cons/cons.go @@ -8,24 +8,27 @@ import ( // Cell is a pair of pointers to Object type Cell struct { - Car *class.Instance - Cdr *class.Instance + car *class.Instance + cdr *class.Instance } func New(car *class.Instance, cdr *class.Instance) *class.Instance { + if cdr.Class() == class.Null || cdr.Class() == class.List { + return class.List.New(&Cell{car, cdr}) + } return class.Cons.New(&Cell{car, cdr}) } func Car(i *class.Instance) (*class.Instance, error) { - if i == nil || i.Class() != class.Cons && i.Class() != class.List { + if i.Class() == class.Null || (i.Class() != class.Cons && i.Class() != class.List) { return nil, fmt.Errorf("%v is not a member of ", i.Class().ToString()) } - return i.Value().(Cell).Car, nil + return i.Value().(*Cell).car, nil } func Cdr(i *class.Instance) (*class.Instance, error) { - if i == nil || i.Class() != class.Cons && i.Class() != class.List { + if i.Class() == class.Null || (i.Class() != class.Cons && i.Class() != class.List) { return nil, fmt.Errorf("%v is not a member of ", i.Class().ToString()) } - return i.Value().(Cell).Cdr, nil + return i.Value().(*Cell).cdr, nil } diff --git a/core/class/instance.go b/core/class/instance.go index 5fe087c..f402301 100644 --- a/core/class/instance.go +++ b/core/class/instance.go @@ -7,15 +7,12 @@ type Instance struct { } func (i *Instance) Class() *Class { - if i == nil { - return Null - } return i.class } func (i *Instance) Value() interface{} { - if i == nil { - return Null + if i.Class() == Null { + return nil } return i.value } diff --git a/reader/parser/parser.go b/reader/parser/parser.go index a7da716..d3aab10 100644 --- a/reader/parser/parser.go +++ b/reader/parser/parser.go @@ -70,7 +70,7 @@ func parseAtom(tok string) (*class.Instance, error) { // symbol // if "nil" == strings.ToLower(tok) { - return nil, nil + return class.Null.New(nil), nil } if r := regexp.MustCompile("^:([<>/*=?_!$%[\\]^{}~0-9a-zA-Z]+)$").FindStringSubmatch(tok); len(r) >= 2 { return class.Symbol.New(r[1]), nil @@ -119,7 +119,7 @@ func parseMacro(tok string, t *tokenizer.TokenReader) (*class.Instance, error) { func parseCons(t *tokenizer.TokenReader) (*class.Instance, error) { car, err := Parse(t) if err == errEOP { - return nil, nil + return class.Null.New(nil), nil } if err == errBOD { cdr, err := Parse(t) From cc16885e368f2b78af94ba9caa00f942ec07964d Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Fri, 28 Jul 2017 13:18:11 +0900 Subject: [PATCH 044/228] Added calling function --- core/class/function/function.go | 2 +- core/eval.go | 80 ++++++++++++++++++++++++++------- core/eval_test.go | 23 ++++++++-- 3 files changed, 83 insertions(+), 22 deletions(-) diff --git a/core/class/function/function.go b/core/class/function/function.go index 53fcafc..675bc33 100644 --- a/core/class/function/function.go +++ b/core/class/function/function.go @@ -34,7 +34,7 @@ func (f NativeFunction) apply(args *class.Instance, global *environment.Env) (*c return obj, nil } -func NewNativeFunction(fun func(*class.Instance, *environment.Env) (*class.Instance, error)) *class.Instance { +func New(fun func(*class.Instance, *environment.Env) (*class.Instance, error)) *class.Instance { return class.Function.New(&NativeFunction{fun}) } diff --git a/core/eval.go b/core/eval.go index f78b383..d991477 100644 --- a/core/eval.go +++ b/core/eval.go @@ -5,35 +5,81 @@ import ( "fmt" "github.com/ta2gch/gazelle/core/class" + "github.com/ta2gch/gazelle/core/class/cons" + "github.com/ta2gch/gazelle/core/class/function" + "github.com/ta2gch/gazelle/core/environment" ) +func evalArgs(args *class.Instance, local *environment.Env, global *environment.Env) (*class.Instance, error) { + if args.Class() == class.Null { + return class.Null.New(nil), nil + } + car, err := cons.Car(args) + if err != nil { + return nil, err + } + cdr, err := cons.Cdr(args) + if err != nil { + return nil, err + } + a, err := Eval(car, local, global) + if err != nil { + return nil, err + } + b, err := evalArgs(cdr, local, global) + if err != nil { + return nil, err + } + return cons.New(a, b), nil +} + // Eval evaluates any classs -func Eval(obj *class.Instance, local *Env, global *Env) (*class.Instance, error) { - if obj == nil { - return nil, nil +func Eval(obj *class.Instance, local *environment.Env, global *environment.Env) (*class.Instance, error) { + if obj.Class() == class.Null { + return class.Null.New(nil), nil } - switch obj.Class { + switch obj.Class() { case class.Symbol: - if val, ok := local.Var[obj.Val.(string)]; ok { + if val, ok := local.Var[obj.Value().(string)]; ok { return val, nil } - if val, ok := global.Var[obj.Val.(string)]; ok { + if val, ok := global.Var[obj.Value().(string)]; ok { return val, nil } - return nil, fmt.Errorf("%v is not defined", obj.Val) + return nil, fmt.Errorf("%v is not defined", obj.Value()) case class.List: - if obj.Val.(class.Cell).Car.Class != class.Symbol { - return nil, fmt.Errorf("%v is not a symbol", obj.Val) + car, err := cons.Car(obj) + if err != nil { + return nil, err + } + cdr, err := cons.Cdr(obj) + if err != nil { + return nil, err + } + if car.Class() != class.Symbol { + return nil, fmt.Errorf("%v is not a symbol", obj.Value()) } - if f, ok := local.Fun[obj.Val.(class.Cell).Car.Val.(string)]; ok { - // TODO: Evaluate each arguments - r, err := f.Val.(Function).Apply(obj.Val.(class.Cell).Cdr, global) - return r, err + if f, ok := local.Fun[car.Value().(string)]; ok { + a, err := evalArgs(cdr, local, global) + if err != nil { + return nil, err + } + r, err := function.Apply(f, a, global) + if err != nil { + return nil, err + } + return r, nil } - if f, ok := global.Fun[obj.Val.(class.Cell).Car.Val.(string)]; ok { - // TODO: Evaluate each arguments - r, err := f.Val.(Function).Apply(obj.Val.(class.Cell).Cdr, global) - return r, err + if f, ok := global.Fun[car.Value().(string)]; ok { + a, err := evalArgs(cdr, local, global) + if err != nil { + return nil, err + } + r, err := function.Apply(f, a, global) + if err != nil { + return nil, err + } + return r, nil } case class.Integer, class.Float, class.Character, class.String: return obj, nil diff --git a/core/eval_test.go b/core/eval_test.go index 1062935..87887a7 100644 --- a/core/eval_test.go +++ b/core/eval_test.go @@ -6,20 +6,29 @@ import ( "testing" "github.com/ta2gch/gazelle/core/class" + "github.com/ta2gch/gazelle/core/class/cons" + "github.com/ta2gch/gazelle/core/class/function" + "github.com/ta2gch/gazelle/core/environment" "github.com/ta2gch/gazelle/reader/parser" "github.com/ta2gch/gazelle/reader/tokenizer" ) func read(s string) *class.Instance { - e, _ := parser.Parse(tokenizer.NewTokenReader(strings.NewReader(s))) + e, _ := parser.Parse(tokenizer.New(strings.NewReader(s))) return e } func TestEval(t *testing.T) { + testEnv := environment.New() + testEnv.Var["PI"] = class.Float.New(3.14) + testEnv.Fun["INC"] = function.New(func(args *class.Instance, global *environment.Env) (*class.Instance, error) { + car, _ := cons.Car(args) + return class.Integer.New(car.Value().(int) + 1), nil + }) type args struct { obj *class.Instance - local *Env - global *Env + local *environment.Env + global *environment.Env } tests := []struct { name string @@ -29,10 +38,16 @@ func TestEval(t *testing.T) { }{ { name: "local variable", - args: args{read("PI"), &Env{nil, map[string]*class.Instance{"PI": class.Float.New(3.14)}}, nil}, + args: args{class.Symbol.New("PI"), testEnv, nil}, want: class.Float.New(3.14), wantErr: false, }, + { + name: "local function", + args: args{read("(inc (inc 1))"), testEnv, nil}, + want: class.Integer.New(3), + wantErr: false, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { From 2d2877777af34cffa58cda2e2253555f490bb284 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Fri, 28 Jul 2017 13:57:06 +0900 Subject: [PATCH 045/228] Renamed Environment Class --- core/class/function/function.go | 10 +++++----- core/environment/environment.go | 16 ++++++++-------- core/eval.go | 12 ++++++------ core/eval_test.go | 8 ++++---- 4 files changed, 23 insertions(+), 23 deletions(-) diff --git a/core/class/function/function.go b/core/class/function/function.go index 675bc33..410c9e8 100644 --- a/core/class/function/function.go +++ b/core/class/function/function.go @@ -8,10 +8,10 @@ import ( ) type Function interface { - apply(args *class.Instance, global *environment.Env) (*class.Instance, error) + apply(args *class.Instance, global *environment.Environment) (*class.Instance, error) } -func Apply(fun *class.Instance, args *class.Instance, global *environment.Env) (*class.Instance, error) { +func Apply(fun *class.Instance, args *class.Instance, global *environment.Environment) (*class.Instance, error) { if fun.Class() != class.Function { return nil, fmt.Errorf("%v is not ", fun.Class().ToString()) } @@ -23,10 +23,10 @@ func Apply(fun *class.Instance, args *class.Instance, global *environment.Env) ( } type NativeFunction struct { - fun func(*class.Instance, *environment.Env) (*class.Instance, error) + fun func(*class.Instance, *environment.Environment) (*class.Instance, error) } -func (f NativeFunction) apply(args *class.Instance, global *environment.Env) (*class.Instance, error) { +func (f NativeFunction) apply(args *class.Instance, global *environment.Environment) (*class.Instance, error) { obj, err := f.fun(args, global) if err != nil { return nil, err @@ -34,7 +34,7 @@ func (f NativeFunction) apply(args *class.Instance, global *environment.Env) (*c return obj, nil } -func New(fun func(*class.Instance, *environment.Env) (*class.Instance, error)) *class.Instance { +func New(fun func(*class.Instance, *environment.Environment) (*class.Instance, error)) *class.Instance { return class.Function.New(&NativeFunction{fun}) } diff --git a/core/environment/environment.go b/core/environment/environment.go index 1944547..7fa2357 100644 --- a/core/environment/environment.go +++ b/core/environment/environment.go @@ -4,17 +4,17 @@ import ( "github.com/ta2gch/gazelle/core/class" ) -// Env struct is the struct for keeping functions and variables -type Env struct { - Fun map[string]*class.Instance - Var map[string]*class.Instance +// Environment struct is the struct for keeping functions and variables +type Environment struct { + Function map[string]*class.Instance + Variable map[string]*class.Instance } // New creates new environment -func New() *Env { - env := new(Env) - env.Fun = map[string]*class.Instance{} - env.Var = map[string]*class.Instance{} +func New() *Environment { + env := new(Environment) + env.Function = map[string]*class.Instance{} + env.Variable = map[string]*class.Instance{} return env } diff --git a/core/eval.go b/core/eval.go index d991477..0c1086c 100644 --- a/core/eval.go +++ b/core/eval.go @@ -10,7 +10,7 @@ import ( "github.com/ta2gch/gazelle/core/environment" ) -func evalArgs(args *class.Instance, local *environment.Env, global *environment.Env) (*class.Instance, error) { +func evalArgs(args *class.Instance, local *environment.Environment, global *environment.Environment) (*class.Instance, error) { if args.Class() == class.Null { return class.Null.New(nil), nil } @@ -34,16 +34,16 @@ func evalArgs(args *class.Instance, local *environment.Env, global *environment. } // Eval evaluates any classs -func Eval(obj *class.Instance, local *environment.Env, global *environment.Env) (*class.Instance, error) { +func Eval(obj *class.Instance, local *environment.Environment, global *environment.Environment) (*class.Instance, error) { if obj.Class() == class.Null { return class.Null.New(nil), nil } switch obj.Class() { case class.Symbol: - if val, ok := local.Var[obj.Value().(string)]; ok { + if val, ok := local.Variable[obj.Value().(string)]; ok { return val, nil } - if val, ok := global.Var[obj.Value().(string)]; ok { + if val, ok := global.Variable[obj.Value().(string)]; ok { return val, nil } return nil, fmt.Errorf("%v is not defined", obj.Value()) @@ -59,7 +59,7 @@ func Eval(obj *class.Instance, local *environment.Env, global *environment.Env) if car.Class() != class.Symbol { return nil, fmt.Errorf("%v is not a symbol", obj.Value()) } - if f, ok := local.Fun[car.Value().(string)]; ok { + if f, ok := local.Function[car.Value().(string)]; ok { a, err := evalArgs(cdr, local, global) if err != nil { return nil, err @@ -70,7 +70,7 @@ func Eval(obj *class.Instance, local *environment.Env, global *environment.Env) } return r, nil } - if f, ok := global.Fun[car.Value().(string)]; ok { + if f, ok := global.Function[car.Value().(string)]; ok { a, err := evalArgs(cdr, local, global) if err != nil { return nil, err diff --git a/core/eval_test.go b/core/eval_test.go index 87887a7..320df15 100644 --- a/core/eval_test.go +++ b/core/eval_test.go @@ -20,15 +20,15 @@ func read(s string) *class.Instance { func TestEval(t *testing.T) { testEnv := environment.New() - testEnv.Var["PI"] = class.Float.New(3.14) - testEnv.Fun["INC"] = function.New(func(args *class.Instance, global *environment.Env) (*class.Instance, error) { + testEnv.Variable["PI"] = class.Float.New(3.14) + testEnv.Function["INC"] = function.New(func(args *class.Instance, global *environment.Environment) (*class.Instance, error) { car, _ := cons.Car(args) return class.Integer.New(car.Value().(int) + 1), nil }) type args struct { obj *class.Instance - local *environment.Env - global *environment.Env + local *environment.Environment + global *environment.Environment } tests := []struct { name string From 17e973bd51ddaf2d47c4853b49815b2641ef5ab3 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Fri, 28 Jul 2017 13:57:26 +0900 Subject: [PATCH 046/228] Added Classes --- core/class/class.go | 36 ++++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/core/class/class.go b/core/class/class.go index cb39ffa..0ee3e1c 100644 --- a/core/class/class.go +++ b/core/class/class.go @@ -18,25 +18,41 @@ func NewClass(parent *Class, name string) *Class { } var Object = &Class{[]*Class{}, ""} -var BuiltInClass = NewClass(Object, "") -var StandardClass = NewClass(Object, "") -var ArithmeticError = NewClass(Object, "") -var FloatingPointUnderflow = NewClass(Object, "") -var SimpleError = NewClass(Object, "") var BasicArray = NewClass(Object, "") var BasicArrayStar = NewClass(BasicArray, "") var GeneralArrayStar = NewClass(BasicArrayStar, "") var BasicVector = NewClass(BasicArray, "") var GeneraVector = NewClass(BasicVector, "") var String = NewClass(BasicVector, "") +var BuiltInClass = NewClass(Object, "") +var Character = NewClass(Object, "") var Function = NewClass(Object, "") var GenericFunction = NewClass(Function, "") var StandardGenericFunction = NewClass(GenericFunction, "") -var Character = NewClass(Object, "") -var Number = NewClass(Object, "") -var Integer = NewClass(Number, "") -var Float = NewClass(Number, "") -var Symbol = NewClass(Object, "") var List = NewClass(Object, "") var Cons = NewClass(List, "") var Null = NewClass(List, "") +var Symbol = NewClass(Object, "") +var Number = NewClass(Object, "") +var Integer = NewClass(Number, "") +var Float = NewClass(Number, "") +var SeriousCondition = NewClass(Object, "") +var Error = NewClass(SeriousCondition, "") +var ArithmeticError = NewClass(Error, "") +var DivisionByZero = NewClass(ArithmeticError, "") +var FloatingPointOnderflow = NewClass(ArithmeticError, "") +var FloatingPointUnderflow = NewClass(ArithmeticError, "") +var ControlError = NewClass(Error, "") +var ParseError = NewClass(Error, "") +var ProgramError = NewClass(Error, "") +var DomainError = NewClass(ProgramError, "") +var UndefinedEntity = NewClass(ProgramError, "") +var UndefinedVariable = NewClass(UndefinedEntity, "") +var UndefinedFunction = NewClass(UndefinedEntity, "") +var SimpleError = NewClass(Error, "") +var StreamError = NewClass(Error, "") +var EndOfStream = NewClass(StreamError, "") +var StorageExhausted = NewClass(SeriousCondition, "") +var StandardClass = NewClass(Object, "") +var StandardObject = NewClass(Object, "") +var Stream = NewClass(Object, "") From a3ceb30ce2b26d753d410b2d5353e2c8b760fcc9 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Fri, 28 Jul 2017 15:20:28 +0900 Subject: [PATCH 047/228] case sensitive --- core/eval_test.go | 6 +++--- reader/parser/parser.go | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/core/eval_test.go b/core/eval_test.go index 320df15..abb0003 100644 --- a/core/eval_test.go +++ b/core/eval_test.go @@ -20,8 +20,8 @@ func read(s string) *class.Instance { func TestEval(t *testing.T) { testEnv := environment.New() - testEnv.Variable["PI"] = class.Float.New(3.14) - testEnv.Function["INC"] = function.New(func(args *class.Instance, global *environment.Environment) (*class.Instance, error) { + testEnv.Variable["pi"] = class.Float.New(3.14) + testEnv.Function["inc"] = function.New(func(args *class.Instance, global *environment.Environment) (*class.Instance, error) { car, _ := cons.Car(args) return class.Integer.New(car.Value().(int) + 1), nil }) @@ -38,7 +38,7 @@ func TestEval(t *testing.T) { }{ { name: "local variable", - args: args{class.Symbol.New("PI"), testEnv, nil}, + args: args{class.Symbol.New("pi"), testEnv, nil}, want: class.Float.New(3.14), wantErr: false, }, diff --git a/reader/parser/parser.go b/reader/parser/parser.go index d3aab10..86e8874 100644 --- a/reader/parser/parser.go +++ b/reader/parser/parser.go @@ -69,7 +69,7 @@ func parseAtom(tok string) (*class.Instance, error) { // // symbol // - if "nil" == strings.ToLower(tok) { + if "nil" == tok { return class.Null.New(nil), nil } if r := regexp.MustCompile("^:([<>/*=?_!$%[\\]^{}~0-9a-zA-Z]+)$").FindStringSubmatch(tok); len(r) >= 2 { @@ -79,7 +79,7 @@ func parseAtom(tok string) (*class.Instance, error) { return class.Symbol.New(tok), nil } if m, _ := regexp.MatchString("^[<>/*=?_!$%[\\]^{}~a-zA-Z][<>/*=?_!$%[\\]^{}~0-9a-zA-Z]*$", tok); m { - return class.Symbol.New(strings.ToUpper(tok)), nil + return class.Symbol.New(tok), nil } return nil, fmt.Errorf("Sorry, I could not parse %s", tok) } From b91c7f695a1340664fe19e922e7221f9e1f3b2b3 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Fri, 28 Jul 2017 16:29:55 +0900 Subject: [PATCH 048/228] Added dynamic scope --- core/class/function/function.go | 23 +++++++++------- core/environment/environment.go | 2 ++ core/eval.go | 48 ++++++++++++++++++++++++++------- core/eval_test.go | 23 +++++++++------- 4 files changed, 68 insertions(+), 28 deletions(-) diff --git a/core/class/function/function.go b/core/class/function/function.go index 410c9e8..9ce79f2 100644 --- a/core/class/function/function.go +++ b/core/class/function/function.go @@ -4,18 +4,18 @@ import ( "fmt" "github.com/ta2gch/gazelle/core/class" - "github.com/ta2gch/gazelle/core/environment" + env "github.com/ta2gch/gazelle/core/environment" ) type Function interface { - apply(args *class.Instance, global *environment.Environment) (*class.Instance, error) + apply(args *class.Instance, local *env.Environment, dynamic *env.Environment, global *env.Environment) (*class.Instance, error) } -func Apply(fun *class.Instance, args *class.Instance, global *environment.Environment) (*class.Instance, error) { +func Apply(fun *class.Instance, args *class.Instance, local *env.Environment, dynamic *env.Environment, global *env.Environment) (*class.Instance, error) { if fun.Class() != class.Function { return nil, fmt.Errorf("%v is not ", fun.Class().ToString()) } - obj, err := fun.Value().(Function).apply(args, global) + obj, err := fun.Value().(Function).apply(args, local, dynamic, global) if err != nil { return nil, err } @@ -23,18 +23,18 @@ func Apply(fun *class.Instance, args *class.Instance, global *environment.Enviro } type NativeFunction struct { - fun func(*class.Instance, *environment.Environment) (*class.Instance, error) + fun func(*class.Instance, *env.Environment, *env.Environment, *env.Environment) (*class.Instance, error) } -func (f NativeFunction) apply(args *class.Instance, global *environment.Environment) (*class.Instance, error) { - obj, err := f.fun(args, global) +func (f NativeFunction) apply(args *class.Instance, local *env.Environment, dynamic *env.Environment, global *env.Environment) (*class.Instance, error) { + obj, err := f.fun(args, local, global, global) if err != nil { return nil, err } return obj, nil } -func New(fun func(*class.Instance, *environment.Environment) (*class.Instance, error)) *class.Instance { +func New(fun func(*class.Instance, *env.Environment, *env.Environment, *env.Environment) (*class.Instance, error)) *class.Instance { return class.Function.New(&NativeFunction{fun}) } @@ -48,5 +48,10 @@ func (f *DefaultFunction) Apply(args *class.Instance, global *Env) (*class.Insta // Assign args to local environment // Eval each body // return evaluate result -}z +} */ + +type GenericFunction struct { + args *class.Instance + body *class.Instance +} diff --git a/core/environment/environment.go b/core/environment/environment.go index 7fa2357..db89c9a 100644 --- a/core/environment/environment.go +++ b/core/environment/environment.go @@ -6,6 +6,7 @@ import ( // Environment struct is the struct for keeping functions and variables type Environment struct { + Macro map[string]*class.Instance Function map[string]*class.Instance Variable map[string]*class.Instance } @@ -13,6 +14,7 @@ type Environment struct { // New creates new environment func New() *Environment { env := new(Environment) + env.Macro = map[string]*class.Instance{} env.Function = map[string]*class.Instance{} env.Variable = map[string]*class.Instance{} return env diff --git a/core/eval.go b/core/eval.go index 0c1086c..72f3470 100644 --- a/core/eval.go +++ b/core/eval.go @@ -7,10 +7,10 @@ import ( "github.com/ta2gch/gazelle/core/class" "github.com/ta2gch/gazelle/core/class/cons" "github.com/ta2gch/gazelle/core/class/function" - "github.com/ta2gch/gazelle/core/environment" + env "github.com/ta2gch/gazelle/core/environment" ) -func evalArgs(args *class.Instance, local *environment.Environment, global *environment.Environment) (*class.Instance, error) { +func evalArgs(args *class.Instance, local *env.Environment, dynamic *env.Environment, global *env.Environment) (*class.Instance, error) { if args.Class() == class.Null { return class.Null.New(nil), nil } @@ -22,11 +22,11 @@ func evalArgs(args *class.Instance, local *environment.Environment, global *envi if err != nil { return nil, err } - a, err := Eval(car, local, global) + a, err := Eval(car, local, dynamic, global) if err != nil { return nil, err } - b, err := evalArgs(cdr, local, global) + b, err := evalArgs(cdr, local, dynamic, global) if err != nil { return nil, err } @@ -34,7 +34,7 @@ func evalArgs(args *class.Instance, local *environment.Environment, global *envi } // Eval evaluates any classs -func Eval(obj *class.Instance, local *environment.Environment, global *environment.Environment) (*class.Instance, error) { +func Eval(obj *class.Instance, local *env.Environment, dynamic *env.Environment, global *env.Environment) (*class.Instance, error) { if obj.Class() == class.Null { return class.Null.New(nil), nil } @@ -60,25 +60,55 @@ func Eval(obj *class.Instance, local *environment.Environment, global *environme return nil, fmt.Errorf("%v is not a symbol", obj.Value()) } if f, ok := local.Function[car.Value().(string)]; ok { - a, err := evalArgs(cdr, local, global) + a, err := evalArgs(cdr, local, dynamic, global) if err != nil { return nil, err } - r, err := function.Apply(f, a, global) + ks := []string{} + for k := range dynamic.Variable { + ks = append(ks, k) + } + r, err := function.Apply(f, a, env.New(), dynamic, global) if err != nil { return nil, err } + for k := range dynamic.Variable { + v := true + for _, l := range ks { + if k == l { + v = false + } + } + if v { + delete(dynamic.Variable, k) + } + } return r, nil } if f, ok := global.Function[car.Value().(string)]; ok { - a, err := evalArgs(cdr, local, global) + a, err := evalArgs(cdr, local, dynamic, global) if err != nil { return nil, err } - r, err := function.Apply(f, a, global) + ks := []string{} + for k := range dynamic.Variable { + ks = append(ks, k) + } + r, err := function.Apply(f, a, env.New(), dynamic, global) if err != nil { return nil, err } + for k := range dynamic.Variable { + v := true + for _, l := range ks { + if k == l { + v = false + } + } + if v { + delete(dynamic.Variable, k) + } + } return r, nil } case class.Integer, class.Float, class.Character, class.String: diff --git a/core/eval_test.go b/core/eval_test.go index abb0003..93f8c6b 100644 --- a/core/eval_test.go +++ b/core/eval_test.go @@ -8,7 +8,7 @@ import ( "github.com/ta2gch/gazelle/core/class" "github.com/ta2gch/gazelle/core/class/cons" "github.com/ta2gch/gazelle/core/class/function" - "github.com/ta2gch/gazelle/core/environment" + env "github.com/ta2gch/gazelle/core/environment" "github.com/ta2gch/gazelle/reader/parser" "github.com/ta2gch/gazelle/reader/tokenizer" ) @@ -19,16 +19,19 @@ func read(s string) *class.Instance { } func TestEval(t *testing.T) { - testEnv := environment.New() - testEnv.Variable["pi"] = class.Float.New(3.14) - testEnv.Function["inc"] = function.New(func(args *class.Instance, global *environment.Environment) (*class.Instance, error) { + local := env.New() + dynamic := env.New() + global := env.New() + local.Variable["pi"] = class.Float.New(3.14) + local.Function["inc"] = function.New(func(args *class.Instance, local *env.Environment, dynamic *env.Environment, global *env.Environment) (*class.Instance, error) { car, _ := cons.Car(args) return class.Integer.New(car.Value().(int) + 1), nil }) type args struct { - obj *class.Instance - local *environment.Environment - global *environment.Environment + obj *class.Instance + local *env.Environment + dynamic *env.Environment + global *env.Environment } tests := []struct { name string @@ -38,20 +41,20 @@ func TestEval(t *testing.T) { }{ { name: "local variable", - args: args{class.Symbol.New("pi"), testEnv, nil}, + args: args{class.Symbol.New("pi"), local, dynamic, global}, want: class.Float.New(3.14), wantErr: false, }, { name: "local function", - args: args{read("(inc (inc 1))"), testEnv, nil}, + args: args{read("(inc (inc 1))"), local, dynamic, global}, want: class.Integer.New(3), wantErr: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := Eval(tt.args.obj, tt.args.local, tt.args.global) + got, err := Eval(tt.args.obj, tt.args.local, tt.args.dynamic, tt.args.global) if (err != nil) != tt.wantErr { t.Errorf("Eval() error = %v, wantErr %v", err, tt.wantErr) return From 987ccc9db2eb118382c6b8b8bc51955f07ad910f Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Fri, 28 Jul 2017 18:26:53 +0900 Subject: [PATCH 049/228] Renamed Tokenizer --- reader/parser/parser.go | 8 ++++---- reader/tokenizer/tokenizer.go | 16 ++++++++-------- reader/tokenizer/tokenizer_test.go | 4 ++-- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/reader/parser/parser.go b/reader/parser/parser.go index 86e8874..ba679b8 100644 --- a/reader/parser/parser.go +++ b/reader/parser/parser.go @@ -83,7 +83,7 @@ func parseAtom(tok string) (*class.Instance, error) { } return nil, fmt.Errorf("Sorry, I could not parse %s", tok) } -func parseMacro(tok string, t *tokenizer.TokenReader) (*class.Instance, error) { +func parseMacro(tok string, t *tokenizer.Tokenizer) (*class.Instance, error) { cdr, err := Parse(t) if err != nil { return nil, err @@ -116,7 +116,7 @@ func parseMacro(tok string, t *tokenizer.TokenReader) (*class.Instance, error) { m := class.Symbol.New(n) return cons.New(m, cons.New(cdr, nil)), nil } -func parseCons(t *tokenizer.TokenReader) (*class.Instance, error) { +func parseCons(t *tokenizer.Tokenizer) (*class.Instance, error) { car, err := Parse(t) if err == errEOP { return class.Null.New(nil), nil @@ -142,8 +142,8 @@ func parseCons(t *tokenizer.TokenReader) (*class.Instance, error) { } // Parse builds a internal expression from tokens -func Parse(t *tokenizer.TokenReader) (*class.Instance, error) { - tok, err := t.ReadToken() +func Parse(t *tokenizer.Tokenizer) (*class.Instance, error) { + tok, err := t.Next() if err != nil { return nil, err } diff --git a/reader/tokenizer/tokenizer.go b/reader/tokenizer/tokenizer.go index 7780ed7..a145fed 100644 --- a/reader/tokenizer/tokenizer.go +++ b/reader/tokenizer/tokenizer.go @@ -6,11 +6,11 @@ import ( "strings" ) -// TokenReader interface type is the interface +// Tokenizer interface type is the interface // for reading string with every token // Reader is like bufio.Reader but has PeekRune // which returns a rune without advancing pointer -type TokenReader struct { +type Tokenizer struct { err error ru rune sz int @@ -18,20 +18,20 @@ type TokenReader struct { } // New creates interal reader from io.RuneReader -func New(r io.RuneReader) *TokenReader { - b := new(TokenReader) +func New(r io.RuneReader) *Tokenizer { + b := new(Tokenizer) b.rr = r b.ru, b.sz, b.err = r.ReadRune() return b } // PeekRune returns a rune without advancing pointer -func (r *TokenReader) PeekRune() (rune, int, error) { +func (r *Tokenizer) PeekRune() (rune, int, error) { return r.ru, r.sz, r.err } // ReadRune returns a rune with advancing pointer -func (r *TokenReader) ReadRune() (rune, int, error) { +func (r *Tokenizer) ReadRune() (rune, int, error) { ru := r.ru sz := r.sz err := r.err @@ -60,8 +60,8 @@ var token = concatMatcher( symbol, parentheses) -// ReadToken returns error or string as token -func (r *TokenReader) ReadToken() (string, error) { +// Next returns error or string as token +func (r *Tokenizer) Next() (string, error) { buf := "" for { if buf == "" { diff --git a/reader/tokenizer/tokenizer_test.go b/reader/tokenizer/tokenizer_test.go index 5e21b5a..4c41a39 100644 --- a/reader/tokenizer/tokenizer_test.go +++ b/reader/tokenizer/tokenizer_test.go @@ -28,13 +28,13 @@ func TestReader_ReadToken(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - r := &Reader{ + r := &Tokenizer{ err: tt.fields.err, ru: tt.fields.ru, sz: tt.fields.sz, rr: tt.fields.rr, } - got, err := r.ReadToken() + got, err := r.Next() if (err != nil) != tt.wantErr { t.Errorf("Reader.ReadToken() error = %v, wantErr %v", err, tt.wantErr) return From 901926eed556d0858fb765f186d6b95792049a1a Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Fri, 28 Jul 2017 18:35:05 +0900 Subject: [PATCH 050/228] added evalFunction --- core/eval.go | 121 +++++++++++++++++++++++++-------------------------- 1 file changed, 59 insertions(+), 62 deletions(-) diff --git a/core/eval.go b/core/eval.go index 72f3470..41fca14 100644 --- a/core/eval.go +++ b/core/eval.go @@ -10,7 +10,7 @@ import ( env "github.com/ta2gch/gazelle/core/environment" ) -func evalArgs(args *class.Instance, local *env.Environment, dynamic *env.Environment, global *env.Environment) (*class.Instance, error) { +func evalArguments(args *class.Instance, local *env.Environment, dynamic *env.Environment, global *env.Environment) (*class.Instance, error) { if args.Class() == class.Null { return class.Null.New(nil), nil } @@ -26,13 +26,68 @@ func evalArgs(args *class.Instance, local *env.Environment, dynamic *env.Environ if err != nil { return nil, err } - b, err := evalArgs(cdr, local, dynamic, global) + b, err := evalArguments(cdr, local, dynamic, global) if err != nil { return nil, err } return cons.New(a, b), nil } +func evalFunction(obj *class.Instance, local *env.Environment, dynamic *env.Environment, global *env.Environment) (*class.Instance, error) { + // get function symbol + car, err := cons.Car(obj) + if err != nil { + return nil, err + } + if car.Class() != class.Symbol { + return nil, fmt.Errorf("%v is not a symbol", obj.Value()) + } + // get function arguments + cdr, err := cons.Cdr(obj) + if err != nil { + return nil, err + } + // get function instance has value of Function interface + var fun *class.Instance + if f, ok := local.Function[car.Value().(string)]; ok { + fun = f + } + if f, ok := global.Function[car.Value().(string)]; ok { + fun = f + } + if fun == nil { + return nil, fmt.Errorf("%v is not defined", obj.Value()) + } + // evaluate each arguments + a, err := evalArguments(cdr, local, dynamic, global) + if err != nil { + return nil, err + } + // keep what dynamic envrionment has. + ks := []string{} + for k := range dynamic.Variable { + ks = append(ks, k) + } + // apply function to arguments + r, err := function.Apply(fun, a, env.New(), dynamic, global) + if err != nil { + return nil, err + } + // remove dynamic variables defined by function called in this time + for k := range dynamic.Variable { + v := true + for _, l := range ks { + if k == l { + v = false + } + } + if v { + delete(dynamic.Variable, k) + } + } + return r, nil +} + // Eval evaluates any classs func Eval(obj *class.Instance, local *env.Environment, dynamic *env.Environment, global *env.Environment) (*class.Instance, error) { if obj.Class() == class.Null { @@ -48,69 +103,11 @@ func Eval(obj *class.Instance, local *env.Environment, dynamic *env.Environment, } return nil, fmt.Errorf("%v is not defined", obj.Value()) case class.List: - car, err := cons.Car(obj) + ret, err := evalFunction(obj, local, dynamic, global) if err != nil { return nil, err } - cdr, err := cons.Cdr(obj) - if err != nil { - return nil, err - } - if car.Class() != class.Symbol { - return nil, fmt.Errorf("%v is not a symbol", obj.Value()) - } - if f, ok := local.Function[car.Value().(string)]; ok { - a, err := evalArgs(cdr, local, dynamic, global) - if err != nil { - return nil, err - } - ks := []string{} - for k := range dynamic.Variable { - ks = append(ks, k) - } - r, err := function.Apply(f, a, env.New(), dynamic, global) - if err != nil { - return nil, err - } - for k := range dynamic.Variable { - v := true - for _, l := range ks { - if k == l { - v = false - } - } - if v { - delete(dynamic.Variable, k) - } - } - return r, nil - } - if f, ok := global.Function[car.Value().(string)]; ok { - a, err := evalArgs(cdr, local, dynamic, global) - if err != nil { - return nil, err - } - ks := []string{} - for k := range dynamic.Variable { - ks = append(ks, k) - } - r, err := function.Apply(f, a, env.New(), dynamic, global) - if err != nil { - return nil, err - } - for k := range dynamic.Variable { - v := true - for _, l := range ks { - if k == l { - v = false - } - } - if v { - delete(dynamic.Variable, k) - } - } - return r, nil - } + return ret, nil case class.Integer, class.Float, class.Character, class.String: return obj, nil } From 20b3d7a27e0c097cdb56c4ce494cad7c488f2d4e Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Fri, 28 Jul 2017 20:35:21 +0900 Subject: [PATCH 051/228] Changed dynamic variables environment --- core/class/function/function.go | 14 +++++----- core/environment/environment.go | 14 +++++----- core/eval.go | 45 +++++++++++---------------------- core/eval_test.go | 16 +++++------- 4 files changed, 37 insertions(+), 52 deletions(-) diff --git a/core/class/function/function.go b/core/class/function/function.go index 9ce79f2..5259577 100644 --- a/core/class/function/function.go +++ b/core/class/function/function.go @@ -8,14 +8,14 @@ import ( ) type Function interface { - apply(args *class.Instance, local *env.Environment, dynamic *env.Environment, global *env.Environment) (*class.Instance, error) + apply(args *class.Instance, local *env.Environment, global *env.Environment) (*class.Instance, error) } -func Apply(fun *class.Instance, args *class.Instance, local *env.Environment, dynamic *env.Environment, global *env.Environment) (*class.Instance, error) { +func Apply(fun *class.Instance, args *class.Instance, local *env.Environment, global *env.Environment) (*class.Instance, error) { if fun.Class() != class.Function { return nil, fmt.Errorf("%v is not ", fun.Class().ToString()) } - obj, err := fun.Value().(Function).apply(args, local, dynamic, global) + obj, err := fun.Value().(Function).apply(args, local, global) if err != nil { return nil, err } @@ -23,18 +23,18 @@ func Apply(fun *class.Instance, args *class.Instance, local *env.Environment, dy } type NativeFunction struct { - fun func(*class.Instance, *env.Environment, *env.Environment, *env.Environment) (*class.Instance, error) + fun func(*class.Instance, *env.Environment, *env.Environment) (*class.Instance, error) } -func (f NativeFunction) apply(args *class.Instance, local *env.Environment, dynamic *env.Environment, global *env.Environment) (*class.Instance, error) { - obj, err := f.fun(args, local, global, global) +func (f NativeFunction) apply(args *class.Instance, local *env.Environment, global *env.Environment) (*class.Instance, error) { + obj, err := f.fun(args, local, global) if err != nil { return nil, err } return obj, nil } -func New(fun func(*class.Instance, *env.Environment, *env.Environment, *env.Environment) (*class.Instance, error)) *class.Instance { +func New(fun func(*class.Instance, *env.Environment, *env.Environment) (*class.Instance, error)) *class.Instance { return class.Function.New(&NativeFunction{fun}) } diff --git a/core/environment/environment.go b/core/environment/environment.go index db89c9a..a7ca628 100644 --- a/core/environment/environment.go +++ b/core/environment/environment.go @@ -6,17 +6,19 @@ import ( // Environment struct is the struct for keeping functions and variables type Environment struct { - Macro map[string]*class.Instance - Function map[string]*class.Instance - Variable map[string]*class.Instance + Macro map[interface{}]*class.Instance + Function map[interface{}]*class.Instance + Variable map[interface{}]*class.Instance + DynamicVariable map[interface{}]*class.Instance } // New creates new environment func New() *Environment { env := new(Environment) - env.Macro = map[string]*class.Instance{} - env.Function = map[string]*class.Instance{} - env.Variable = map[string]*class.Instance{} + env.Macro = map[interface{}]*class.Instance{} + env.Function = map[interface{}]*class.Instance{} + env.Variable = map[interface{}]*class.Instance{} + env.DynamicVariable = map[interface{}]*class.Instance{} return env } diff --git a/core/eval.go b/core/eval.go index 41fca14..70d0e23 100644 --- a/core/eval.go +++ b/core/eval.go @@ -10,7 +10,7 @@ import ( env "github.com/ta2gch/gazelle/core/environment" ) -func evalArguments(args *class.Instance, local *env.Environment, dynamic *env.Environment, global *env.Environment) (*class.Instance, error) { +func evalArguments(args *class.Instance, local *env.Environment, global *env.Environment) (*class.Instance, error) { if args.Class() == class.Null { return class.Null.New(nil), nil } @@ -22,18 +22,18 @@ func evalArguments(args *class.Instance, local *env.Environment, dynamic *env.En if err != nil { return nil, err } - a, err := Eval(car, local, dynamic, global) + a, err := Eval(car, local, global) if err != nil { return nil, err } - b, err := evalArguments(cdr, local, dynamic, global) + b, err := evalArguments(cdr, local, global) if err != nil { return nil, err } return cons.New(a, b), nil } -func evalFunction(obj *class.Instance, local *env.Environment, dynamic *env.Environment, global *env.Environment) (*class.Instance, error) { +func evalFunction(obj *class.Instance, local *env.Environment, global *env.Environment) (*class.Instance, error) { // get function symbol car, err := cons.Car(obj) if err != nil { @@ -49,61 +49,46 @@ func evalFunction(obj *class.Instance, local *env.Environment, dynamic *env.Envi } // get function instance has value of Function interface var fun *class.Instance - if f, ok := local.Function[car.Value().(string)]; ok { + if f, ok := local.Function[car.Value()]; ok { fun = f } - if f, ok := global.Function[car.Value().(string)]; ok { + if f, ok := global.Function[car.Value()]; ok { fun = f } if fun == nil { return nil, fmt.Errorf("%v is not defined", obj.Value()) } // evaluate each arguments - a, err := evalArguments(cdr, local, dynamic, global) + a, err := evalArguments(cdr, local, global) if err != nil { return nil, err } - // keep what dynamic envrionment has. - ks := []string{} - for k := range dynamic.Variable { - ks = append(ks, k) - } // apply function to arguments - r, err := function.Apply(fun, a, env.New(), dynamic, global) + e := env.New() + e.DynamicVariable = local.DynamicVariable + r, err := function.Apply(fun, a, env.New(), global) if err != nil { return nil, err } - // remove dynamic variables defined by function called in this time - for k := range dynamic.Variable { - v := true - for _, l := range ks { - if k == l { - v = false - } - } - if v { - delete(dynamic.Variable, k) - } - } return r, nil } // Eval evaluates any classs -func Eval(obj *class.Instance, local *env.Environment, dynamic *env.Environment, global *env.Environment) (*class.Instance, error) { +func Eval(obj *class.Instance, local *env.Environment, global *env.Environment) (*class.Instance, error) { if obj.Class() == class.Null { return class.Null.New(nil), nil } switch obj.Class() { case class.Symbol: - if val, ok := local.Variable[obj.Value().(string)]; ok { + if val, ok := local.Variable[obj.Value()]; ok { return val, nil } - if val, ok := global.Variable[obj.Value().(string)]; ok { + if val, ok := global.Variable[obj.Value()]; ok { return val, nil } return nil, fmt.Errorf("%v is not defined", obj.Value()) - case class.List: - ret, err := evalFunction(obj, local, dynamic, global) + case class.List: // obj is a form or a macro + ret, err := evalFunction(obj, local, global) if err != nil { return nil, err } diff --git a/core/eval_test.go b/core/eval_test.go index 93f8c6b..3129d64 100644 --- a/core/eval_test.go +++ b/core/eval_test.go @@ -20,18 +20,16 @@ func read(s string) *class.Instance { func TestEval(t *testing.T) { local := env.New() - dynamic := env.New() global := env.New() local.Variable["pi"] = class.Float.New(3.14) - local.Function["inc"] = function.New(func(args *class.Instance, local *env.Environment, dynamic *env.Environment, global *env.Environment) (*class.Instance, error) { + local.Function["inc"] = function.New(func(args *class.Instance, local *env.Environment, global *env.Environment) (*class.Instance, error) { car, _ := cons.Car(args) return class.Integer.New(car.Value().(int) + 1), nil }) type args struct { - obj *class.Instance - local *env.Environment - dynamic *env.Environment - global *env.Environment + obj *class.Instance + local *env.Environment + global *env.Environment } tests := []struct { name string @@ -41,20 +39,20 @@ func TestEval(t *testing.T) { }{ { name: "local variable", - args: args{class.Symbol.New("pi"), local, dynamic, global}, + args: args{class.Symbol.New("pi"), local, global}, want: class.Float.New(3.14), wantErr: false, }, { name: "local function", - args: args{read("(inc (inc 1))"), local, dynamic, global}, + args: args{read("(inc (inc 1))"), local, global}, want: class.Integer.New(3), wantErr: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := Eval(tt.args.obj, tt.args.local, tt.args.dynamic, tt.args.global) + got, err := Eval(tt.args.obj, tt.args.local, tt.args.global) if (err != nil) != tt.wantErr { t.Errorf("Eval() error = %v, wantErr %v", err, tt.wantErr) return From 86602db10b51eb30f658a01c02eba8c71d012721 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Fri, 28 Jul 2017 21:18:05 +0900 Subject: [PATCH 052/228] Added Macro --- core/class/instance.go | 6 +++-- core/environment/environment.go | 16 +++++------ core/eval.go | 47 ++++++++++++++++++++++----------- core/eval_test.go | 9 +++++++ 4 files changed, 52 insertions(+), 26 deletions(-) diff --git a/core/class/instance.go b/core/class/instance.go index f402301..1017dfd 100644 --- a/core/class/instance.go +++ b/core/class/instance.go @@ -1,16 +1,18 @@ package class +type Value interface{} + // Instance struct type is the struct for the internal representations type Instance struct { class *Class - value interface{} + value Value } func (i *Instance) Class() *Class { return i.class } -func (i *Instance) Value() interface{} { +func (i *Instance) Value() Value { if i.Class() == Null { return nil } diff --git a/core/environment/environment.go b/core/environment/environment.go index a7ca628..1f87671 100644 --- a/core/environment/environment.go +++ b/core/environment/environment.go @@ -6,19 +6,19 @@ import ( // Environment struct is the struct for keeping functions and variables type Environment struct { - Macro map[interface{}]*class.Instance - Function map[interface{}]*class.Instance - Variable map[interface{}]*class.Instance - DynamicVariable map[interface{}]*class.Instance + Macro map[class.Value]*class.Instance + Function map[class.Value]*class.Instance + Variable map[class.Value]*class.Instance + DynamicVariable map[class.Value]*class.Instance } // New creates new environment func New() *Environment { env := new(Environment) - env.Macro = map[interface{}]*class.Instance{} - env.Function = map[interface{}]*class.Instance{} - env.Variable = map[interface{}]*class.Instance{} - env.DynamicVariable = map[interface{}]*class.Instance{} + env.Macro = map[class.Value]*class.Instance{} + env.Function = map[class.Value]*class.Instance{} + env.Variable = map[class.Value]*class.Instance{} + env.DynamicVariable = map[class.Value]*class.Instance{} return env } diff --git a/core/eval.go b/core/eval.go index 70d0e23..5790ea3 100644 --- a/core/eval.go +++ b/core/eval.go @@ -43,10 +43,29 @@ func evalFunction(obj *class.Instance, local *env.Environment, global *env.Envir return nil, fmt.Errorf("%v is not a symbol", obj.Value()) } // get function arguments - cdr, err := cons.Cdr(obj) + args, err := cons.Cdr(obj) if err != nil { return nil, err } + // get macro instance has value of Function interface + var mac *class.Instance + if m, ok := local.Macro[car.Value()]; ok { + mac = m + } + if m, ok := global.Macro[car.Value()]; ok { + mac = m + } + if mac != nil { + ret, err := function.Apply(mac, args, local, global) + if err != nil { + return nil, err + } + ret, err = Eval(ret, local, global) + if err != nil { + return nil, err + } + return ret, nil + } // get function instance has value of Function interface var fun *class.Instance if f, ok := local.Function[car.Value()]; ok { @@ -55,22 +74,18 @@ func evalFunction(obj *class.Instance, local *env.Environment, global *env.Envir if f, ok := global.Function[car.Value()]; ok { fun = f } - if fun == nil { - return nil, fmt.Errorf("%v is not defined", obj.Value()) - } - // evaluate each arguments - a, err := evalArguments(cdr, local, global) - if err != nil { - return nil, err - } - // apply function to arguments - e := env.New() - e.DynamicVariable = local.DynamicVariable - r, err := function.Apply(fun, a, env.New(), global) - if err != nil { - return nil, err + if fun != nil { + a, err := evalArguments(args, local, global) + if err != nil { + return nil, err + } + r, err := function.Apply(fun, a, local, global) + if err != nil { + return nil, err + } + return r, nil } - return r, nil + return nil, fmt.Errorf("%v is not defined", obj.Value()) } // Eval evaluates any classs diff --git a/core/eval_test.go b/core/eval_test.go index 3129d64..13a237b 100644 --- a/core/eval_test.go +++ b/core/eval_test.go @@ -26,6 +26,9 @@ func TestEval(t *testing.T) { car, _ := cons.Car(args) return class.Integer.New(car.Value().(int) + 1), nil }) + local.Macro["minc"] = function.New(func(args *class.Instance, local *env.Environment, global *env.Environment) (*class.Instance, error) { + return cons.New(class.Symbol.New("inc"), args), nil + }) type args struct { obj *class.Instance local *env.Environment @@ -49,6 +52,12 @@ func TestEval(t *testing.T) { want: class.Integer.New(3), wantErr: false, }, + { + name: "local macro", + args: args{read("(minc (minc 1))"), local, global}, + want: class.Integer.New(3), + wantErr: false, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { From 4dc2c74b99b5c826952b3c7e8dcb2d6d1e547b1b Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Fri, 28 Jul 2017 22:10:05 +0900 Subject: [PATCH 053/228] Changed macro system --- core/eval.go | 4 ---- core/eval_test.go | 3 ++- reader/parser/parser.go | 6 +++--- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/core/eval.go b/core/eval.go index 5790ea3..c752526 100644 --- a/core/eval.go +++ b/core/eval.go @@ -60,10 +60,6 @@ func evalFunction(obj *class.Instance, local *env.Environment, global *env.Envir if err != nil { return nil, err } - ret, err = Eval(ret, local, global) - if err != nil { - return nil, err - } return ret, nil } // get function instance has value of Function interface diff --git a/core/eval_test.go b/core/eval_test.go index 13a237b..a8ae7a6 100644 --- a/core/eval_test.go +++ b/core/eval_test.go @@ -27,7 +27,8 @@ func TestEval(t *testing.T) { return class.Integer.New(car.Value().(int) + 1), nil }) local.Macro["minc"] = function.New(func(args *class.Instance, local *env.Environment, global *env.Environment) (*class.Instance, error) { - return cons.New(class.Symbol.New("inc"), args), nil + ret, _ := Eval(cons.New(class.Symbol.New("inc"), args), local, global) + return ret, nil }) type args struct { obj *class.Instance diff --git a/reader/parser/parser.go b/reader/parser/parser.go index ba679b8..5f90bcb 100644 --- a/reader/parser/parser.go +++ b/reader/parser/parser.go @@ -94,14 +94,14 @@ func parseMacro(tok string, t *tokenizer.Tokenizer) (*class.Instance, error) { i := strings.IndexRune(strings.ToLower(tok), 'a') if i == 1 { d := class.Integer.New(1) - return cons.New(s, cons.New(d, cons.New(cdr, nil))), nil + return cons.New(s, cons.New(d, cons.New(cdr, class.Null.New(nil)))), nil } v, err := strconv.ParseInt(tok[1:i], 10, 32) if err != nil { return nil, err } d := class.Integer.New(int(v)) - return cons.New(s, cons.New(d, cons.New(cdr, nil))), nil + return cons.New(s, cons.New(d, cons.New(cdr, class.Null.New(nil)))), nil } switch tok { case ",@": @@ -114,7 +114,7 @@ func parseMacro(tok string, t *tokenizer.Tokenizer) (*class.Instance, error) { n = "backquote" } m := class.Symbol.New(n) - return cons.New(m, cons.New(cdr, nil)), nil + return cons.New(m, cons.New(cdr, class.Null.New(nil))), nil } func parseCons(t *tokenizer.Tokenizer) (*class.Instance, error) { car, err := Parse(t) From 62d9ab567c70181f29a1fa4125c65fc49a46fdcc Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Sat, 29 Jul 2017 07:13:02 +0900 Subject: [PATCH 054/228] Dynamic variables deep binding --- core/environment/environment.go | 4 ++-- core/eval.go | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/core/environment/environment.go b/core/environment/environment.go index 1f87671..56dab2c 100644 --- a/core/environment/environment.go +++ b/core/environment/environment.go @@ -9,7 +9,7 @@ type Environment struct { Macro map[class.Value]*class.Instance Function map[class.Value]*class.Instance Variable map[class.Value]*class.Instance - DynamicVariable map[class.Value]*class.Instance + DynamicVariable []map[class.Value]*class.Instance // deep biding } // New creates new environment @@ -18,7 +18,7 @@ func New() *Environment { env.Macro = map[class.Value]*class.Instance{} env.Function = map[class.Value]*class.Instance{} env.Variable = map[class.Value]*class.Instance{} - env.DynamicVariable = map[class.Value]*class.Instance{} + env.DynamicVariable = []map[class.Value]*class.Instance{map[class.Value]*class.Instance{}} return env } diff --git a/core/eval.go b/core/eval.go index c752526..d47c7fd 100644 --- a/core/eval.go +++ b/core/eval.go @@ -75,7 +75,9 @@ func evalFunction(obj *class.Instance, local *env.Environment, global *env.Envir if err != nil { return nil, err } - r, err := function.Apply(fun, a, local, global) + env := env.New() + env.DynamicVariable = append(local.DynamicVariable, env.DynamicVariable...) + r, err := function.Apply(fun, a, env, global) if err != nil { return nil, err } From 059a1b5e9a3c955c71b69482a0dcf758cb69da87 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Sat, 29 Jul 2017 17:58:18 +0900 Subject: [PATCH 055/228] Added lambda expression --- core/class/cons/cons.go | 3 - core/class/function/function.go | 20 +------ core/class/function/native.go | 22 +++++++ core/environment/environment.go | 103 +++++++++++++++++++++++++++++--- core/eval.go | 46 +++++++++----- core/eval_test.go | 21 +++++-- core/lambda.go | 59 ++++++++++++++++++ 7 files changed, 226 insertions(+), 48 deletions(-) create mode 100644 core/class/function/native.go create mode 100644 core/lambda.go diff --git a/core/class/cons/cons.go b/core/class/cons/cons.go index 2a69dec..4079b9f 100644 --- a/core/class/cons/cons.go +++ b/core/class/cons/cons.go @@ -13,9 +13,6 @@ type Cell struct { } func New(car *class.Instance, cdr *class.Instance) *class.Instance { - if cdr.Class() == class.Null || cdr.Class() == class.List { - return class.List.New(&Cell{car, cdr}) - } return class.Cons.New(&Cell{car, cdr}) } diff --git a/core/class/function/function.go b/core/class/function/function.go index 5259577..0ba2cf4 100644 --- a/core/class/function/function.go +++ b/core/class/function/function.go @@ -8,36 +8,20 @@ import ( ) type Function interface { - apply(args *class.Instance, local *env.Environment, global *env.Environment) (*class.Instance, error) + Apply(args *class.Instance, local *env.Environment, global *env.Environment) (*class.Instance, error) } func Apply(fun *class.Instance, args *class.Instance, local *env.Environment, global *env.Environment) (*class.Instance, error) { if fun.Class() != class.Function { return nil, fmt.Errorf("%v is not ", fun.Class().ToString()) } - obj, err := fun.Value().(Function).apply(args, local, global) + obj, err := fun.Value().(Function).Apply(args, local, global) if err != nil { return nil, err } return obj, nil } -type NativeFunction struct { - fun func(*class.Instance, *env.Environment, *env.Environment) (*class.Instance, error) -} - -func (f NativeFunction) apply(args *class.Instance, local *env.Environment, global *env.Environment) (*class.Instance, error) { - obj, err := f.fun(args, local, global) - if err != nil { - return nil, err - } - return obj, nil -} - -func New(fun func(*class.Instance, *env.Environment, *env.Environment) (*class.Instance, error)) *class.Instance { - return class.Function.New(&NativeFunction{fun}) -} - type DefaultFunction struct { args *class.Instance body *class.Instance diff --git a/core/class/function/native.go b/core/class/function/native.go new file mode 100644 index 0000000..ea06da2 --- /dev/null +++ b/core/class/function/native.go @@ -0,0 +1,22 @@ +package function + +import ( + "github.com/ta2gch/gazelle/core/class" + env "github.com/ta2gch/gazelle/core/environment" +) + +type NativeFunction struct { + fun func(*class.Instance, *env.Environment, *env.Environment) (*class.Instance, error) +} + +func (f NativeFunction) Apply(args *class.Instance, local *env.Environment, global *env.Environment) (*class.Instance, error) { + obj, err := f.fun(args, local, global) + if err != nil { + return nil, err + } + return obj, nil +} + +func New(fun func(*class.Instance, *env.Environment, *env.Environment) (*class.Instance, error)) *class.Instance { + return class.Function.New(&NativeFunction{fun}) +} diff --git a/core/environment/environment.go b/core/environment/environment.go index 56dab2c..0713fd8 100644 --- a/core/environment/environment.go +++ b/core/environment/environment.go @@ -6,21 +6,108 @@ import ( // Environment struct is the struct for keeping functions and variables type Environment struct { - Macro map[class.Value]*class.Instance - Function map[class.Value]*class.Instance - Variable map[class.Value]*class.Instance - DynamicVariable []map[class.Value]*class.Instance // deep biding + Macro []map[class.Instance]*class.Instance + Function []map[class.Instance]*class.Instance + Variable []map[class.Instance]*class.Instance + DynamicVariable []map[class.Instance]*class.Instance // deep biding } // New creates new environment func New() *Environment { env := new(Environment) - env.Macro = map[class.Value]*class.Instance{} - env.Function = map[class.Value]*class.Instance{} - env.Variable = map[class.Value]*class.Instance{} - env.DynamicVariable = []map[class.Value]*class.Instance{map[class.Value]*class.Instance{}} + env.Macro = []map[class.Instance]*class.Instance{map[class.Instance]*class.Instance{}} + env.Function = []map[class.Instance]*class.Instance{map[class.Instance]*class.Instance{}} + env.Variable = []map[class.Instance]*class.Instance{map[class.Instance]*class.Instance{}} + env.DynamicVariable = []map[class.Instance]*class.Instance{map[class.Instance]*class.Instance{}} return env } +func (e *Environment) MergeDynamicVariable(f *Environment) { + e.DynamicVariable = append(e.DynamicVariable, f.DynamicVariable...) +} + +func (e *Environment) MergeAll(f *Environment) { + e.Variable = append(e.Variable, f.Variable...) + e.Function = append(e.Function, f.Function...) + e.Macro = append(e.Macro, f.Macro...) + e.DynamicVariable = append(e.DynamicVariable, f.DynamicVariable...) +} + +func (e *Environment) GetVariable(key *class.Instance) (*class.Instance, bool) { + for _, vars := range e.Variable { + if v, ok := vars[*key]; ok { + return v, ok + } + } + return nil, false +} + +func (e *Environment) SetVariable(key *class.Instance, value *class.Instance) { + for _, vars := range e.Variable { + if _, ok := vars[*key]; ok { + vars[*key] = value + return + } + } + e.Variable[0][*key] = value +} + +func (e *Environment) GetFunction(key *class.Instance) (*class.Instance, bool) { + for _, vars := range e.Function { + if v, ok := vars[*key]; ok { + return v, ok + } + } + return nil, false +} + +func (e *Environment) SetFunction(key *class.Instance, value *class.Instance) { + for _, vars := range e.Function { + if _, ok := vars[*key]; ok { + vars[*key] = value + return + } + } + e.Function[0][*key] = value +} + +func (e *Environment) GetMacro(key *class.Instance) (*class.Instance, bool) { + for _, vars := range e.Macro { + if v, ok := vars[*key]; ok { + return v, ok + } + } + return nil, false +} + +func (e *Environment) SetMacro(key *class.Instance, value *class.Instance) { + for _, vars := range e.Macro { + if _, ok := vars[*key]; ok { + vars[*key] = value + return + } + } + e.Macro[0][*key] = value +} + +func (e *Environment) GetDynamicVariable(key *class.Instance) (*class.Instance, bool) { + for _, vars := range e.DynamicVariable { + if v, ok := vars[*key]; ok { + return v, ok + } + } + return nil, false +} + +func (e *Environment) SetDynamicVariable(key *class.Instance, value *class.Instance) { + for _, vars := range e.DynamicVariable { + if _, ok := vars[*key]; ok { + vars[*key] = value + return + } + } + e.DynamicVariable[0][*key] = value +} + // TopLevel is a global environment var TopLevel = New() diff --git a/core/eval.go b/core/eval.go index d47c7fd..d60b8dc 100644 --- a/core/eval.go +++ b/core/eval.go @@ -39,24 +39,42 @@ func evalFunction(obj *class.Instance, local *env.Environment, global *env.Envir if err != nil { return nil, err } - if car.Class() != class.Symbol { - return nil, fmt.Errorf("%v is not a symbol", obj.Value()) - } // get function arguments - args, err := cons.Cdr(obj) + cdr, err := cons.Cdr(obj) if err != nil { return nil, err } + // eval if lambda form + if car.Class() == class.Cons { + caar, err := cons.Car(car) + if err != nil { + return nil, err + } + if *caar == *class.Symbol.New("lambda") { + fun, err := Eval(car, local, global) + if err != nil { + return nil, err + } + ret, err := function.Apply(fun, cdr, local, global) + if err != nil { + return nil, err + } + return ret, nil + } + } + if car.Class() != class.Symbol { + return nil, fmt.Errorf("%v is not a symbol", obj.Value()) + } // get macro instance has value of Function interface var mac *class.Instance - if m, ok := local.Macro[car.Value()]; ok { + if m, ok := local.GetMacro(car); ok { mac = m } - if m, ok := global.Macro[car.Value()]; ok { + if m, ok := global.GetMacro(car); ok { mac = m } if mac != nil { - ret, err := function.Apply(mac, args, local, global) + ret, err := function.Apply(mac, cdr, local, global) if err != nil { return nil, err } @@ -64,19 +82,19 @@ func evalFunction(obj *class.Instance, local *env.Environment, global *env.Envir } // get function instance has value of Function interface var fun *class.Instance - if f, ok := local.Function[car.Value()]; ok { + if f, ok := local.GetFunction(car); ok { fun = f } - if f, ok := global.Function[car.Value()]; ok { + if f, ok := global.GetFunction(car); ok { fun = f } if fun != nil { - a, err := evalArguments(args, local, global) + a, err := evalArguments(cdr, local, global) if err != nil { return nil, err } env := env.New() - env.DynamicVariable = append(local.DynamicVariable, env.DynamicVariable...) + env.MergeDynamicVariable(local) r, err := function.Apply(fun, a, env, global) if err != nil { return nil, err @@ -93,14 +111,14 @@ func Eval(obj *class.Instance, local *env.Environment, global *env.Environment) } switch obj.Class() { case class.Symbol: - if val, ok := local.Variable[obj.Value()]; ok { + if val, ok := local.GetVariable(obj); ok { return val, nil } - if val, ok := global.Variable[obj.Value()]; ok { + if val, ok := global.GetVariable(obj); ok { return val, nil } return nil, fmt.Errorf("%v is not defined", obj.Value()) - case class.List: // obj is a form or a macro + case class.Cons: // obj is a form or a macro ret, err := evalFunction(obj, local, global) if err != nil { return nil, err diff --git a/core/eval_test.go b/core/eval_test.go index a8ae7a6..a27d2f2 100644 --- a/core/eval_test.go +++ b/core/eval_test.go @@ -21,15 +21,20 @@ func read(s string) *class.Instance { func TestEval(t *testing.T) { local := env.New() global := env.New() - local.Variable["pi"] = class.Float.New(3.14) - local.Function["inc"] = function.New(func(args *class.Instance, local *env.Environment, global *env.Environment) (*class.Instance, error) { + local.SetVariable(class.Symbol.New("pi"), class.Float.New(3.14)) + local.SetFunction(class.Symbol.New("inc"), function.New(func(args *class.Instance, local *env.Environment, global *env.Environment) (*class.Instance, error) { car, _ := cons.Car(args) return class.Integer.New(car.Value().(int) + 1), nil - }) - local.Macro["minc"] = function.New(func(args *class.Instance, local *env.Environment, global *env.Environment) (*class.Instance, error) { + })) + local.SetMacro(class.Symbol.New("minc"), function.New(func(args *class.Instance, local *env.Environment, global *env.Environment) (*class.Instance, error) { ret, _ := Eval(cons.New(class.Symbol.New("inc"), args), local, global) return ret, nil - }) + })) + local.SetMacro(class.Symbol.New("lambda"), function.New(func(args *class.Instance, local *env.Environment, global *env.Environment) (*class.Instance, error) { + lambdaList, _ := cons.Car(args) + lambdaBody, _ := cons.Cdr(args) + return Lambda(lambdaList, lambdaBody, local), nil + })) type args struct { obj *class.Instance local *env.Environment @@ -59,6 +64,12 @@ func TestEval(t *testing.T) { want: class.Integer.New(3), wantErr: false, }, + { + name: "lambda", + args: args{read("((lambda (x) (minc x)) 1)"), local, global}, + want: class.Integer.New(2), + wantErr: false, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/core/lambda.go b/core/lambda.go new file mode 100644 index 0000000..1d8d650 --- /dev/null +++ b/core/lambda.go @@ -0,0 +1,59 @@ +package core + +import ( + "github.com/ta2gch/gazelle/core/class" + "github.com/ta2gch/gazelle/core/class/cons" + env "github.com/ta2gch/gazelle/core/environment" +) + +type LambdaFunction struct { + args *class.Instance + body *class.Instance + local *env.Environment +} + +func Lambda(args *class.Instance, body *class.Instance, local *env.Environment) *class.Instance { + return class.Function.New(&LambdaFunction{args, body, local}) +} + +func (f LambdaFunction) Apply(args *class.Instance, local *env.Environment, global *env.Environment) (*class.Instance, error) { + local.MergeAll(f.local) + fargs := f.args + aargs := args + for fargs.Class() != class.Null { + key, err := cons.Car(fargs) + if err != nil { + return nil, err + } + value, err := cons.Car(aargs) + if err != nil { + return nil, err + } + local.SetVariable(key, value) + fargs, err = cons.Cdr(fargs) + if err != nil { + return nil, err + } + aargs, err = cons.Cdr(aargs) + if err != nil { + return nil, err + } + } + body := f.body + var ret *class.Instance + for body.Class() != class.Null { + exp, err := cons.Car(body) + if err != nil { + return nil, err + } + ret, err = Eval(exp, local, global) + if err != nil { + return nil, err + } + body, err = cons.Cdr(body) + if err != nil { + return nil, err + } + } + return ret, nil +} From c72bb7a6e7dd79408b38128643aaef3b78deab23 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Sat, 29 Jul 2017 18:09:19 +0900 Subject: [PATCH 056/228] Renamed function structures --- core/class/function/function.go | 18 ------------------ core/eval_test.go | 13 ++++++------- core/lambda.go | 2 +- core/{class/function => }/native.go | 4 ++-- 4 files changed, 9 insertions(+), 28 deletions(-) rename core/{class/function => }/native.go (77%) diff --git a/core/class/function/function.go b/core/class/function/function.go index 0ba2cf4..3d24b33 100644 --- a/core/class/function/function.go +++ b/core/class/function/function.go @@ -21,21 +21,3 @@ func Apply(fun *class.Instance, args *class.Instance, local *env.Environment, gl } return obj, nil } - -type DefaultFunction struct { - args *class.Instance - body *class.Instance -} - -/* -func (f *DefaultFunction) Apply(args *class.Instance, global *Env) (*class.Instance, error) { - // Assign args to local environment - // Eval each body - // return evaluate result -} -*/ - -type GenericFunction struct { - args *class.Instance - body *class.Instance -} diff --git a/core/eval_test.go b/core/eval_test.go index a27d2f2..db15863 100644 --- a/core/eval_test.go +++ b/core/eval_test.go @@ -7,7 +7,6 @@ import ( "github.com/ta2gch/gazelle/core/class" "github.com/ta2gch/gazelle/core/class/cons" - "github.com/ta2gch/gazelle/core/class/function" env "github.com/ta2gch/gazelle/core/environment" "github.com/ta2gch/gazelle/reader/parser" "github.com/ta2gch/gazelle/reader/tokenizer" @@ -22,18 +21,18 @@ func TestEval(t *testing.T) { local := env.New() global := env.New() local.SetVariable(class.Symbol.New("pi"), class.Float.New(3.14)) - local.SetFunction(class.Symbol.New("inc"), function.New(func(args *class.Instance, local *env.Environment, global *env.Environment) (*class.Instance, error) { + local.SetFunction(class.Symbol.New("inc"), NewNativeFunction(func(args *class.Instance, local *env.Environment, global *env.Environment) (*class.Instance, error) { car, _ := cons.Car(args) return class.Integer.New(car.Value().(int) + 1), nil })) - local.SetMacro(class.Symbol.New("minc"), function.New(func(args *class.Instance, local *env.Environment, global *env.Environment) (*class.Instance, error) { + local.SetMacro(class.Symbol.New("minc"), NewNativeFunction(func(args *class.Instance, local *env.Environment, global *env.Environment) (*class.Instance, error) { ret, _ := Eval(cons.New(class.Symbol.New("inc"), args), local, global) return ret, nil })) - local.SetMacro(class.Symbol.New("lambda"), function.New(func(args *class.Instance, local *env.Environment, global *env.Environment) (*class.Instance, error) { - lambdaList, _ := cons.Car(args) - lambdaBody, _ := cons.Cdr(args) - return Lambda(lambdaList, lambdaBody, local), nil + global.SetMacro(class.Symbol.New("lambda"), NewNativeFunction(func(args *class.Instance, local *env.Environment, global *env.Environment) (*class.Instance, error) { + car, _ := cons.Car(args) + cdr, _ := cons.Cdr(args) + return NewLambdaFunction(car, cdr, local), nil })) type args struct { obj *class.Instance diff --git a/core/lambda.go b/core/lambda.go index 1d8d650..8c1ecc1 100644 --- a/core/lambda.go +++ b/core/lambda.go @@ -12,7 +12,7 @@ type LambdaFunction struct { local *env.Environment } -func Lambda(args *class.Instance, body *class.Instance, local *env.Environment) *class.Instance { +func NewLambdaFunction(args *class.Instance, body *class.Instance, local *env.Environment) *class.Instance { return class.Function.New(&LambdaFunction{args, body, local}) } diff --git a/core/class/function/native.go b/core/native.go similarity index 77% rename from core/class/function/native.go rename to core/native.go index ea06da2..873bda9 100644 --- a/core/class/function/native.go +++ b/core/native.go @@ -1,4 +1,4 @@ -package function +package core import ( "github.com/ta2gch/gazelle/core/class" @@ -17,6 +17,6 @@ func (f NativeFunction) Apply(args *class.Instance, local *env.Environment, glob return obj, nil } -func New(fun func(*class.Instance, *env.Environment, *env.Environment) (*class.Instance, error)) *class.Instance { +func NewNativeFunction(fun func(*class.Instance, *env.Environment, *env.Environment) (*class.Instance, error)) *class.Instance { return class.Function.New(&NativeFunction{fun}) } From 50a391e445d7ea53b6b9acaf1503924cf8d6896c Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Sat, 29 Jul 2017 18:19:06 +0900 Subject: [PATCH 057/228] Eval arguments if lambda --- core/eval.go | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/core/eval.go b/core/eval.go index d60b8dc..7128b98 100644 --- a/core/eval.go +++ b/core/eval.go @@ -55,7 +55,13 @@ func evalFunction(obj *class.Instance, local *env.Environment, global *env.Envir if err != nil { return nil, err } - ret, err := function.Apply(fun, cdr, local, global) + args, err := evalArguments(cdr, local, global) + if err != nil { + return nil, err + } + env := env.New() + env.MergeDynamicVariable(local) + ret, err := function.Apply(fun, args, env, global) if err != nil { return nil, err } @@ -89,17 +95,17 @@ func evalFunction(obj *class.Instance, local *env.Environment, global *env.Envir fun = f } if fun != nil { - a, err := evalArguments(cdr, local, global) + args, err := evalArguments(cdr, local, global) if err != nil { return nil, err } env := env.New() env.MergeDynamicVariable(local) - r, err := function.Apply(fun, a, env, global) + ret, err := function.Apply(fun, args, env, global) if err != nil { return nil, err } - return r, nil + return ret, nil } return nil, fmt.Errorf("%v is not defined", obj.Value()) } From 479f2fe0c14eb5d288808d861530ca00c6dedfe9 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Sat, 29 Jul 2017 18:20:47 +0900 Subject: [PATCH 058/228] Added TravisCI --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..6c6ff55 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,3 @@ +language: go +script: + - go test -v ./... \ No newline at end of file From e8c21b05164f63b864f046931763713559addb5d Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Sat, 29 Jul 2017 18:39:07 +0900 Subject: [PATCH 059/228] Added rest parameter --- core/lambda.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/core/lambda.go b/core/lambda.go index 8c1ecc1..0aa49ac 100644 --- a/core/lambda.go +++ b/core/lambda.go @@ -29,6 +29,18 @@ func (f LambdaFunction) Apply(args *class.Instance, local *env.Environment, glob if err != nil { return nil, err } + if *key == *class.Symbol.New(":rest") || *key == *class.Symbol.New("&rest") { + cdr, err := cons.Cdr(fargs) + if err != nil { + return nil, err + } + caar, err := cons.Car(cdr) + if err != nil { + return nil, err + } + local.SetVariable(caar, aargs) + break + } local.SetVariable(key, value) fargs, err = cons.Cdr(fargs) if err != nil { From ef47ed1a1250f382ee433a74322f04db47782c6c Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Sat, 29 Jul 2017 20:56:12 +0900 Subject: [PATCH 060/228] Added condition system --- core/class/cons/cons.go | 10 ++++------ core/class/function/function.go | 8 +++----- core/eval.go | 17 +++++++---------- core/eval_test.go | 6 +++--- core/lambda.go | 2 +- core/native.go | 6 +++--- reader/parser/parser.go | 29 ++++++++++++++--------------- reader/tokenizer/tokenizer.go | 6 ++++-- 8 files changed, 39 insertions(+), 45 deletions(-) diff --git a/core/class/cons/cons.go b/core/class/cons/cons.go index 4079b9f..a727798 100644 --- a/core/class/cons/cons.go +++ b/core/class/cons/cons.go @@ -1,8 +1,6 @@ package cons import ( - "fmt" - "github.com/ta2gch/gazelle/core/class" ) @@ -16,16 +14,16 @@ func New(car *class.Instance, cdr *class.Instance) *class.Instance { return class.Cons.New(&Cell{car, cdr}) } -func Car(i *class.Instance) (*class.Instance, error) { +func Car(i *class.Instance) (*class.Instance, *class.Instance) { if i.Class() == class.Null || (i.Class() != class.Cons && i.Class() != class.List) { - return nil, fmt.Errorf("%v is not a member of ", i.Class().ToString()) + return nil, class.DomainError.New(nil) } return i.Value().(*Cell).car, nil } -func Cdr(i *class.Instance) (*class.Instance, error) { +func Cdr(i *class.Instance) (*class.Instance, *class.Instance) { if i.Class() == class.Null || (i.Class() != class.Cons && i.Class() != class.List) { - return nil, fmt.Errorf("%v is not a member of ", i.Class().ToString()) + return nil, class.DomainError.New(nil) } return i.Value().(*Cell).cdr, nil } diff --git a/core/class/function/function.go b/core/class/function/function.go index 3d24b33..3a18d9a 100644 --- a/core/class/function/function.go +++ b/core/class/function/function.go @@ -1,19 +1,17 @@ package function import ( - "fmt" - "github.com/ta2gch/gazelle/core/class" env "github.com/ta2gch/gazelle/core/environment" ) type Function interface { - Apply(args *class.Instance, local *env.Environment, global *env.Environment) (*class.Instance, error) + Apply(args *class.Instance, local *env.Environment, global *env.Environment) (*class.Instance, *class.Instance) } -func Apply(fun *class.Instance, args *class.Instance, local *env.Environment, global *env.Environment) (*class.Instance, error) { +func Apply(fun *class.Instance, args *class.Instance, local *env.Environment, global *env.Environment) (*class.Instance, *class.Instance) { if fun.Class() != class.Function { - return nil, fmt.Errorf("%v is not ", fun.Class().ToString()) + return nil, class.DomainError.New(nil) } obj, err := fun.Value().(Function).Apply(args, local, global) if err != nil { diff --git a/core/eval.go b/core/eval.go index 7128b98..9ac9a3b 100644 --- a/core/eval.go +++ b/core/eval.go @@ -1,16 +1,13 @@ package core import ( - "errors" - "fmt" - "github.com/ta2gch/gazelle/core/class" "github.com/ta2gch/gazelle/core/class/cons" "github.com/ta2gch/gazelle/core/class/function" env "github.com/ta2gch/gazelle/core/environment" ) -func evalArguments(args *class.Instance, local *env.Environment, global *env.Environment) (*class.Instance, error) { +func evalArguments(args *class.Instance, local *env.Environment, global *env.Environment) (*class.Instance, *class.Instance) { if args.Class() == class.Null { return class.Null.New(nil), nil } @@ -33,7 +30,7 @@ func evalArguments(args *class.Instance, local *env.Environment, global *env.Env return cons.New(a, b), nil } -func evalFunction(obj *class.Instance, local *env.Environment, global *env.Environment) (*class.Instance, error) { +func evalFunction(obj *class.Instance, local *env.Environment, global *env.Environment) (*class.Instance, *class.Instance) { // get function symbol car, err := cons.Car(obj) if err != nil { @@ -69,7 +66,7 @@ func evalFunction(obj *class.Instance, local *env.Environment, global *env.Envir } } if car.Class() != class.Symbol { - return nil, fmt.Errorf("%v is not a symbol", obj.Value()) + return nil, class.DomainError.New(nil) } // get macro instance has value of Function interface var mac *class.Instance @@ -107,11 +104,11 @@ func evalFunction(obj *class.Instance, local *env.Environment, global *env.Envir } return ret, nil } - return nil, fmt.Errorf("%v is not defined", obj.Value()) + return nil, class.UndefinedFunction.New(nil) } // Eval evaluates any classs -func Eval(obj *class.Instance, local *env.Environment, global *env.Environment) (*class.Instance, error) { +func Eval(obj *class.Instance, local *env.Environment, global *env.Environment) (*class.Instance, *class.Instance) { if obj.Class() == class.Null { return class.Null.New(nil), nil } @@ -123,7 +120,7 @@ func Eval(obj *class.Instance, local *env.Environment, global *env.Environment) if val, ok := global.GetVariable(obj); ok { return val, nil } - return nil, fmt.Errorf("%v is not defined", obj.Value()) + return nil, class.UndefinedVariable.New(nil) case class.Cons: // obj is a form or a macro ret, err := evalFunction(obj, local, global) if err != nil { @@ -133,5 +130,5 @@ func Eval(obj *class.Instance, local *env.Environment, global *env.Environment) case class.Integer, class.Float, class.Character, class.String: return obj, nil } - return nil, errors.New("I have no ideas") + return nil, class.ParseError.New(nil) } diff --git a/core/eval_test.go b/core/eval_test.go index db15863..90994b5 100644 --- a/core/eval_test.go +++ b/core/eval_test.go @@ -21,15 +21,15 @@ func TestEval(t *testing.T) { local := env.New() global := env.New() local.SetVariable(class.Symbol.New("pi"), class.Float.New(3.14)) - local.SetFunction(class.Symbol.New("inc"), NewNativeFunction(func(args *class.Instance, local *env.Environment, global *env.Environment) (*class.Instance, error) { + local.SetFunction(class.Symbol.New("inc"), NewNativeFunction(func(args *class.Instance, local *env.Environment, global *env.Environment) (*class.Instance, *class.Instance) { car, _ := cons.Car(args) return class.Integer.New(car.Value().(int) + 1), nil })) - local.SetMacro(class.Symbol.New("minc"), NewNativeFunction(func(args *class.Instance, local *env.Environment, global *env.Environment) (*class.Instance, error) { + local.SetMacro(class.Symbol.New("minc"), NewNativeFunction(func(args *class.Instance, local *env.Environment, global *env.Environment) (*class.Instance, *class.Instance) { ret, _ := Eval(cons.New(class.Symbol.New("inc"), args), local, global) return ret, nil })) - global.SetMacro(class.Symbol.New("lambda"), NewNativeFunction(func(args *class.Instance, local *env.Environment, global *env.Environment) (*class.Instance, error) { + global.SetMacro(class.Symbol.New("lambda"), NewNativeFunction(func(args *class.Instance, local *env.Environment, global *env.Environment) (*class.Instance, *class.Instance) { car, _ := cons.Car(args) cdr, _ := cons.Cdr(args) return NewLambdaFunction(car, cdr, local), nil diff --git a/core/lambda.go b/core/lambda.go index 0aa49ac..b52ebea 100644 --- a/core/lambda.go +++ b/core/lambda.go @@ -16,7 +16,7 @@ func NewLambdaFunction(args *class.Instance, body *class.Instance, local *env.En return class.Function.New(&LambdaFunction{args, body, local}) } -func (f LambdaFunction) Apply(args *class.Instance, local *env.Environment, global *env.Environment) (*class.Instance, error) { +func (f LambdaFunction) Apply(args *class.Instance, local *env.Environment, global *env.Environment) (*class.Instance, *class.Instance) { local.MergeAll(f.local) fargs := f.args aargs := args diff --git a/core/native.go b/core/native.go index 873bda9..2ed0d03 100644 --- a/core/native.go +++ b/core/native.go @@ -6,10 +6,10 @@ import ( ) type NativeFunction struct { - fun func(*class.Instance, *env.Environment, *env.Environment) (*class.Instance, error) + fun func(*class.Instance, *env.Environment, *env.Environment) (*class.Instance, *class.Instance) } -func (f NativeFunction) Apply(args *class.Instance, local *env.Environment, global *env.Environment) (*class.Instance, error) { +func (f NativeFunction) Apply(args *class.Instance, local *env.Environment, global *env.Environment) (*class.Instance, *class.Instance) { obj, err := f.fun(args, local, global) if err != nil { return nil, err @@ -17,6 +17,6 @@ func (f NativeFunction) Apply(args *class.Instance, local *env.Environment, glob return obj, nil } -func NewNativeFunction(fun func(*class.Instance, *env.Environment, *env.Environment) (*class.Instance, error)) *class.Instance { +func NewNativeFunction(fun func(*class.Instance, *env.Environment, *env.Environment) (*class.Instance, *class.Instance)) *class.Instance { return class.Function.New(&NativeFunction{fun}) } diff --git a/reader/parser/parser.go b/reader/parser/parser.go index 5f90bcb..a9cd590 100644 --- a/reader/parser/parser.go +++ b/reader/parser/parser.go @@ -1,8 +1,6 @@ package parser import ( - "errors" - "fmt" "math" "regexp" "strconv" @@ -13,10 +11,10 @@ import ( "github.com/ta2gch/gazelle/reader/tokenizer" ) -var errEOP = errors.New("End Of Parentheses") -var errBOD = errors.New("Begin Of Dot") +var eop = class.SimpleError.New("End Of Parentheses") +var bod = class.SimpleError.New("Begin Of Dot") -func parseAtom(tok string) (*class.Instance, error) { +func parseAtom(tok string) (*class.Instance, *class.Instance) { // // integer // @@ -81,9 +79,10 @@ func parseAtom(tok string) (*class.Instance, error) { if m, _ := regexp.MatchString("^[<>/*=?_!$%[\\]^{}~a-zA-Z][<>/*=?_!$%[\\]^{}~0-9a-zA-Z]*$", tok); m { return class.Symbol.New(tok), nil } - return nil, fmt.Errorf("Sorry, I could not parse %s", tok) + return nil, class.ParseError.New(nil) } -func parseMacro(tok string, t *tokenizer.Tokenizer) (*class.Instance, error) { + +func parseMacro(tok string, t *tokenizer.Tokenizer) (*class.Instance, *class.Instance) { cdr, err := Parse(t) if err != nil { return nil, err @@ -98,7 +97,7 @@ func parseMacro(tok string, t *tokenizer.Tokenizer) (*class.Instance, error) { } v, err := strconv.ParseInt(tok[1:i], 10, 32) if err != nil { - return nil, err + return nil, class.ParseError.New(nil) } d := class.Integer.New(int(v)) return cons.New(s, cons.New(d, cons.New(cdr, class.Null.New(nil)))), nil @@ -116,17 +115,17 @@ func parseMacro(tok string, t *tokenizer.Tokenizer) (*class.Instance, error) { m := class.Symbol.New(n) return cons.New(m, cons.New(cdr, class.Null.New(nil))), nil } -func parseCons(t *tokenizer.Tokenizer) (*class.Instance, error) { +func parseCons(t *tokenizer.Tokenizer) (*class.Instance, *class.Instance) { car, err := Parse(t) - if err == errEOP { + if err == eop { return class.Null.New(nil), nil } - if err == errBOD { + if err == bod { cdr, err := Parse(t) if err != nil { return nil, err } - if _, err := Parse(t); err != errEOP { + if _, err := Parse(t); err != eop { return nil, err } return cdr, nil @@ -142,7 +141,7 @@ func parseCons(t *tokenizer.Tokenizer) (*class.Instance, error) { } // Parse builds a internal expression from tokens -func Parse(t *tokenizer.Tokenizer) (*class.Instance, error) { +func Parse(t *tokenizer.Tokenizer) (*class.Instance, *class.Instance) { tok, err := t.Next() if err != nil { return nil, err @@ -155,10 +154,10 @@ func Parse(t *tokenizer.Tokenizer) (*class.Instance, error) { return cons, err } if tok == ")" { - return nil, errEOP + return nil, eop } if tok == "." { - return nil, errBOD + return nil, bod } if mat, _ := regexp.MatchString("^(?:,@?|'|`|#[[:digit:]]*[aA])$", tok); mat { m, err := parseMacro(tok, t) diff --git a/reader/tokenizer/tokenizer.go b/reader/tokenizer/tokenizer.go index a145fed..c2cbf12 100644 --- a/reader/tokenizer/tokenizer.go +++ b/reader/tokenizer/tokenizer.go @@ -4,6 +4,8 @@ import ( "io" "regexp" "strings" + + "github.com/ta2gch/gazelle/core/class" ) // Tokenizer interface type is the interface @@ -61,13 +63,13 @@ var token = concatMatcher( parentheses) // Next returns error or string as token -func (r *Tokenizer) Next() (string, error) { +func (r *Tokenizer) Next() (string, *class.Instance) { buf := "" for { if buf == "" { p, _, err := r.PeekRune() if err != nil { - return "", err + return "", class.ParseError.New(nil) } if token.MatchString(string(p)) { buf = string(p) From 17b224a9b6b474ea7a3e9bd2b5f3b7d0ad89add4 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Sun, 30 Jul 2017 13:26:14 +0900 Subject: [PATCH 061/228] class as object --- core/class/class.go | 148 +++++++++++++++--------- core/class/cons/cons.go | 31 +++-- core/class/domain-error/domain-error.go | 10 ++ core/class/function/function.go | 6 +- core/class/instance.go | 15 ++- core/environment/environment.go | 64 +++++----- core/eval.go | 24 ++-- core/eval_test.go | 28 ++--- core/init.go | 27 +++++ core/lambda.go | 31 +++-- core/native.go | 8 +- reader/parser/parser.go | 60 +++++----- reader/parser/parser_test.go | 34 +++--- reader/tokenizer/tokenizer.go | 4 +- 14 files changed, 298 insertions(+), 192 deletions(-) create mode 100644 core/class/domain-error/domain-error.go create mode 100644 core/init.go diff --git a/core/class/class.go b/core/class/class.go index 0ee3e1c..2e47ea3 100644 --- a/core/class/class.go +++ b/core/class/class.go @@ -1,58 +1,100 @@ package class -type Class struct { - Parents []*Class +type Class interface { + ToString() string + Parents() []Class + New(...Value) Instance +} + +func New(c Instance, value ...Value) Instance { + return c.(Class).New(value...) +} + +type MetaClass struct { + name string +} + +func (m *MetaClass) ToString() string { + return m.name +} + +func (*MetaClass) Parents() []Class { + return []Class{Object.Value().(Class)} +} + +func (*MetaClass) Class() Instance { + return Object +} + +func (m *MetaClass) Value() Value { + return m +} + +func (m *MetaClass) New(value ...Value) Instance { + return &builtInClass{[]Class{value[0].(Instance).Value().(Class)}, value[1].(string)} +} + +type builtInClass struct { + parents []Class name string } -func (class *Class) ToString() string { - return class.name -} - -func (class *Class) New(value interface{}) *Instance { - return &Instance{class, value} -} - -func NewClass(parent *Class, name string) *Class { - return &Class{[]*Class{parent}, name} -} - -var Object = &Class{[]*Class{}, ""} -var BasicArray = NewClass(Object, "") -var BasicArrayStar = NewClass(BasicArray, "") -var GeneralArrayStar = NewClass(BasicArrayStar, "") -var BasicVector = NewClass(BasicArray, "") -var GeneraVector = NewClass(BasicVector, "") -var String = NewClass(BasicVector, "") -var BuiltInClass = NewClass(Object, "") -var Character = NewClass(Object, "") -var Function = NewClass(Object, "") -var GenericFunction = NewClass(Function, "") -var StandardGenericFunction = NewClass(GenericFunction, "") -var List = NewClass(Object, "") -var Cons = NewClass(List, "") -var Null = NewClass(List, "") -var Symbol = NewClass(Object, "") -var Number = NewClass(Object, "") -var Integer = NewClass(Number, "") -var Float = NewClass(Number, "") -var SeriousCondition = NewClass(Object, "") -var Error = NewClass(SeriousCondition, "") -var ArithmeticError = NewClass(Error, "") -var DivisionByZero = NewClass(ArithmeticError, "") -var FloatingPointOnderflow = NewClass(ArithmeticError, "") -var FloatingPointUnderflow = NewClass(ArithmeticError, "") -var ControlError = NewClass(Error, "") -var ParseError = NewClass(Error, "") -var ProgramError = NewClass(Error, "") -var DomainError = NewClass(ProgramError, "") -var UndefinedEntity = NewClass(ProgramError, "") -var UndefinedVariable = NewClass(UndefinedEntity, "") -var UndefinedFunction = NewClass(UndefinedEntity, "") -var SimpleError = NewClass(Error, "") -var StreamError = NewClass(Error, "") -var EndOfStream = NewClass(StreamError, "") -var StorageExhausted = NewClass(SeriousCondition, "") -var StandardClass = NewClass(Object, "") -var StandardObject = NewClass(Object, "") -var Stream = NewClass(Object, "") +func (c *builtInClass) ToString() string { + return c.name +} + +func (c *builtInClass) Parents() []Class { + return c.parents +} + +func (c *builtInClass) Class() Instance { + return BuiltInClass +} + +func (c *builtInClass) Value() Value { + return c +} + +func (c *builtInClass) New(value ...Value) Instance { + return &DefaultInstance{c, value[0]} +} + +var Object = &builtInClass{[]Class{}, ""} +var BasicArray = BuiltInClass.New(Object, "") +var BasicArrayStar = BuiltInClass.New(BasicArray, "") +var GeneralArrayStar = BuiltInClass.New(BasicArrayStar, "") +var BasicVector = BuiltInClass.New(BasicArray, "") +var GeneraVector = BuiltInClass.New(BasicVector, "") +var String = BuiltInClass.New(BasicVector, "") +var BuiltInClass = &MetaClass{""} +var Character = BuiltInClass.New(Object, "") +var Function = BuiltInClass.New(Object, "") +var GenericFunction = BuiltInClass.New(Function, "") +var StandardGenericFunction = BuiltInClass.New(GenericFunction, "") +var List = BuiltInClass.New(Object, "") +var Cons = BuiltInClass.New(List, "") +var Null = BuiltInClass.New(List, "") +var Symbol = BuiltInClass.New(Object, "") +var Number = BuiltInClass.New(Object, "") +var Integer = BuiltInClass.New(Number, "") +var Float = BuiltInClass.New(Number, "") +var SeriousCondition = BuiltInClass.New(Object, "") +var Error = BuiltInClass.New(SeriousCondition, "") +var ArithmeticError = BuiltInClass.New(Error, "") +var DivisionByZero = BuiltInClass.New(ArithmeticError, "") +var FloatingPointOnderflow = BuiltInClass.New(ArithmeticError, "") +var FloatingPointUnderflow = BuiltInClass.New(ArithmeticError, "") +var ControlError = BuiltInClass.New(Error, "") +var ParseError = BuiltInClass.New(Error, "") +var ProgramError = BuiltInClass.New(Error, "") +var DomainError = BuiltInClass.New(ProgramError, "") +var UndefinedEntity = BuiltInClass.New(ProgramError, "") +var UndefinedVariable = BuiltInClass.New(UndefinedEntity, "") +var UndefinedFunction = BuiltInClass.New(UndefinedEntity, "") +var SimpleError = BuiltInClass.New(Error, "") +var StreamError = BuiltInClass.New(Error, "") +var EndOfStream = BuiltInClass.New(StreamError, "") +var StorageExhausted = BuiltInClass.New(SeriousCondition, "") +var StandardClass = &MetaClass{""} +var StandardObject = BuiltInClass.New(Object, "") +var Stream = BuiltInClass.New(Object, "") diff --git a/core/class/cons/cons.go b/core/class/cons/cons.go index a727798..b24156c 100644 --- a/core/class/cons/cons.go +++ b/core/class/cons/cons.go @@ -6,24 +6,39 @@ import ( // Cell is a pair of pointers to Object type Cell struct { - car *class.Instance - cdr *class.Instance + car class.Instance + cdr class.Instance } -func New(car *class.Instance, cdr *class.Instance) *class.Instance { - return class.Cons.New(&Cell{car, cdr}) +func New(car class.Instance, cdr class.Instance) class.Instance { + return class.New(class.Cons, &Cell{car, cdr}) } -func Car(i *class.Instance) (*class.Instance, *class.Instance) { +func Car(i class.Instance) (class.Instance, class.Instance) { if i.Class() == class.Null || (i.Class() != class.Cons && i.Class() != class.List) { - return nil, class.DomainError.New(nil) + return nil, class.New(class.DomainError, nil) } return i.Value().(*Cell).car, nil } -func Cdr(i *class.Instance) (*class.Instance, *class.Instance) { +func Cdr(i class.Instance) (class.Instance, class.Instance) { if i.Class() == class.Null || (i.Class() != class.Cons && i.Class() != class.List) { - return nil, class.DomainError.New(nil) + return nil, class.New(class.DomainError, nil) } return i.Value().(*Cell).cdr, nil } + +func Length(list class.Instance) (int, class.Instance) { + if list.Class() == class.Null { + return 0, nil + } + cdr, err := Cdr(list) + if err != nil { + return 0, err + } + len, err := Length(cdr) + if err != nil { + return 0, err + } + return 1 + len, nil +} diff --git a/core/class/domain-error/domain-error.go b/core/class/domain-error/domain-error.go new file mode 100644 index 0000000..248a4d8 --- /dev/null +++ b/core/class/domain-error/domain-error.go @@ -0,0 +1,10 @@ +package domainerror + +import ( + "github.com/ta2gch/gazelle/core/class" +) + +type DomainError struct { + object class.Instance + expectedClass class.Instance +} diff --git a/core/class/function/function.go b/core/class/function/function.go index 3a18d9a..173fec6 100644 --- a/core/class/function/function.go +++ b/core/class/function/function.go @@ -6,12 +6,12 @@ import ( ) type Function interface { - Apply(args *class.Instance, local *env.Environment, global *env.Environment) (*class.Instance, *class.Instance) + Apply(args class.Instance, local *env.Environment, global *env.Environment) (class.Instance, class.Instance) } -func Apply(fun *class.Instance, args *class.Instance, local *env.Environment, global *env.Environment) (*class.Instance, *class.Instance) { +func Apply(fun class.Instance, args class.Instance, local *env.Environment, global *env.Environment) (class.Instance, class.Instance) { if fun.Class() != class.Function { - return nil, class.DomainError.New(nil) + return nil, class.New(class.DomainError, nil) } obj, err := fun.Value().(Function).Apply(args, local, global) if err != nil { diff --git a/core/class/instance.go b/core/class/instance.go index 1017dfd..afd2637 100644 --- a/core/class/instance.go +++ b/core/class/instance.go @@ -3,17 +3,22 @@ package class type Value interface{} // Instance struct type is the struct for the internal representations -type Instance struct { - class *Class +type Instance interface { + Class() Instance + Value() Value +} + +type DefaultInstance struct { + class Instance value Value } -func (i *Instance) Class() *Class { +func (i *DefaultInstance) Class() Instance { return i.class } -func (i *Instance) Value() Value { - if i.Class() == Null { +func (i *DefaultInstance) Value() Value { + if i.Class() == nil { return nil } return i.value diff --git a/core/environment/environment.go b/core/environment/environment.go index 0713fd8..8f401a1 100644 --- a/core/environment/environment.go +++ b/core/environment/environment.go @@ -6,19 +6,19 @@ import ( // Environment struct is the struct for keeping functions and variables type Environment struct { - Macro []map[class.Instance]*class.Instance - Function []map[class.Instance]*class.Instance - Variable []map[class.Instance]*class.Instance - DynamicVariable []map[class.Instance]*class.Instance // deep biding + Macro []map[class.Value]class.Instance + Function []map[class.Value]class.Instance + Variable []map[class.Value]class.Instance + DynamicVariable []map[class.Value]class.Instance // deep biding } // New creates new environment func New() *Environment { env := new(Environment) - env.Macro = []map[class.Instance]*class.Instance{map[class.Instance]*class.Instance{}} - env.Function = []map[class.Instance]*class.Instance{map[class.Instance]*class.Instance{}} - env.Variable = []map[class.Instance]*class.Instance{map[class.Instance]*class.Instance{}} - env.DynamicVariable = []map[class.Instance]*class.Instance{map[class.Instance]*class.Instance{}} + env.Macro = []map[class.Value]class.Instance{map[class.Value]class.Instance{}} + env.Function = []map[class.Value]class.Instance{map[class.Value]class.Instance{}} + env.Variable = []map[class.Value]class.Instance{map[class.Value]class.Instance{}} + env.DynamicVariable = []map[class.Value]class.Instance{map[class.Value]class.Instance{}} return env } @@ -33,80 +33,80 @@ func (e *Environment) MergeAll(f *Environment) { e.DynamicVariable = append(e.DynamicVariable, f.DynamicVariable...) } -func (e *Environment) GetVariable(key *class.Instance) (*class.Instance, bool) { +func (e *Environment) GetVariable(key class.Instance) (class.Instance, bool) { for _, vars := range e.Variable { - if v, ok := vars[*key]; ok { + if v, ok := vars[key.Value()]; ok { return v, ok } } return nil, false } -func (e *Environment) SetVariable(key *class.Instance, value *class.Instance) { +func (e *Environment) SetVariable(key class.Instance, value class.Instance) { for _, vars := range e.Variable { - if _, ok := vars[*key]; ok { - vars[*key] = value + if _, ok := vars[key.Value()]; ok { + vars[key.Value()] = value return } } - e.Variable[0][*key] = value + e.Variable[0][key.Value()] = value } -func (e *Environment) GetFunction(key *class.Instance) (*class.Instance, bool) { +func (e *Environment) GetFunction(key class.Instance) (class.Instance, bool) { for _, vars := range e.Function { - if v, ok := vars[*key]; ok { + if v, ok := vars[key.Value()]; ok { return v, ok } } return nil, false } -func (e *Environment) SetFunction(key *class.Instance, value *class.Instance) { +func (e *Environment) SetFunction(key class.Instance, value class.Instance) { for _, vars := range e.Function { - if _, ok := vars[*key]; ok { - vars[*key] = value + if _, ok := vars[key.Value()]; ok { + vars[key.Value()] = value return } } - e.Function[0][*key] = value + e.Function[0][key.Value()] = value } -func (e *Environment) GetMacro(key *class.Instance) (*class.Instance, bool) { +func (e *Environment) GetMacro(key class.Instance) (class.Instance, bool) { for _, vars := range e.Macro { - if v, ok := vars[*key]; ok { + if v, ok := vars[key.Value()]; ok { return v, ok } } return nil, false } -func (e *Environment) SetMacro(key *class.Instance, value *class.Instance) { +func (e *Environment) SetMacro(key class.Instance, value class.Instance) { for _, vars := range e.Macro { - if _, ok := vars[*key]; ok { - vars[*key] = value + if _, ok := vars[key.Value()]; ok { + vars[key.Value()] = value return } } - e.Macro[0][*key] = value + e.Macro[0][key.Value()] = value } -func (e *Environment) GetDynamicVariable(key *class.Instance) (*class.Instance, bool) { +func (e *Environment) GetDynamicVariable(key class.Instance) (class.Instance, bool) { for _, vars := range e.DynamicVariable { - if v, ok := vars[*key]; ok { + if v, ok := vars[key.Value()]; ok { return v, ok } } return nil, false } -func (e *Environment) SetDynamicVariable(key *class.Instance, value *class.Instance) { +func (e *Environment) SetDynamicVariable(key class.Instance, value class.Instance) { for _, vars := range e.DynamicVariable { - if _, ok := vars[*key]; ok { - vars[*key] = value + if _, ok := vars[key.Value()]; ok { + vars[key.Value()] = value return } } - e.DynamicVariable[0][*key] = value + e.DynamicVariable[0][key.Value()] = value } // TopLevel is a global environment diff --git a/core/eval.go b/core/eval.go index 9ac9a3b..0b5e466 100644 --- a/core/eval.go +++ b/core/eval.go @@ -7,9 +7,9 @@ import ( env "github.com/ta2gch/gazelle/core/environment" ) -func evalArguments(args *class.Instance, local *env.Environment, global *env.Environment) (*class.Instance, *class.Instance) { +func evalArguments(args class.Instance, local *env.Environment, global *env.Environment) (class.Instance, class.Instance) { if args.Class() == class.Null { - return class.Null.New(nil), nil + return class.New(class.Null, nil), nil } car, err := cons.Car(args) if err != nil { @@ -30,7 +30,7 @@ func evalArguments(args *class.Instance, local *env.Environment, global *env.Env return cons.New(a, b), nil } -func evalFunction(obj *class.Instance, local *env.Environment, global *env.Environment) (*class.Instance, *class.Instance) { +func evalFunction(obj class.Instance, local *env.Environment, global *env.Environment) (class.Instance, class.Instance) { // get function symbol car, err := cons.Car(obj) if err != nil { @@ -47,7 +47,7 @@ func evalFunction(obj *class.Instance, local *env.Environment, global *env.Envir if err != nil { return nil, err } - if *caar == *class.Symbol.New("lambda") { + if caar.Value() == "lambda" { fun, err := Eval(car, local, global) if err != nil { return nil, err @@ -66,10 +66,10 @@ func evalFunction(obj *class.Instance, local *env.Environment, global *env.Envir } } if car.Class() != class.Symbol { - return nil, class.DomainError.New(nil) + return nil, class.New(class.DomainError, nil) } // get macro instance has value of Function interface - var mac *class.Instance + var mac class.Instance if m, ok := local.GetMacro(car); ok { mac = m } @@ -84,7 +84,7 @@ func evalFunction(obj *class.Instance, local *env.Environment, global *env.Envir return ret, nil } // get function instance has value of Function interface - var fun *class.Instance + var fun class.Instance if f, ok := local.GetFunction(car); ok { fun = f } @@ -104,13 +104,13 @@ func evalFunction(obj *class.Instance, local *env.Environment, global *env.Envir } return ret, nil } - return nil, class.UndefinedFunction.New(nil) + return nil, class.New(class.UndefinedFunction, nil) } // Eval evaluates any classs -func Eval(obj *class.Instance, local *env.Environment, global *env.Environment) (*class.Instance, *class.Instance) { +func Eval(obj class.Instance, local *env.Environment, global *env.Environment) (class.Instance, class.Instance) { if obj.Class() == class.Null { - return class.Null.New(nil), nil + return class.New(class.Null, nil), nil } switch obj.Class() { case class.Symbol: @@ -120,7 +120,7 @@ func Eval(obj *class.Instance, local *env.Environment, global *env.Environment) if val, ok := global.GetVariable(obj); ok { return val, nil } - return nil, class.UndefinedVariable.New(nil) + return nil, class.New(class.UndefinedVariable, nil) case class.Cons: // obj is a form or a macro ret, err := evalFunction(obj, local, global) if err != nil { @@ -130,5 +130,5 @@ func Eval(obj *class.Instance, local *env.Environment, global *env.Environment) case class.Integer, class.Float, class.Character, class.String: return obj, nil } - return nil, class.ParseError.New(nil) + return nil, class.New(class.ParseError, nil) } diff --git a/core/eval_test.go b/core/eval_test.go index 90994b5..3013b04 100644 --- a/core/eval_test.go +++ b/core/eval_test.go @@ -12,7 +12,7 @@ import ( "github.com/ta2gch/gazelle/reader/tokenizer" ) -func read(s string) *class.Instance { +func read(s string) class.Instance { e, _ := parser.Parse(tokenizer.New(strings.NewReader(s))) return e } @@ -20,53 +20,53 @@ func read(s string) *class.Instance { func TestEval(t *testing.T) { local := env.New() global := env.New() - local.SetVariable(class.Symbol.New("pi"), class.Float.New(3.14)) - local.SetFunction(class.Symbol.New("inc"), NewNativeFunction(func(args *class.Instance, local *env.Environment, global *env.Environment) (*class.Instance, *class.Instance) { + local.SetVariable(class.New(class.Symbol, "pi"), class.New(class.Float, 3.14)) + local.SetFunction(class.New(class.Symbol, "inc"), NewNativeFunction(func(args class.Instance, local *env.Environment, global *env.Environment) (class.Instance, class.Instance) { car, _ := cons.Car(args) - return class.Integer.New(car.Value().(int) + 1), nil + return class.New(class.Integer, car.Value().(int)+1), nil })) - local.SetMacro(class.Symbol.New("minc"), NewNativeFunction(func(args *class.Instance, local *env.Environment, global *env.Environment) (*class.Instance, *class.Instance) { - ret, _ := Eval(cons.New(class.Symbol.New("inc"), args), local, global) + local.SetMacro(class.New(class.Symbol, "minc"), NewNativeFunction(func(args class.Instance, local *env.Environment, global *env.Environment) (class.Instance, class.Instance) { + ret, _ := Eval(cons.New(class.New(class.Symbol, "inc"), args), local, global) return ret, nil })) - global.SetMacro(class.Symbol.New("lambda"), NewNativeFunction(func(args *class.Instance, local *env.Environment, global *env.Environment) (*class.Instance, *class.Instance) { + global.SetMacro(class.New(class.Symbol, "lambda"), NewNativeFunction(func(args class.Instance, local *env.Environment, global *env.Environment) (class.Instance, class.Instance) { car, _ := cons.Car(args) cdr, _ := cons.Cdr(args) return NewLambdaFunction(car, cdr, local), nil })) type args struct { - obj *class.Instance + obj class.Instance local *env.Environment global *env.Environment } tests := []struct { name string args args - want *class.Instance + want class.Instance wantErr bool }{ { name: "local variable", - args: args{class.Symbol.New("pi"), local, global}, - want: class.Float.New(3.14), + args: args{class.New(class.Symbol, "pi"), local, global}, + want: class.New(class.Float, 3.14), wantErr: false, }, { name: "local function", args: args{read("(inc (inc 1))"), local, global}, - want: class.Integer.New(3), + want: class.New(class.Integer, 3), wantErr: false, }, { name: "local macro", args: args{read("(minc (minc 1))"), local, global}, - want: class.Integer.New(3), + want: class.New(class.Integer, 3), wantErr: false, }, { name: "lambda", args: args{read("((lambda (x) (minc x)) 1)"), local, global}, - want: class.Integer.New(2), + want: class.New(class.Integer, 2), wantErr: false, }, } diff --git a/core/init.go b/core/init.go new file mode 100644 index 0000000..47edcdd --- /dev/null +++ b/core/init.go @@ -0,0 +1,27 @@ +package core + +import ( + "github.com/ta2gch/gazelle/core/class" + "github.com/ta2gch/gazelle/core/class/cons" + env "github.com/ta2gch/gazelle/core/environment" +) + +func init() { + env.TopLevel.SetFunction(class.New(class.Symbol, "functionp"), NewNativeFunction(func(args class.Instance, local *env.Environment, global *env.Environment) (class.Instance, class.Instance) { + len, err := cons.Length(args) + if err != nil { + return nil, err + } + if len != 1 { + return nil, class.New(class.UndefinedFunction, nil) + } + car, err := cons.Car(args) + if err != nil { + return nil, err + } + if car.Class() == class.Function { + return class.New(class.Object, true), nil + } + return class.New(class.Null, nil), nil + })) +} diff --git a/core/lambda.go b/core/lambda.go index b52ebea..8f1a341 100644 --- a/core/lambda.go +++ b/core/lambda.go @@ -7,18 +7,18 @@ import ( ) type LambdaFunction struct { - args *class.Instance - body *class.Instance - local *env.Environment + lambdaList class.Instance + forms class.Instance + local *env.Environment } -func NewLambdaFunction(args *class.Instance, body *class.Instance, local *env.Environment) *class.Instance { - return class.Function.New(&LambdaFunction{args, body, local}) +func NewLambdaFunction(lambdaList class.Instance, forms class.Instance, local *env.Environment) class.Instance { + return class.New(class.Function, &LambdaFunction{lambdaList, forms, local}) } -func (f LambdaFunction) Apply(args *class.Instance, local *env.Environment, global *env.Environment) (*class.Instance, *class.Instance) { +func (f LambdaFunction) Apply(args class.Instance, local *env.Environment, global *env.Environment) (class.Instance, class.Instance) { local.MergeAll(f.local) - fargs := f.args + fargs := f.lambdaList aargs := args for fargs.Class() != class.Null { key, err := cons.Car(fargs) @@ -29,16 +29,23 @@ func (f LambdaFunction) Apply(args *class.Instance, local *env.Environment, glob if err != nil { return nil, err } - if *key == *class.Symbol.New(":rest") || *key == *class.Symbol.New("&rest") { + if key == class.New(class.Symbol, ":rest") || key == class.New(class.Symbol, "&rest") { cdr, err := cons.Cdr(fargs) if err != nil { return nil, err } - caar, err := cons.Car(cdr) + cadr, err := cons.Car(cdr) if err != nil { return nil, err } - local.SetVariable(caar, aargs) + cddr, err := cons.Cdr(cdr) + if err != nil { + return nil, err + } + if cddr.Class() == class.Null { + return nil, class.New(class.ParseError, nil) + } + local.SetVariable(cadr, aargs) break } local.SetVariable(key, value) @@ -51,8 +58,8 @@ func (f LambdaFunction) Apply(args *class.Instance, local *env.Environment, glob return nil, err } } - body := f.body - var ret *class.Instance + body := f.forms + var ret class.Instance for body.Class() != class.Null { exp, err := cons.Car(body) if err != nil { diff --git a/core/native.go b/core/native.go index 2ed0d03..df6fe44 100644 --- a/core/native.go +++ b/core/native.go @@ -6,10 +6,10 @@ import ( ) type NativeFunction struct { - fun func(*class.Instance, *env.Environment, *env.Environment) (*class.Instance, *class.Instance) + fun func(class.Instance, *env.Environment, *env.Environment) (class.Instance, class.Instance) } -func (f NativeFunction) Apply(args *class.Instance, local *env.Environment, global *env.Environment) (*class.Instance, *class.Instance) { +func (f NativeFunction) Apply(args class.Instance, local *env.Environment, global *env.Environment) (class.Instance, class.Instance) { obj, err := f.fun(args, local, global) if err != nil { return nil, err @@ -17,6 +17,6 @@ func (f NativeFunction) Apply(args *class.Instance, local *env.Environment, glob return obj, nil } -func NewNativeFunction(fun func(*class.Instance, *env.Environment, *env.Environment) (*class.Instance, *class.Instance)) *class.Instance { - return class.Function.New(&NativeFunction{fun}) +func NewNativeFunction(fun func(class.Instance, *env.Environment, *env.Environment) (class.Instance, class.Instance)) class.Instance { + return class.New(class.Function, &NativeFunction{fun}) } diff --git a/reader/parser/parser.go b/reader/parser/parser.go index a9cd590..9710a26 100644 --- a/reader/parser/parser.go +++ b/reader/parser/parser.go @@ -11,96 +11,96 @@ import ( "github.com/ta2gch/gazelle/reader/tokenizer" ) -var eop = class.SimpleError.New("End Of Parentheses") -var bod = class.SimpleError.New("Begin Of Dot") +var eop = class.New(class.Object, "End Of Parentheses") +var bod = class.New(class.Object, "Begin Of Dot") -func parseAtom(tok string) (*class.Instance, *class.Instance) { +func parseAtom(tok string) (class.Instance, class.Instance) { // // integer // if m, _ := regexp.MatchString("^[-+]?[[:digit:]]+$", tok); m { n, _ := strconv.ParseInt(tok, 10, 64) - return class.Integer.New(int(n)), nil + return class.New(class.Integer, int(n)), nil } if r := regexp.MustCompile("^#[bB]([-+]?[01]+)$").FindStringSubmatch(tok); len(r) >= 2 { n, _ := strconv.ParseInt(r[1], 2, 64) - return class.Integer.New(int(n)), nil + return class.New(class.Integer, int(n)), nil } if r := regexp.MustCompile("^#[oO]([-+]?[0-7]+)$").FindStringSubmatch(tok); len(r) >= 2 { n, _ := strconv.ParseInt(r[1], 8, 64) - return class.Integer.New(int(n)), nil + return class.New(class.Integer, int(n)), nil } if r := regexp.MustCompile("^#[xX]([-+]?[[:xdigit:]]+)$").FindStringSubmatch(tok); len(r) >= 2 { n, _ := strconv.ParseInt(r[1], 16, 64) - return class.Integer.New(int(n)), nil + return class.New(class.Integer, int(n)), nil } // // float // if m, _ := regexp.MatchString("^[-+]?[[:digit:]]+\\.[[:digit:]]+$", tok); m { n, _ := strconv.ParseFloat(tok, 64) - return class.Float.New(n), nil + return class.New(class.Float, n), nil } if r := regexp.MustCompile("^([-+]?[[:digit:]]+(?:\\.[[:digit:]]+)?)[eE]([-+]?[[:digit:]]+)$").FindStringSubmatch(tok); len(r) >= 3 { n, _ := strconv.ParseFloat(r[1], 64) e, _ := strconv.ParseInt(r[2], 10, 64) - return class.Float.New(n * math.Pow10(int(e))), nil + return class.New(class.Float, n*math.Pow10(int(e))), nil } // // character // if m, _ := regexp.MatchString("^#\\\\newline$", tok); m { - return class.Character.New('\n'), nil + return class.New(class.Character, '\n'), nil } if m, _ := regexp.MatchString("^#\\\\space$", tok); m { - return class.Character.New(' '), nil + return class.New(class.Character, ' '), nil } if r := regexp.MustCompile("^#\\\\([[:graph:]])$").FindStringSubmatch(tok); len(r) >= 2 { - return class.Character.New(rune(r[1][0])), nil + return class.New(class.Character, rune(r[1][0])), nil } // // string // if m, _ := regexp.MatchString("^\".*\"$", tok); m { - return class.String.New(tok), nil + return class.New(class.String, tok), nil } // // symbol // if "nil" == tok { - return class.Null.New(nil), nil + return class.New(class.Null, nil), nil } if r := regexp.MustCompile("^:([<>/*=?_!$%[\\]^{}~0-9a-zA-Z]+)$").FindStringSubmatch(tok); len(r) >= 2 { - return class.Symbol.New(r[1]), nil + return class.New(class.Symbol, r[1]), nil } if m, _ := regexp.MatchString("^\\|.*\\|$", tok); m { - return class.Symbol.New(tok), nil + return class.New(class.Symbol, tok), nil } if m, _ := regexp.MatchString("^[<>/*=?_!$%[\\]^{}~a-zA-Z][<>/*=?_!$%[\\]^{}~0-9a-zA-Z]*$", tok); m { - return class.Symbol.New(tok), nil + return class.New(class.Symbol, tok), nil } - return nil, class.ParseError.New(nil) + return nil, class.New(class.ParseError, nil) } -func parseMacro(tok string, t *tokenizer.Tokenizer) (*class.Instance, *class.Instance) { +func parseMacro(tok string, t *tokenizer.Tokenizer) (class.Instance, class.Instance) { cdr, err := Parse(t) if err != nil { return nil, err } n := tok if m, _ := regexp.MatchString("#[[:digit:]]*[aA]", tok); m { - s := class.Symbol.New("array") + s := class.New(class.Symbol, "array") i := strings.IndexRune(strings.ToLower(tok), 'a') if i == 1 { - d := class.Integer.New(1) - return cons.New(s, cons.New(d, cons.New(cdr, class.Null.New(nil)))), nil + d := class.New(class.Integer, 1) + return cons.New(s, cons.New(d, cons.New(cdr, class.New(class.Null, nil)))), nil } v, err := strconv.ParseInt(tok[1:i], 10, 32) if err != nil { - return nil, class.ParseError.New(nil) + return nil, class.New(class.ParseError, nil) } - d := class.Integer.New(int(v)) - return cons.New(s, cons.New(d, cons.New(cdr, class.Null.New(nil)))), nil + d := class.New(class.Integer, int(v)) + return cons.New(s, cons.New(d, cons.New(cdr, class.New(class.Null, nil)))), nil } switch tok { case ",@": @@ -112,13 +112,13 @@ func parseMacro(tok string, t *tokenizer.Tokenizer) (*class.Instance, *class.Ins case "`": n = "backquote" } - m := class.Symbol.New(n) - return cons.New(m, cons.New(cdr, class.Null.New(nil))), nil + m := class.New(class.Symbol, n) + return cons.New(m, cons.New(cdr, class.New(class.Null, nil))), nil } -func parseCons(t *tokenizer.Tokenizer) (*class.Instance, *class.Instance) { +func parseCons(t *tokenizer.Tokenizer) (class.Instance, class.Instance) { car, err := Parse(t) if err == eop { - return class.Null.New(nil), nil + return class.New(class.Null, nil), nil } if err == bod { cdr, err := Parse(t) @@ -141,7 +141,7 @@ func parseCons(t *tokenizer.Tokenizer) (*class.Instance, *class.Instance) { } // Parse builds a internal expression from tokens -func Parse(t *tokenizer.Tokenizer) (*class.Instance, *class.Instance) { +func Parse(t *tokenizer.Tokenizer) (class.Instance, class.Instance) { tok, err := t.Next() if err != nil { return nil, err diff --git a/reader/parser/parser_test.go b/reader/parser/parser_test.go index 4e45e0a..982477f 100644 --- a/reader/parser/parser_test.go +++ b/reader/parser/parser_test.go @@ -14,7 +14,7 @@ func Test_parseAtom(t *testing.T) { tests := []struct { name string args args - want *class.Instance + want class.Instance wantErr bool }{ // @@ -23,31 +23,31 @@ func Test_parseAtom(t *testing.T) { { name: "default", args: args{"3.14"}, - want: class.Float.New(3.14), + want: class.New(class.Float, 3.14), wantErr: false, }, { name: "signed", args: args{"-5.0"}, - want: class.Float.New(-5.0), + want: class.New(class.Float, -5.0), wantErr: false, }, { name: "exponential", args: args{"-5.0E3"}, - want: class.Float.New(-5.0 * 1000), + want: class.New(class.Float, -5.0*1000), wantErr: false, }, { name: "signed exponential", args: args{"5.0E-3"}, - want: class.Float.New(5.0 * 1.0 / 1000.0), + want: class.New(class.Float, 5.0*1.0/1000.0), wantErr: false, }, { name: "without point", args: args{"5E-3"}, - want: class.Float.New(5.0 * 1.0 / 1000.0), + want: class.New(class.Float, 5.0*1.0/1000.0), wantErr: false, }, { @@ -68,49 +68,49 @@ func Test_parseAtom(t *testing.T) { { name: "default", args: args{"5"}, - want: class.Integer.New(5), + want: class.New(class.Integer, 5), wantErr: false, }, { name: "signed", args: args{"-5"}, - want: class.Integer.New(-5), + want: class.New(class.Integer, -5), wantErr: false, }, { name: "binary", args: args{"#B00101"}, - want: class.Integer.New(5), + want: class.New(class.Integer, 5), wantErr: false, }, { name: "signed binary", args: args{"#b+00101"}, - want: class.Integer.New(5), + want: class.New(class.Integer, 5), wantErr: false, }, { name: "octal", args: args{"#o00101"}, - want: class.Integer.New(65), + want: class.New(class.Integer, 65), wantErr: false, }, { name: "signed octal", args: args{"#O-00101"}, - want: class.Integer.New(-65), + want: class.New(class.Integer, -65), wantErr: false, }, { name: "hexadecimal", args: args{"#X00101"}, - want: class.Integer.New(257), + want: class.New(class.Integer, 257), wantErr: false, }, { name: "signed hexadecimal", args: args{"#x-00101"}, - want: class.Integer.New(-257), + want: class.New(class.Integer, -257), wantErr: false, }, { @@ -125,19 +125,19 @@ func Test_parseAtom(t *testing.T) { { name: "default", args: args{"#\\a"}, - want: class.Character.New('a'), + want: class.New(class.Character, 'a'), wantErr: false, }, { name: "newline", args: args{"#\\newline"}, - want: class.Character.New('\n'), + want: class.New(class.Character, '\n'), wantErr: false, }, { name: "space", args: args{"#\\space"}, - want: class.Character.New(' '), + want: class.New(class.Character, ' '), wantErr: false, }, { diff --git a/reader/tokenizer/tokenizer.go b/reader/tokenizer/tokenizer.go index c2cbf12..a8c18b8 100644 --- a/reader/tokenizer/tokenizer.go +++ b/reader/tokenizer/tokenizer.go @@ -63,13 +63,13 @@ var token = concatMatcher( parentheses) // Next returns error or string as token -func (r *Tokenizer) Next() (string, *class.Instance) { +func (r *Tokenizer) Next() (string, class.Instance) { buf := "" for { if buf == "" { p, _, err := r.PeekRune() if err != nil { - return "", class.ParseError.New(nil) + return "", class.New(class.ParseError, nil) } if token.MatchString(string(p)) { buf = string(p) From 62fe273d46d54361a5738d6d670a24e59415b7d6 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Sun, 30 Jul 2017 13:28:20 +0900 Subject: [PATCH 062/228] refactor --- core/class/class.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/class/class.go b/core/class/class.go index 2e47ea3..d02512a 100644 --- a/core/class/class.go +++ b/core/class/class.go @@ -31,7 +31,7 @@ func (m *MetaClass) Value() Value { } func (m *MetaClass) New(value ...Value) Instance { - return &builtInClass{[]Class{value[0].(Instance).Value().(Class)}, value[1].(string)} + return &builtInClass{[]Class{value[0].(Class)}, value[1].(string)} } type builtInClass struct { From 506d4434a72289aaf88527739f3a51406c66252b Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Sun, 30 Jul 2017 13:41:59 +0900 Subject: [PATCH 063/228] Changed type of Parents --- core/class/class.go | 112 ++++++++++++++++++++++---------------------- 1 file changed, 56 insertions(+), 56 deletions(-) diff --git a/core/class/class.go b/core/class/class.go index d02512a..5acb9ed 100644 --- a/core/class/class.go +++ b/core/class/class.go @@ -2,7 +2,7 @@ package class type Class interface { ToString() string - Parents() []Class + Parents() []Instance New(...Value) Instance } @@ -10,91 +10,91 @@ func New(c Instance, value ...Value) Instance { return c.(Class).New(value...) } -type MetaClass struct { +type meta struct { name string } -func (m *MetaClass) ToString() string { +func (m *meta) ToString() string { return m.name } -func (*MetaClass) Parents() []Class { - return []Class{Object.Value().(Class)} +func (*meta) Parents() []Instance { + return []Instance{Object} } -func (*MetaClass) Class() Instance { - return Object +func (*meta) Class() Instance { + return BuiltInClass } -func (m *MetaClass) Value() Value { +func (m *meta) Value() Value { return m } -func (m *MetaClass) New(value ...Value) Instance { - return &builtInClass{[]Class{value[0].(Class)}, value[1].(string)} +func (m *meta) New(value ...Value) Instance { + return &builtin{[]Instance{value[0].(Instance)}, value[1].(string)} } -type builtInClass struct { - parents []Class +type builtin struct { + parents []Instance name string } -func (c *builtInClass) ToString() string { +func (c *builtin) ToString() string { return c.name } -func (c *builtInClass) Parents() []Class { +func (c *builtin) Parents() []Instance { return c.parents } -func (c *builtInClass) Class() Instance { +func (c *builtin) Class() Instance { return BuiltInClass } -func (c *builtInClass) Value() Value { +func (c *builtin) Value() Value { return c } -func (c *builtInClass) New(value ...Value) Instance { +func (c *builtin) New(value ...Value) Instance { return &DefaultInstance{c, value[0]} } -var Object = &builtInClass{[]Class{}, ""} -var BasicArray = BuiltInClass.New(Object, "") -var BasicArrayStar = BuiltInClass.New(BasicArray, "") -var GeneralArrayStar = BuiltInClass.New(BasicArrayStar, "") -var BasicVector = BuiltInClass.New(BasicArray, "") -var GeneraVector = BuiltInClass.New(BasicVector, "") -var String = BuiltInClass.New(BasicVector, "") -var BuiltInClass = &MetaClass{""} -var Character = BuiltInClass.New(Object, "") -var Function = BuiltInClass.New(Object, "") -var GenericFunction = BuiltInClass.New(Function, "") -var StandardGenericFunction = BuiltInClass.New(GenericFunction, "") -var List = BuiltInClass.New(Object, "") -var Cons = BuiltInClass.New(List, "") -var Null = BuiltInClass.New(List, "") -var Symbol = BuiltInClass.New(Object, "") -var Number = BuiltInClass.New(Object, "") -var Integer = BuiltInClass.New(Number, "") -var Float = BuiltInClass.New(Number, "") -var SeriousCondition = BuiltInClass.New(Object, "") -var Error = BuiltInClass.New(SeriousCondition, "") -var ArithmeticError = BuiltInClass.New(Error, "") -var DivisionByZero = BuiltInClass.New(ArithmeticError, "") -var FloatingPointOnderflow = BuiltInClass.New(ArithmeticError, "") -var FloatingPointUnderflow = BuiltInClass.New(ArithmeticError, "") -var ControlError = BuiltInClass.New(Error, "") -var ParseError = BuiltInClass.New(Error, "") -var ProgramError = BuiltInClass.New(Error, "") -var DomainError = BuiltInClass.New(ProgramError, "") -var UndefinedEntity = BuiltInClass.New(ProgramError, "") -var UndefinedVariable = BuiltInClass.New(UndefinedEntity, "") -var UndefinedFunction = BuiltInClass.New(UndefinedEntity, "") -var SimpleError = BuiltInClass.New(Error, "") -var StreamError = BuiltInClass.New(Error, "") -var EndOfStream = BuiltInClass.New(StreamError, "") -var StorageExhausted = BuiltInClass.New(SeriousCondition, "") -var StandardClass = &MetaClass{""} -var StandardObject = BuiltInClass.New(Object, "") -var Stream = BuiltInClass.New(Object, "") +var Object = &builtin{[]Instance{}, ""} +var BasicArray = New(BuiltInClass, Object, "") +var BasicArrayStar = New(BuiltInClass, BasicArray, "") +var GeneralArrayStar = New(BuiltInClass, BasicArrayStar, "") +var BasicVector = New(BuiltInClass, BasicArray, "") +var GeneraVector = New(BuiltInClass, BasicVector, "") +var String = New(BuiltInClass, BasicVector, "") +var BuiltInClass = &meta{""} +var Character = New(BuiltInClass, Object, "") +var Function = New(BuiltInClass, Object, "") +var GenericFunction = New(BuiltInClass, Function, "") +var StandardGenericFunction = New(BuiltInClass, GenericFunction, "") +var List = New(BuiltInClass, Object, "") +var Cons = New(BuiltInClass, List, "") +var Null = New(BuiltInClass, List, "") +var Symbol = New(BuiltInClass, Object, "") +var Number = New(BuiltInClass, Object, "") +var Integer = New(BuiltInClass, Number, "") +var Float = New(BuiltInClass, Number, "") +var SeriousCondition = New(BuiltInClass, Object, "") +var Error = New(BuiltInClass, SeriousCondition, "") +var ArithmeticError = New(BuiltInClass, Error, "") +var DivisionByZero = New(BuiltInClass, ArithmeticError, "") +var FloatingPointOnderflow = New(BuiltInClass, ArithmeticError, "") +var FloatingPointUnderflow = New(BuiltInClass, ArithmeticError, "") +var ControlError = New(BuiltInClass, Error, "") +var ParseError = New(BuiltInClass, Error, "") +var ProgramError = New(BuiltInClass, Error, "") +var DomainError = New(BuiltInClass, ProgramError, "") +var UndefinedEntity = New(BuiltInClass, ProgramError, "") +var UndefinedVariable = New(BuiltInClass, UndefinedEntity, "") +var UndefinedFunction = New(BuiltInClass, UndefinedEntity, "") +var SimpleError = New(BuiltInClass, Error, "") +var StreamError = New(BuiltInClass, Error, "") +var EndOfStream = New(BuiltInClass, StreamError, "") +var StorageExhausted = New(BuiltInClass, SeriousCondition, "") +var StandardClass = &meta{""} +var StandardObject = New(BuiltInClass, Object, "") +var Stream = New(BuiltInClass, Object, "") From 7758d8f73add7b5068bb4e6cf0cfb2ac6f99d699 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Sun, 30 Jul 2017 17:15:36 +0900 Subject: [PATCH 064/228] Added IsInstanceOf --- core/class/class.go | 132 ++++++++++++++++++++------------ core/class/cons/cons.go | 12 +-- core/class/function/function.go | 2 +- core/class/instance.go | 26 +++++-- core/eval.go | 20 +++-- core/eval_test.go | 2 +- core/init.go | 2 +- core/lambda.go | 8 +- core/native.go | 2 +- 9 files changed, 128 insertions(+), 78 deletions(-) diff --git a/core/class/class.go b/core/class/class.go index 5acb9ed..9837940 100644 --- a/core/class/class.go +++ b/core/class/class.go @@ -2,12 +2,24 @@ package class type Class interface { ToString() string - Parents() []Instance + Parents() []Class New(...Value) Instance } -func New(c Instance, value ...Value) Instance { - return c.(Class).New(value...) +func test(child Class, parent Class) bool { + if child == parent { + return true + } + for _, p := range child.Parents() { + if test(p, parent) { + return true + } + } + return false +} + +func New(class Class, value ...Value) Instance { + return class.New(value...) } type meta struct { @@ -18,11 +30,11 @@ func (m *meta) ToString() string { return m.name } -func (*meta) Parents() []Instance { - return []Instance{Object} +func (*meta) Parents() []Class { + return []Class{Object} } -func (*meta) Class() Instance { +func (*meta) Class() Class { return BuiltInClass } @@ -31,11 +43,23 @@ func (m *meta) Value() Value { } func (m *meta) New(value ...Value) Instance { - return &builtin{[]Instance{value[0].(Instance)}, value[1].(string)} + return &builtin{[]Class{value[0].(Class)}, value[1].(string)} +} + +func (m *meta) IsInstanceOf(class Class) bool { + if m.Class() == class { + return true + } + for _, p := range m.Class().Parents() { + if test(p, class) { + return true + } + } + return false } type builtin struct { - parents []Instance + parents []Class name string } @@ -43,11 +67,11 @@ func (c *builtin) ToString() string { return c.name } -func (c *builtin) Parents() []Instance { +func (c *builtin) Parents() []Class { return c.parents } -func (c *builtin) Class() Instance { +func (c *builtin) Class() Class { return BuiltInClass } @@ -56,45 +80,57 @@ func (c *builtin) Value() Value { } func (c *builtin) New(value ...Value) Instance { - return &DefaultInstance{c, value[0]} + return &defaultInstance{c, value[0]} +} + +func (c *builtin) IsInstanceOf(class Class) bool { + if c == class { + return true + } + for _, p := range c.Class().Parents() { + if test(p, class) { + return true + } + } + return false } -var Object = &builtin{[]Instance{}, ""} -var BasicArray = New(BuiltInClass, Object, "") -var BasicArrayStar = New(BuiltInClass, BasicArray, "") -var GeneralArrayStar = New(BuiltInClass, BasicArrayStar, "") -var BasicVector = New(BuiltInClass, BasicArray, "") -var GeneraVector = New(BuiltInClass, BasicVector, "") -var String = New(BuiltInClass, BasicVector, "") +var Object = &builtin{[]Class{}, ""} +var BasicArray = New(BuiltInClass, Object, "").(Class) +var BasicArrayStar = New(BuiltInClass, BasicArray, "").(Class) +var GeneralArrayStar = New(BuiltInClass, BasicArrayStar, "").(Class) +var BasicVector = New(BuiltInClass, BasicArray, "").(Class) +var GeneraVector = New(BuiltInClass, BasicVector, "").(Class) +var String = New(BuiltInClass, BasicVector, "").(Class) var BuiltInClass = &meta{""} -var Character = New(BuiltInClass, Object, "") -var Function = New(BuiltInClass, Object, "") -var GenericFunction = New(BuiltInClass, Function, "") -var StandardGenericFunction = New(BuiltInClass, GenericFunction, "") -var List = New(BuiltInClass, Object, "") -var Cons = New(BuiltInClass, List, "") -var Null = New(BuiltInClass, List, "") -var Symbol = New(BuiltInClass, Object, "") -var Number = New(BuiltInClass, Object, "") -var Integer = New(BuiltInClass, Number, "") -var Float = New(BuiltInClass, Number, "") -var SeriousCondition = New(BuiltInClass, Object, "") -var Error = New(BuiltInClass, SeriousCondition, "") -var ArithmeticError = New(BuiltInClass, Error, "") -var DivisionByZero = New(BuiltInClass, ArithmeticError, "") -var FloatingPointOnderflow = New(BuiltInClass, ArithmeticError, "") -var FloatingPointUnderflow = New(BuiltInClass, ArithmeticError, "") -var ControlError = New(BuiltInClass, Error, "") -var ParseError = New(BuiltInClass, Error, "") -var ProgramError = New(BuiltInClass, Error, "") -var DomainError = New(BuiltInClass, ProgramError, "") -var UndefinedEntity = New(BuiltInClass, ProgramError, "") -var UndefinedVariable = New(BuiltInClass, UndefinedEntity, "") -var UndefinedFunction = New(BuiltInClass, UndefinedEntity, "") -var SimpleError = New(BuiltInClass, Error, "") -var StreamError = New(BuiltInClass, Error, "") -var EndOfStream = New(BuiltInClass, StreamError, "") -var StorageExhausted = New(BuiltInClass, SeriousCondition, "") +var Character = New(BuiltInClass, Object, "").(Class) +var Function = New(BuiltInClass, Object, "").(Class) +var GenericFunction = New(BuiltInClass, Function, "").(Class) +var StandardGenericFunction = New(BuiltInClass, GenericFunction, "").(Class) +var List = New(BuiltInClass, Object, "").(Class) +var Cons = New(BuiltInClass, List, "").(Class) +var Null = New(BuiltInClass, List, "").(Class) +var Symbol = New(BuiltInClass, Object, "").(Class) +var Number = New(BuiltInClass, Object, "").(Class) +var Integer = New(BuiltInClass, Number, "").(Class) +var Float = New(BuiltInClass, Number, "").(Class) +var SeriousCondition = New(BuiltInClass, Object, "").(Class) +var Error = New(BuiltInClass, SeriousCondition, "").(Class) +var ArithmeticError = New(BuiltInClass, Error, "").(Class) +var DivisionByZero = New(BuiltInClass, ArithmeticError, "").(Class) +var FloatingPointOnderflow = New(BuiltInClass, ArithmeticError, "").(Class) +var FloatingPointUnderflow = New(BuiltInClass, ArithmeticError, "").(Class) +var ControlError = New(BuiltInClass, Error, "").(Class) +var ParseError = New(BuiltInClass, Error, "").(Class) +var ProgramError = New(BuiltInClass, Error, "").(Class) +var DomainError = New(BuiltInClass, ProgramError, "").(Class) +var UndefinedEntity = New(BuiltInClass, ProgramError, "").(Class) +var UndefinedVariable = New(BuiltInClass, UndefinedEntity, "").(Class) +var UndefinedFunction = New(BuiltInClass, UndefinedEntity, "").(Class) +var SimpleError = New(BuiltInClass, Error, "").(Class) +var StreamError = New(BuiltInClass, Error, "").(Class) +var EndOfStream = New(BuiltInClass, StreamError, "").(Class) +var StorageExhausted = New(BuiltInClass, SeriousCondition, "").(Class) var StandardClass = &meta{""} -var StandardObject = New(BuiltInClass, Object, "") -var Stream = New(BuiltInClass, Object, "") +var StandardObject = New(BuiltInClass, Object, "").(Class) +var Stream = New(BuiltInClass, Object, "").(Class) diff --git a/core/class/cons/cons.go b/core/class/cons/cons.go index b24156c..e1ce032 100644 --- a/core/class/cons/cons.go +++ b/core/class/cons/cons.go @@ -11,25 +11,25 @@ type Cell struct { } func New(car class.Instance, cdr class.Instance) class.Instance { - return class.New(class.Cons, &Cell{car, cdr}) + return class.New(class.Cons, Cell{car, cdr}) } func Car(i class.Instance) (class.Instance, class.Instance) { - if i.Class() == class.Null || (i.Class() != class.Cons && i.Class() != class.List) { + if !i.IsInstanceOf(class.List) { return nil, class.New(class.DomainError, nil) } - return i.Value().(*Cell).car, nil + return i.Value().(Cell).car, nil } func Cdr(i class.Instance) (class.Instance, class.Instance) { - if i.Class() == class.Null || (i.Class() != class.Cons && i.Class() != class.List) { + if i.IsInstanceOf(class.Null) || !i.IsInstanceOf(class.List) { return nil, class.New(class.DomainError, nil) } - return i.Value().(*Cell).cdr, nil + return i.Value().(Cell).cdr, nil } func Length(list class.Instance) (int, class.Instance) { - if list.Class() == class.Null { + if list.IsInstanceOf(class.Null) { return 0, nil } cdr, err := Cdr(list) diff --git a/core/class/function/function.go b/core/class/function/function.go index 173fec6..6e84789 100644 --- a/core/class/function/function.go +++ b/core/class/function/function.go @@ -10,7 +10,7 @@ type Function interface { } func Apply(fun class.Instance, args class.Instance, local *env.Environment, global *env.Environment) (class.Instance, class.Instance) { - if fun.Class() != class.Function { + if !fun.IsInstanceOf(class.Function) { return nil, class.New(class.DomainError, nil) } obj, err := fun.Value().(Function).Apply(args, local, global) diff --git a/core/class/instance.go b/core/class/instance.go index afd2637..a83d99d 100644 --- a/core/class/instance.go +++ b/core/class/instance.go @@ -4,22 +4,32 @@ type Value interface{} // Instance struct type is the struct for the internal representations type Instance interface { - Class() Instance + Class() Class Value() Value + IsInstanceOf(Class) bool } -type DefaultInstance struct { - class Instance +type defaultInstance struct { + class Class value Value } -func (i *DefaultInstance) Class() Instance { +func (i *defaultInstance) Class() Class { return i.class } -func (i *DefaultInstance) Value() Value { - if i.Class() == nil { - return nil - } +func (i *defaultInstance) Value() Value { return i.value } + +func (i *defaultInstance) IsInstanceOf(class Class) bool { + if i.Class() == class { + return true + } + for _, p := range i.Class().Parents() { + if test(p, class) { + return true + } + } + return false +} diff --git a/core/eval.go b/core/eval.go index 0b5e466..5b2ce89 100644 --- a/core/eval.go +++ b/core/eval.go @@ -8,7 +8,7 @@ import ( ) func evalArguments(args class.Instance, local *env.Environment, global *env.Environment) (class.Instance, class.Instance) { - if args.Class() == class.Null { + if args.IsInstanceOf(class.Null) { return class.New(class.Null, nil), nil } car, err := cons.Car(args) @@ -36,13 +36,15 @@ func evalFunction(obj class.Instance, local *env.Environment, global *env.Enviro if err != nil { return nil, err } + println("called") + // get function arguments cdr, err := cons.Cdr(obj) if err != nil { return nil, err } // eval if lambda form - if car.Class() == class.Cons { + if car.IsInstanceOf(class.Cons) { caar, err := cons.Car(car) if err != nil { return nil, err @@ -65,7 +67,8 @@ func evalFunction(obj class.Instance, local *env.Environment, global *env.Enviro return ret, nil } } - if car.Class() != class.Symbol { + + if !car.IsInstanceOf(class.Symbol) { return nil, class.New(class.DomainError, nil) } // get macro instance has value of Function interface @@ -109,11 +112,10 @@ func evalFunction(obj class.Instance, local *env.Environment, global *env.Enviro // Eval evaluates any classs func Eval(obj class.Instance, local *env.Environment, global *env.Environment) (class.Instance, class.Instance) { - if obj.Class() == class.Null { + if obj.IsInstanceOf(class.Null) { return class.New(class.Null, nil), nil } - switch obj.Class() { - case class.Symbol: + if obj.IsInstanceOf(class.Symbol) { if val, ok := local.GetVariable(obj); ok { return val, nil } @@ -121,13 +123,15 @@ func Eval(obj class.Instance, local *env.Environment, global *env.Environment) ( return val, nil } return nil, class.New(class.UndefinedVariable, nil) - case class.Cons: // obj is a form or a macro + } + if obj.IsInstanceOf(class.Cons) { ret, err := evalFunction(obj, local, global) if err != nil { return nil, err } return ret, nil - case class.Integer, class.Float, class.Character, class.String: + } + if obj.IsInstanceOf(class.Number) || obj.IsInstanceOf(class.Character) || obj.IsInstanceOf(class.String) { return obj, nil } return nil, class.New(class.ParseError, nil) diff --git a/core/eval_test.go b/core/eval_test.go index 3013b04..ec89499 100644 --- a/core/eval_test.go +++ b/core/eval_test.go @@ -74,7 +74,7 @@ func TestEval(t *testing.T) { t.Run(tt.name, func(t *testing.T) { got, err := Eval(tt.args.obj, tt.args.local, tt.args.global) if (err != nil) != tt.wantErr { - t.Errorf("Eval() error = %v, wantErr %v", err, tt.wantErr) + t.Errorf("Eval() error = %v, wantErr %v", err.Class().(class.Class).ToString(), tt.wantErr) return } if !reflect.DeepEqual(got, tt.want) { diff --git a/core/init.go b/core/init.go index 47edcdd..d6b30ad 100644 --- a/core/init.go +++ b/core/init.go @@ -19,7 +19,7 @@ func init() { if err != nil { return nil, err } - if car.Class() == class.Function { + if car.IsInstanceOf(class.Function) { return class.New(class.Object, true), nil } return class.New(class.Null, nil), nil diff --git a/core/lambda.go b/core/lambda.go index 8f1a341..7581e82 100644 --- a/core/lambda.go +++ b/core/lambda.go @@ -13,14 +13,14 @@ type LambdaFunction struct { } func NewLambdaFunction(lambdaList class.Instance, forms class.Instance, local *env.Environment) class.Instance { - return class.New(class.Function, &LambdaFunction{lambdaList, forms, local}) + return class.New(class.Function, LambdaFunction{lambdaList, forms, local}) } func (f LambdaFunction) Apply(args class.Instance, local *env.Environment, global *env.Environment) (class.Instance, class.Instance) { local.MergeAll(f.local) fargs := f.lambdaList aargs := args - for fargs.Class() != class.Null { + for !fargs.IsInstanceOf(class.Null) { key, err := cons.Car(fargs) if err != nil { return nil, err @@ -42,7 +42,7 @@ func (f LambdaFunction) Apply(args class.Instance, local *env.Environment, globa if err != nil { return nil, err } - if cddr.Class() == class.Null { + if !cddr.IsInstanceOf(class.Null) { return nil, class.New(class.ParseError, nil) } local.SetVariable(cadr, aargs) @@ -60,7 +60,7 @@ func (f LambdaFunction) Apply(args class.Instance, local *env.Environment, globa } body := f.forms var ret class.Instance - for body.Class() != class.Null { + for !body.IsInstanceOf(class.Null) { exp, err := cons.Car(body) if err != nil { return nil, err diff --git a/core/native.go b/core/native.go index df6fe44..54f302b 100644 --- a/core/native.go +++ b/core/native.go @@ -18,5 +18,5 @@ func (f NativeFunction) Apply(args class.Instance, local *env.Environment, globa } func NewNativeFunction(fun func(class.Instance, *env.Environment, *env.Environment) (class.Instance, class.Instance)) class.Instance { - return class.New(class.Function, &NativeFunction{fun}) + return class.New(class.Function, NativeFunction{fun}) } From ced06b2835a1ab36e669cc4c6692224a1cdae231 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Sun, 30 Jul 2017 17:17:24 +0900 Subject: [PATCH 065/228] cleanup test --- core/eval_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/eval_test.go b/core/eval_test.go index ec89499..3013b04 100644 --- a/core/eval_test.go +++ b/core/eval_test.go @@ -74,7 +74,7 @@ func TestEval(t *testing.T) { t.Run(tt.name, func(t *testing.T) { got, err := Eval(tt.args.obj, tt.args.local, tt.args.global) if (err != nil) != tt.wantErr { - t.Errorf("Eval() error = %v, wantErr %v", err.Class().(class.Class).ToString(), tt.wantErr) + t.Errorf("Eval() error = %v, wantErr %v", err, tt.wantErr) return } if !reflect.DeepEqual(got, tt.want) { From a5a2eb1145ae243eef7c836157ef6c12d128f514 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Sun, 30 Jul 2017 17:32:04 +0900 Subject: [PATCH 066/228] Splited file --- core/class/builtin.go | 76 ++++++++++++++++++++++++++ core/class/class.go | 119 +++-------------------------------------- core/class/instance.go | 5 ++ core/class/meta.go | 40 ++++++++++++++ 4 files changed, 127 insertions(+), 113 deletions(-) create mode 100644 core/class/builtin.go create mode 100644 core/class/meta.go diff --git a/core/class/builtin.go b/core/class/builtin.go new file mode 100644 index 0000000..f21d672 --- /dev/null +++ b/core/class/builtin.go @@ -0,0 +1,76 @@ +package class + +type builtin struct { + parents []Class + name string +} + +func (c *builtin) ToString() string { + return c.name +} + +func (c *builtin) Parents() []Class { + return c.parents +} + +func (c *builtin) Class() Class { + return BuiltInClass +} + +func (c *builtin) Value() Value { + return c +} + +func (c *builtin) New(value ...Value) Instance { + return &defaultInstance{c, value[0]} +} + +func (c *builtin) IsInstanceOf(class Class) bool { + if c == class { + return true + } + for _, p := range c.Class().Parents() { + if test(p, class) { + return true + } + } + return false +} + +var Object = &builtin{[]Class{}, ""} +var BasicArray = New(BuiltInClass, Object, "").(Class) +var BasicArrayStar = New(BuiltInClass, BasicArray, "").(Class) +var GeneralArrayStar = New(BuiltInClass, BasicArrayStar, "").(Class) +var BasicVector = New(BuiltInClass, BasicArray, "").(Class) +var GeneraVector = New(BuiltInClass, BasicVector, "").(Class) +var String = New(BuiltInClass, BasicVector, "").(Class) +var Character = New(BuiltInClass, Object, "").(Class) +var Function = New(BuiltInClass, Object, "").(Class) +var GenericFunction = New(BuiltInClass, Function, "").(Class) +var StandardGenericFunction = New(BuiltInClass, GenericFunction, "").(Class) +var List = New(BuiltInClass, Object, "").(Class) +var Cons = New(BuiltInClass, List, "").(Class) +var Null = New(BuiltInClass, List, "").(Class) +var Symbol = New(BuiltInClass, Object, "").(Class) +var Number = New(BuiltInClass, Object, "").(Class) +var Integer = New(BuiltInClass, Number, "").(Class) +var Float = New(BuiltInClass, Number, "").(Class) +var SeriousCondition = New(BuiltInClass, Object, "").(Class) +var Error = New(BuiltInClass, SeriousCondition, "").(Class) +var ArithmeticError = New(BuiltInClass, Error, "").(Class) +var DivisionByZero = New(BuiltInClass, ArithmeticError, "").(Class) +var FloatingPointOnderflow = New(BuiltInClass, ArithmeticError, "").(Class) +var FloatingPointUnderflow = New(BuiltInClass, ArithmeticError, "").(Class) +var ControlError = New(BuiltInClass, Error, "").(Class) +var ParseError = New(BuiltInClass, Error, "").(Class) +var ProgramError = New(BuiltInClass, Error, "").(Class) +var DomainError = New(BuiltInClass, ProgramError, "").(Class) +var UndefinedEntity = New(BuiltInClass, ProgramError, "").(Class) +var UndefinedVariable = New(BuiltInClass, UndefinedEntity, "").(Class) +var UndefinedFunction = New(BuiltInClass, UndefinedEntity, "").(Class) +var SimpleError = New(BuiltInClass, Error, "").(Class) +var StreamError = New(BuiltInClass, Error, "").(Class) +var EndOfStream = New(BuiltInClass, StreamError, "").(Class) +var StorageExhausted = New(BuiltInClass, SeriousCondition, "").(Class) +var StandardObject = New(BuiltInClass, Object, "").(Class) +var Stream = New(BuiltInClass, Object, "").(Class) diff --git a/core/class/class.go b/core/class/class.go index 9837940..f4aaa29 100644 --- a/core/class/class.go +++ b/core/class/class.go @@ -1,11 +1,17 @@ package class type Class interface { + // For Instance interface + Class() Class + Value() Value + IsInstanceOf(Class) bool ToString() string + // Class main interface Parents() []Class New(...Value) Instance } +// Test function for IsInstanceOf func test(child Class, parent Class) bool { if child == parent { return true @@ -21,116 +27,3 @@ func test(child Class, parent Class) bool { func New(class Class, value ...Value) Instance { return class.New(value...) } - -type meta struct { - name string -} - -func (m *meta) ToString() string { - return m.name -} - -func (*meta) Parents() []Class { - return []Class{Object} -} - -func (*meta) Class() Class { - return BuiltInClass -} - -func (m *meta) Value() Value { - return m -} - -func (m *meta) New(value ...Value) Instance { - return &builtin{[]Class{value[0].(Class)}, value[1].(string)} -} - -func (m *meta) IsInstanceOf(class Class) bool { - if m.Class() == class { - return true - } - for _, p := range m.Class().Parents() { - if test(p, class) { - return true - } - } - return false -} - -type builtin struct { - parents []Class - name string -} - -func (c *builtin) ToString() string { - return c.name -} - -func (c *builtin) Parents() []Class { - return c.parents -} - -func (c *builtin) Class() Class { - return BuiltInClass -} - -func (c *builtin) Value() Value { - return c -} - -func (c *builtin) New(value ...Value) Instance { - return &defaultInstance{c, value[0]} -} - -func (c *builtin) IsInstanceOf(class Class) bool { - if c == class { - return true - } - for _, p := range c.Class().Parents() { - if test(p, class) { - return true - } - } - return false -} - -var Object = &builtin{[]Class{}, ""} -var BasicArray = New(BuiltInClass, Object, "").(Class) -var BasicArrayStar = New(BuiltInClass, BasicArray, "").(Class) -var GeneralArrayStar = New(BuiltInClass, BasicArrayStar, "").(Class) -var BasicVector = New(BuiltInClass, BasicArray, "").(Class) -var GeneraVector = New(BuiltInClass, BasicVector, "").(Class) -var String = New(BuiltInClass, BasicVector, "").(Class) -var BuiltInClass = &meta{""} -var Character = New(BuiltInClass, Object, "").(Class) -var Function = New(BuiltInClass, Object, "").(Class) -var GenericFunction = New(BuiltInClass, Function, "").(Class) -var StandardGenericFunction = New(BuiltInClass, GenericFunction, "").(Class) -var List = New(BuiltInClass, Object, "").(Class) -var Cons = New(BuiltInClass, List, "").(Class) -var Null = New(BuiltInClass, List, "").(Class) -var Symbol = New(BuiltInClass, Object, "").(Class) -var Number = New(BuiltInClass, Object, "").(Class) -var Integer = New(BuiltInClass, Number, "").(Class) -var Float = New(BuiltInClass, Number, "").(Class) -var SeriousCondition = New(BuiltInClass, Object, "").(Class) -var Error = New(BuiltInClass, SeriousCondition, "").(Class) -var ArithmeticError = New(BuiltInClass, Error, "").(Class) -var DivisionByZero = New(BuiltInClass, ArithmeticError, "").(Class) -var FloatingPointOnderflow = New(BuiltInClass, ArithmeticError, "").(Class) -var FloatingPointUnderflow = New(BuiltInClass, ArithmeticError, "").(Class) -var ControlError = New(BuiltInClass, Error, "").(Class) -var ParseError = New(BuiltInClass, Error, "").(Class) -var ProgramError = New(BuiltInClass, Error, "").(Class) -var DomainError = New(BuiltInClass, ProgramError, "").(Class) -var UndefinedEntity = New(BuiltInClass, ProgramError, "").(Class) -var UndefinedVariable = New(BuiltInClass, UndefinedEntity, "").(Class) -var UndefinedFunction = New(BuiltInClass, UndefinedEntity, "").(Class) -var SimpleError = New(BuiltInClass, Error, "").(Class) -var StreamError = New(BuiltInClass, Error, "").(Class) -var EndOfStream = New(BuiltInClass, StreamError, "").(Class) -var StorageExhausted = New(BuiltInClass, SeriousCondition, "").(Class) -var StandardClass = &meta{""} -var StandardObject = New(BuiltInClass, Object, "").(Class) -var Stream = New(BuiltInClass, Object, "").(Class) diff --git a/core/class/instance.go b/core/class/instance.go index a83d99d..c477d4b 100644 --- a/core/class/instance.go +++ b/core/class/instance.go @@ -7,6 +7,7 @@ type Instance interface { Class() Class Value() Value IsInstanceOf(Class) bool + ToString() string } type defaultInstance struct { @@ -33,3 +34,7 @@ func (i *defaultInstance) IsInstanceOf(class Class) bool { } return false } + +func (i *defaultInstance) ToString() string { + return "" +} diff --git a/core/class/meta.go b/core/class/meta.go new file mode 100644 index 0000000..31c220f --- /dev/null +++ b/core/class/meta.go @@ -0,0 +1,40 @@ +package class + +type meta struct { + name string +} + +func (m *meta) ToString() string { + return m.name +} + +func (*meta) Parents() []Class { + return []Class{Object} +} + +func (*meta) Class() Class { + return BuiltInClass +} + +func (m *meta) Value() Value { + return m +} + +func (m *meta) New(value ...Value) Instance { + return &builtin{[]Class{value[0].(Class)}, value[1].(string)} +} + +func (m *meta) IsInstanceOf(class Class) bool { + if m.Class() == class { + return true + } + for _, p := range m.Class().Parents() { + if test(p, class) { + return true + } + } + return false +} + +var BuiltInClass = &meta{""} +var StandardClass = &meta{""} From d62f47c67818fae65b59fc8fbe229a59d149e847 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Sun, 30 Jul 2017 17:34:03 +0900 Subject: [PATCH 067/228] Rename core to runtime --- reader/parser/parser.go | 4 ++-- reader/parser/parser_test.go | 2 +- reader/tokenizer/tokenizer.go | 2 +- {core => runtime}/class/builtin.go | 0 {core => runtime}/class/class.go | 0 {core => runtime}/class/cons/cons.go | 2 +- {core => runtime}/class/domain-error/domain-error.go | 2 +- {core => runtime}/class/function/function.go | 4 ++-- {core => runtime}/class/instance.go | 0 {core => runtime}/class/meta.go | 0 {core => runtime}/environment/environment.go | 2 +- {core => runtime}/eval.go | 10 +++++----- {core => runtime}/eval_test.go | 8 ++++---- {core => runtime}/init.go | 8 ++++---- {core => runtime}/lambda.go | 8 ++++---- {core => runtime}/native.go | 6 +++--- 16 files changed, 29 insertions(+), 29 deletions(-) rename {core => runtime}/class/builtin.go (100%) rename {core => runtime}/class/class.go (100%) rename {core => runtime}/class/cons/cons.go (95%) rename {core => runtime}/class/domain-error/domain-error.go (73%) rename {core => runtime}/class/function/function.go (84%) rename {core => runtime}/class/instance.go (100%) rename {core => runtime}/class/meta.go (100%) rename {core => runtime}/environment/environment.go (98%) rename {core => runtime}/eval.go (93%) rename {core => runtime}/eval_test.go (93%) rename {core => runtime}/init.go (78%) rename {core => runtime}/lambda.go (91%) rename {core => runtime}/native.go (83%) diff --git a/reader/parser/parser.go b/reader/parser/parser.go index 9710a26..fa7ad8f 100644 --- a/reader/parser/parser.go +++ b/reader/parser/parser.go @@ -6,9 +6,9 @@ import ( "strconv" "strings" - "github.com/ta2gch/gazelle/core/class" - "github.com/ta2gch/gazelle/core/class/cons" "github.com/ta2gch/gazelle/reader/tokenizer" + "github.com/ta2gch/gazelle/runtime/class" + "github.com/ta2gch/gazelle/runtime/class/cons" ) var eop = class.New(class.Object, "End Of Parentheses") diff --git a/reader/parser/parser_test.go b/reader/parser/parser_test.go index 982477f..ccb6c64 100644 --- a/reader/parser/parser_test.go +++ b/reader/parser/parser_test.go @@ -4,7 +4,7 @@ import ( "reflect" "testing" - "github.com/ta2gch/gazelle/core/class" + "github.com/ta2gch/gazelle/runtime/class" ) func Test_parseAtom(t *testing.T) { diff --git a/reader/tokenizer/tokenizer.go b/reader/tokenizer/tokenizer.go index a8c18b8..291a7aa 100644 --- a/reader/tokenizer/tokenizer.go +++ b/reader/tokenizer/tokenizer.go @@ -5,7 +5,7 @@ import ( "regexp" "strings" - "github.com/ta2gch/gazelle/core/class" + "github.com/ta2gch/gazelle/runtime/class" ) // Tokenizer interface type is the interface diff --git a/core/class/builtin.go b/runtime/class/builtin.go similarity index 100% rename from core/class/builtin.go rename to runtime/class/builtin.go diff --git a/core/class/class.go b/runtime/class/class.go similarity index 100% rename from core/class/class.go rename to runtime/class/class.go diff --git a/core/class/cons/cons.go b/runtime/class/cons/cons.go similarity index 95% rename from core/class/cons/cons.go rename to runtime/class/cons/cons.go index e1ce032..346f42b 100644 --- a/core/class/cons/cons.go +++ b/runtime/class/cons/cons.go @@ -1,7 +1,7 @@ package cons import ( - "github.com/ta2gch/gazelle/core/class" + "github.com/ta2gch/gazelle/runtime/class" ) // Cell is a pair of pointers to Object diff --git a/core/class/domain-error/domain-error.go b/runtime/class/domain-error/domain-error.go similarity index 73% rename from core/class/domain-error/domain-error.go rename to runtime/class/domain-error/domain-error.go index 248a4d8..fb4ff4b 100644 --- a/core/class/domain-error/domain-error.go +++ b/runtime/class/domain-error/domain-error.go @@ -1,7 +1,7 @@ package domainerror import ( - "github.com/ta2gch/gazelle/core/class" + "github.com/ta2gch/gazelle/runtime/class" ) type DomainError struct { diff --git a/core/class/function/function.go b/runtime/class/function/function.go similarity index 84% rename from core/class/function/function.go rename to runtime/class/function/function.go index 6e84789..d650dad 100644 --- a/core/class/function/function.go +++ b/runtime/class/function/function.go @@ -1,8 +1,8 @@ package function import ( - "github.com/ta2gch/gazelle/core/class" - env "github.com/ta2gch/gazelle/core/environment" + "github.com/ta2gch/gazelle/runtime/class" + env "github.com/ta2gch/gazelle/runtime/environment" ) type Function interface { diff --git a/core/class/instance.go b/runtime/class/instance.go similarity index 100% rename from core/class/instance.go rename to runtime/class/instance.go diff --git a/core/class/meta.go b/runtime/class/meta.go similarity index 100% rename from core/class/meta.go rename to runtime/class/meta.go diff --git a/core/environment/environment.go b/runtime/environment/environment.go similarity index 98% rename from core/environment/environment.go rename to runtime/environment/environment.go index 8f401a1..d1e00fb 100644 --- a/core/environment/environment.go +++ b/runtime/environment/environment.go @@ -1,7 +1,7 @@ package environment import ( - "github.com/ta2gch/gazelle/core/class" + "github.com/ta2gch/gazelle/runtime/class" ) // Environment struct is the struct for keeping functions and variables diff --git a/core/eval.go b/runtime/eval.go similarity index 93% rename from core/eval.go rename to runtime/eval.go index 5b2ce89..26d582c 100644 --- a/core/eval.go +++ b/runtime/eval.go @@ -1,10 +1,10 @@ -package core +package runtime import ( - "github.com/ta2gch/gazelle/core/class" - "github.com/ta2gch/gazelle/core/class/cons" - "github.com/ta2gch/gazelle/core/class/function" - env "github.com/ta2gch/gazelle/core/environment" + "github.com/ta2gch/gazelle/runtime/class" + "github.com/ta2gch/gazelle/runtime/class/cons" + "github.com/ta2gch/gazelle/runtime/class/function" + env "github.com/ta2gch/gazelle/runtime/environment" ) func evalArguments(args class.Instance, local *env.Environment, global *env.Environment) (class.Instance, class.Instance) { diff --git a/core/eval_test.go b/runtime/eval_test.go similarity index 93% rename from core/eval_test.go rename to runtime/eval_test.go index 3013b04..118d3cd 100644 --- a/core/eval_test.go +++ b/runtime/eval_test.go @@ -1,13 +1,13 @@ -package core +package runtime import ( "reflect" "strings" "testing" - "github.com/ta2gch/gazelle/core/class" - "github.com/ta2gch/gazelle/core/class/cons" - env "github.com/ta2gch/gazelle/core/environment" + "github.com/ta2gch/gazelle/runtime/class" + "github.com/ta2gch/gazelle/runtime/class/cons" + env "github.com/ta2gch/gazelle/runtime/environment" "github.com/ta2gch/gazelle/reader/parser" "github.com/ta2gch/gazelle/reader/tokenizer" ) diff --git a/core/init.go b/runtime/init.go similarity index 78% rename from core/init.go rename to runtime/init.go index d6b30ad..5ce15af 100644 --- a/core/init.go +++ b/runtime/init.go @@ -1,9 +1,9 @@ -package core +package runtime import ( - "github.com/ta2gch/gazelle/core/class" - "github.com/ta2gch/gazelle/core/class/cons" - env "github.com/ta2gch/gazelle/core/environment" + "github.com/ta2gch/gazelle/runtime/class" + "github.com/ta2gch/gazelle/runtime/class/cons" + env "github.com/ta2gch/gazelle/runtime/environment" ) func init() { diff --git a/core/lambda.go b/runtime/lambda.go similarity index 91% rename from core/lambda.go rename to runtime/lambda.go index 7581e82..f51974d 100644 --- a/core/lambda.go +++ b/runtime/lambda.go @@ -1,9 +1,9 @@ -package core +package runtime import ( - "github.com/ta2gch/gazelle/core/class" - "github.com/ta2gch/gazelle/core/class/cons" - env "github.com/ta2gch/gazelle/core/environment" + "github.com/ta2gch/gazelle/runtime/class" + "github.com/ta2gch/gazelle/runtime/class/cons" + env "github.com/ta2gch/gazelle/runtime/environment" ) type LambdaFunction struct { diff --git a/core/native.go b/runtime/native.go similarity index 83% rename from core/native.go rename to runtime/native.go index 54f302b..7877c74 100644 --- a/core/native.go +++ b/runtime/native.go @@ -1,8 +1,8 @@ -package core +package runtime import ( - "github.com/ta2gch/gazelle/core/class" - env "github.com/ta2gch/gazelle/core/environment" + "github.com/ta2gch/gazelle/runtime/class" + env "github.com/ta2gch/gazelle/runtime/environment" ) type NativeFunction struct { From 948d8f9099a5c08cbe8f6e98760b2deed0ce5f82 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Sun, 30 Jul 2017 18:36:12 +0900 Subject: [PATCH 068/228] Added String() --- runtime/class/builtin.go | 12 ++---------- runtime/class/class.go | 14 +++++++++++++- runtime/class/cons/cons.go | 6 ++++++ runtime/class/instance.go | 20 ++++++++------------ runtime/class/meta.go | 12 ++---------- 5 files changed, 31 insertions(+), 33 deletions(-) diff --git a/runtime/class/builtin.go b/runtime/class/builtin.go index f21d672..f500860 100644 --- a/runtime/class/builtin.go +++ b/runtime/class/builtin.go @@ -5,7 +5,7 @@ type builtin struct { name string } -func (c *builtin) ToString() string { +func (c *builtin) String() string { return c.name } @@ -26,15 +26,7 @@ func (c *builtin) New(value ...Value) Instance { } func (c *builtin) IsInstanceOf(class Class) bool { - if c == class { - return true - } - for _, p := range c.Class().Parents() { - if test(p, class) { - return true - } - } - return false + return isInstanceOf(c, class) } var Object = &builtin{[]Class{}, ""} diff --git a/runtime/class/class.go b/runtime/class/class.go index f4aaa29..2749d15 100644 --- a/runtime/class/class.go +++ b/runtime/class/class.go @@ -5,7 +5,7 @@ type Class interface { Class() Class Value() Value IsInstanceOf(Class) bool - ToString() string + String() string // Class main interface Parents() []Class New(...Value) Instance @@ -24,6 +24,18 @@ func test(child Class, parent Class) bool { return false } +func isInstanceOf(i Instance, class Class) bool { + if i.Class() == class { + return true + } + for _, p := range i.Class().Parents() { + if test(p, class) { + return true + } + } + return false +} + func New(class Class, value ...Value) Instance { return class.New(value...) } diff --git a/runtime/class/cons/cons.go b/runtime/class/cons/cons.go index 346f42b..55d21fb 100644 --- a/runtime/class/cons/cons.go +++ b/runtime/class/cons/cons.go @@ -1,6 +1,8 @@ package cons import ( + "fmt" + "github.com/ta2gch/gazelle/runtime/class" ) @@ -42,3 +44,7 @@ func Length(list class.Instance) (int, class.Instance) { } return 1 + len, nil } + +func (c *Cell) String() string { + return fmt.Sprintf("(%v . %v)", c.car, c.cdr) +} diff --git a/runtime/class/instance.go b/runtime/class/instance.go index c477d4b..e231989 100644 --- a/runtime/class/instance.go +++ b/runtime/class/instance.go @@ -1,5 +1,9 @@ package class +import ( + "fmt" +) + type Value interface{} // Instance struct type is the struct for the internal representations @@ -7,7 +11,7 @@ type Instance interface { Class() Class Value() Value IsInstanceOf(Class) bool - ToString() string + String() string } type defaultInstance struct { @@ -24,17 +28,9 @@ func (i *defaultInstance) Value() Value { } func (i *defaultInstance) IsInstanceOf(class Class) bool { - if i.Class() == class { - return true - } - for _, p := range i.Class().Parents() { - if test(p, class) { - return true - } - } - return false + return isInstanceOf(i, class) } -func (i *defaultInstance) ToString() string { - return "" +func (i *defaultInstance) String() string { + return fmt.Sprintf("%v", i.Value()) } diff --git a/runtime/class/meta.go b/runtime/class/meta.go index 31c220f..86d28f2 100644 --- a/runtime/class/meta.go +++ b/runtime/class/meta.go @@ -4,7 +4,7 @@ type meta struct { name string } -func (m *meta) ToString() string { +func (m *meta) String() string { return m.name } @@ -25,15 +25,7 @@ func (m *meta) New(value ...Value) Instance { } func (m *meta) IsInstanceOf(class Class) bool { - if m.Class() == class { - return true - } - for _, p := range m.Class().Parents() { - if test(p, class) { - return true - } - } - return false + return isInstanceOf(m, class) } var BuiltInClass = &meta{""} From e9d91ab6d6db2aa8c19c46cfba38eb739f6da27f Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Sun, 30 Jul 2017 21:58:19 +0900 Subject: [PATCH 069/228] simplify class system --- reader/parser/parser.go | 48 +++++++------- reader/parser/parser_test.go | 32 +++++----- runtime/class/builtin.go | 74 +++++++++++----------- runtime/class/class.go | 2 +- runtime/class/cons/cons.go | 38 +++++++---- runtime/class/domain-error/domain-error.go | 10 --- runtime/class/domainerror/domainerror.go | 32 ++++++++++ runtime/class/function/function.go | 3 +- runtime/class/instance.go | 2 +- runtime/class/meta.go | 2 +- runtime/class/parseerror/parseerror.go | 32 ++++++++++ runtime/eval.go | 4 +- runtime/eval_test.go | 26 ++++---- runtime/init.go | 6 +- runtime/lambda.go | 4 +- runtime/native.go | 2 +- 16 files changed, 194 insertions(+), 123 deletions(-) delete mode 100644 runtime/class/domain-error/domain-error.go create mode 100644 runtime/class/domainerror/domainerror.go create mode 100644 runtime/class/parseerror/parseerror.go diff --git a/reader/parser/parser.go b/reader/parser/parser.go index fa7ad8f..3d51893 100644 --- a/reader/parser/parser.go +++ b/reader/parser/parser.go @@ -11,8 +11,8 @@ import ( "github.com/ta2gch/gazelle/runtime/class/cons" ) -var eop = class.New(class.Object, "End Of Parentheses") -var bod = class.New(class.Object, "Begin Of Dot") +var eop = class.Object.New("End Of Parentheses") +var bod = class.Object.New("Begin Of Dot") func parseAtom(tok string) (class.Instance, class.Instance) { // @@ -20,64 +20,64 @@ func parseAtom(tok string) (class.Instance, class.Instance) { // if m, _ := regexp.MatchString("^[-+]?[[:digit:]]+$", tok); m { n, _ := strconv.ParseInt(tok, 10, 64) - return class.New(class.Integer, int(n)), nil + return class.Integer.New(int(n)), nil } if r := regexp.MustCompile("^#[bB]([-+]?[01]+)$").FindStringSubmatch(tok); len(r) >= 2 { n, _ := strconv.ParseInt(r[1], 2, 64) - return class.New(class.Integer, int(n)), nil + return class.Integer.New(int(n)), nil } if r := regexp.MustCompile("^#[oO]([-+]?[0-7]+)$").FindStringSubmatch(tok); len(r) >= 2 { n, _ := strconv.ParseInt(r[1], 8, 64) - return class.New(class.Integer, int(n)), nil + return class.Integer.New(int(n)), nil } if r := regexp.MustCompile("^#[xX]([-+]?[[:xdigit:]]+)$").FindStringSubmatch(tok); len(r) >= 2 { n, _ := strconv.ParseInt(r[1], 16, 64) - return class.New(class.Integer, int(n)), nil + return class.Integer.New(int(n)), nil } // // float // if m, _ := regexp.MatchString("^[-+]?[[:digit:]]+\\.[[:digit:]]+$", tok); m { n, _ := strconv.ParseFloat(tok, 64) - return class.New(class.Float, n), nil + return class.Float.New(n), nil } if r := regexp.MustCompile("^([-+]?[[:digit:]]+(?:\\.[[:digit:]]+)?)[eE]([-+]?[[:digit:]]+)$").FindStringSubmatch(tok); len(r) >= 3 { n, _ := strconv.ParseFloat(r[1], 64) e, _ := strconv.ParseInt(r[2], 10, 64) - return class.New(class.Float, n*math.Pow10(int(e))), nil + return class.Float.New(n * math.Pow10(int(e))), nil } // // character // if m, _ := regexp.MatchString("^#\\\\newline$", tok); m { - return class.New(class.Character, '\n'), nil + return class.Character.New('\n'), nil } if m, _ := regexp.MatchString("^#\\\\space$", tok); m { - return class.New(class.Character, ' '), nil + return class.Character.New(' '), nil } if r := regexp.MustCompile("^#\\\\([[:graph:]])$").FindStringSubmatch(tok); len(r) >= 2 { - return class.New(class.Character, rune(r[1][0])), nil + return class.Character.New(rune(r[1][0])), nil } // // string // if m, _ := regexp.MatchString("^\".*\"$", tok); m { - return class.New(class.String, tok), nil + return class.String.New(tok), nil } // // symbol // if "nil" == tok { - return class.New(class.Null, nil), nil + return class.Null.New(nil), nil } if r := regexp.MustCompile("^:([<>/*=?_!$%[\\]^{}~0-9a-zA-Z]+)$").FindStringSubmatch(tok); len(r) >= 2 { - return class.New(class.Symbol, r[1]), nil + return class.Symbol.New(r[1]), nil } if m, _ := regexp.MatchString("^\\|.*\\|$", tok); m { - return class.New(class.Symbol, tok), nil + return class.Symbol.New(tok), nil } if m, _ := regexp.MatchString("^[<>/*=?_!$%[\\]^{}~a-zA-Z][<>/*=?_!$%[\\]^{}~0-9a-zA-Z]*$", tok); m { - return class.New(class.Symbol, tok), nil + return class.Symbol.New(tok), nil } return nil, class.New(class.ParseError, nil) } @@ -89,18 +89,18 @@ func parseMacro(tok string, t *tokenizer.Tokenizer) (class.Instance, class.Insta } n := tok if m, _ := regexp.MatchString("#[[:digit:]]*[aA]", tok); m { - s := class.New(class.Symbol, "array") + s := class.Symbol.New("array") i := strings.IndexRune(strings.ToLower(tok), 'a') if i == 1 { - d := class.New(class.Integer, 1) - return cons.New(s, cons.New(d, cons.New(cdr, class.New(class.Null, nil)))), nil + d := class.Integer.New(1) + return cons.New(s, cons.New(d, cons.New(cdr, class.Null.New(nil)))), nil } v, err := strconv.ParseInt(tok[1:i], 10, 32) if err != nil { return nil, class.New(class.ParseError, nil) } - d := class.New(class.Integer, int(v)) - return cons.New(s, cons.New(d, cons.New(cdr, class.New(class.Null, nil)))), nil + d := class.Integer.New(int(v)) + return cons.New(s, cons.New(d, cons.New(cdr, class.Null.New(nil)))), nil } switch tok { case ",@": @@ -112,13 +112,13 @@ func parseMacro(tok string, t *tokenizer.Tokenizer) (class.Instance, class.Insta case "`": n = "backquote" } - m := class.New(class.Symbol, n) - return cons.New(m, cons.New(cdr, class.New(class.Null, nil))), nil + m := class.Symbol.New(n) + return cons.New(m, cons.New(cdr, class.Null.New(nil))), nil } func parseCons(t *tokenizer.Tokenizer) (class.Instance, class.Instance) { car, err := Parse(t) if err == eop { - return class.New(class.Null, nil), nil + return class.Null.New(nil), nil } if err == bod { cdr, err := Parse(t) diff --git a/reader/parser/parser_test.go b/reader/parser/parser_test.go index ccb6c64..67a242f 100644 --- a/reader/parser/parser_test.go +++ b/reader/parser/parser_test.go @@ -23,31 +23,31 @@ func Test_parseAtom(t *testing.T) { { name: "default", args: args{"3.14"}, - want: class.New(class.Float, 3.14), + want: class.Float.New(3.14), wantErr: false, }, { name: "signed", args: args{"-5.0"}, - want: class.New(class.Float, -5.0), + want: class.Float.New(-5.0), wantErr: false, }, { name: "exponential", args: args{"-5.0E3"}, - want: class.New(class.Float, -5.0*1000), + want: class.Float.New(-5.0 * 1000), wantErr: false, }, { name: "signed exponential", args: args{"5.0E-3"}, - want: class.New(class.Float, 5.0*1.0/1000.0), + want: class.Float.New(5.0 * 1.0 / 1000.0), wantErr: false, }, { name: "without point", args: args{"5E-3"}, - want: class.New(class.Float, 5.0*1.0/1000.0), + want: class.Float.New(5.0 * 1.0 / 1000.0), wantErr: false, }, { @@ -68,49 +68,49 @@ func Test_parseAtom(t *testing.T) { { name: "default", args: args{"5"}, - want: class.New(class.Integer, 5), + want: class.Integer.New(5), wantErr: false, }, { name: "signed", args: args{"-5"}, - want: class.New(class.Integer, -5), + want: class.Integer.New(-5), wantErr: false, }, { name: "binary", args: args{"#B00101"}, - want: class.New(class.Integer, 5), + want: class.Integer.New(5), wantErr: false, }, { name: "signed binary", args: args{"#b+00101"}, - want: class.New(class.Integer, 5), + want: class.Integer.New(5), wantErr: false, }, { name: "octal", args: args{"#o00101"}, - want: class.New(class.Integer, 65), + want: class.Integer.New(65), wantErr: false, }, { name: "signed octal", args: args{"#O-00101"}, - want: class.New(class.Integer, -65), + want: class.Integer.New(-65), wantErr: false, }, { name: "hexadecimal", args: args{"#X00101"}, - want: class.New(class.Integer, 257), + want: class.Integer.New(257), wantErr: false, }, { name: "signed hexadecimal", args: args{"#x-00101"}, - want: class.New(class.Integer, -257), + want: class.Integer.New(-257), wantErr: false, }, { @@ -125,19 +125,19 @@ func Test_parseAtom(t *testing.T) { { name: "default", args: args{"#\\a"}, - want: class.New(class.Character, 'a'), + want: class.Character.New('a'), wantErr: false, }, { name: "newline", args: args{"#\\newline"}, - want: class.New(class.Character, '\n'), + want: class.Character.New('\n'), wantErr: false, }, { name: "space", args: args{"#\\space"}, - want: class.New(class.Character, ' '), + want: class.Character.New(' '), wantErr: false, }, { diff --git a/runtime/class/builtin.go b/runtime/class/builtin.go index f500860..1eb3247 100644 --- a/runtime/class/builtin.go +++ b/runtime/class/builtin.go @@ -26,43 +26,43 @@ func (c *builtin) New(value ...Value) Instance { } func (c *builtin) IsInstanceOf(class Class) bool { - return isInstanceOf(c, class) + return IsInstanceOf(c, class) } var Object = &builtin{[]Class{}, ""} -var BasicArray = New(BuiltInClass, Object, "").(Class) -var BasicArrayStar = New(BuiltInClass, BasicArray, "").(Class) -var GeneralArrayStar = New(BuiltInClass, BasicArrayStar, "").(Class) -var BasicVector = New(BuiltInClass, BasicArray, "").(Class) -var GeneraVector = New(BuiltInClass, BasicVector, "").(Class) -var String = New(BuiltInClass, BasicVector, "").(Class) -var Character = New(BuiltInClass, Object, "").(Class) -var Function = New(BuiltInClass, Object, "").(Class) -var GenericFunction = New(BuiltInClass, Function, "").(Class) -var StandardGenericFunction = New(BuiltInClass, GenericFunction, "").(Class) -var List = New(BuiltInClass, Object, "").(Class) -var Cons = New(BuiltInClass, List, "").(Class) -var Null = New(BuiltInClass, List, "").(Class) -var Symbol = New(BuiltInClass, Object, "").(Class) -var Number = New(BuiltInClass, Object, "").(Class) -var Integer = New(BuiltInClass, Number, "").(Class) -var Float = New(BuiltInClass, Number, "").(Class) -var SeriousCondition = New(BuiltInClass, Object, "").(Class) -var Error = New(BuiltInClass, SeriousCondition, "").(Class) -var ArithmeticError = New(BuiltInClass, Error, "").(Class) -var DivisionByZero = New(BuiltInClass, ArithmeticError, "").(Class) -var FloatingPointOnderflow = New(BuiltInClass, ArithmeticError, "").(Class) -var FloatingPointUnderflow = New(BuiltInClass, ArithmeticError, "").(Class) -var ControlError = New(BuiltInClass, Error, "").(Class) -var ParseError = New(BuiltInClass, Error, "").(Class) -var ProgramError = New(BuiltInClass, Error, "").(Class) -var DomainError = New(BuiltInClass, ProgramError, "").(Class) -var UndefinedEntity = New(BuiltInClass, ProgramError, "").(Class) -var UndefinedVariable = New(BuiltInClass, UndefinedEntity, "").(Class) -var UndefinedFunction = New(BuiltInClass, UndefinedEntity, "").(Class) -var SimpleError = New(BuiltInClass, Error, "").(Class) -var StreamError = New(BuiltInClass, Error, "").(Class) -var EndOfStream = New(BuiltInClass, StreamError, "").(Class) -var StorageExhausted = New(BuiltInClass, SeriousCondition, "").(Class) -var StandardObject = New(BuiltInClass, Object, "").(Class) -var Stream = New(BuiltInClass, Object, "").(Class) +var BasicArray = BuiltInClass.New(Object, "").(Class) +var BasicArrayStar = BuiltInClass.New(BasicArray, "").(Class) +var GeneralArrayStar = BuiltInClass.New(BasicArrayStar, "").(Class) +var BasicVector = BuiltInClass.New(BasicArray, "").(Class) +var GeneraVector = BuiltInClass.New(BasicVector, "").(Class) +var String = BuiltInClass.New(BasicVector, "").(Class) +var Character = BuiltInClass.New(Object, "").(Class) +var Function = BuiltInClass.New(Object, "").(Class) +var GenericFunction = BuiltInClass.New(Function, "").(Class) +var StandardGenericFunction = BuiltInClass.New(GenericFunction, "").(Class) +var List = BuiltInClass.New(Object, "").(Class) +var Cons = BuiltInClass.New(List, "").(Class) +var Null = BuiltInClass.New(List, "").(Class) +var Symbol = BuiltInClass.New(Object, "").(Class) +var Number = BuiltInClass.New(Object, "").(Class) +var Integer = BuiltInClass.New(Number, "").(Class) +var Float = BuiltInClass.New(Number, "").(Class) +var SeriousCondition = BuiltInClass.New(Object, "").(Class) +var Error = BuiltInClass.New(SeriousCondition, "").(Class) +var ArithmeticError = BuiltInClass.New(Error, "").(Class) +var DivisionByZero = BuiltInClass.New(ArithmeticError, "").(Class) +var FloatingPointOnderflow = BuiltInClass.New(ArithmeticError, "").(Class) +var FloatingPointUnderflow = BuiltInClass.New(ArithmeticError, "").(Class) +var ControlError = BuiltInClass.New(Error, "").(Class) +var ParseError = BuiltInClass.New(Error, "").(Class) +var ProgramError = BuiltInClass.New(Error, "").(Class) +var DomainError = BuiltInClass.New(ProgramError, "").(Class) +var UndefinedEntity = BuiltInClass.New(ProgramError, "").(Class) +var UndefinedVariable = BuiltInClass.New(UndefinedEntity, "").(Class) +var UndefinedFunction = BuiltInClass.New(UndefinedEntity, "").(Class) +var SimpleError = BuiltInClass.New(Error, "").(Class) +var StreamError = BuiltInClass.New(Error, "").(Class) +var EndOfStream = BuiltInClass.New(StreamError, "").(Class) +var StorageExhausted = BuiltInClass.New(SeriousCondition, "").(Class) +var StandardObject = BuiltInClass.New(Object, "").(Class) +var Stream = BuiltInClass.New(Object, "").(Class) diff --git a/runtime/class/class.go b/runtime/class/class.go index 2749d15..e7a2d82 100644 --- a/runtime/class/class.go +++ b/runtime/class/class.go @@ -24,7 +24,7 @@ func test(child Class, parent Class) bool { return false } -func isInstanceOf(i Instance, class Class) bool { +func IsInstanceOf(i Instance, class Class) bool { if i.Class() == class { return true } diff --git a/runtime/class/cons/cons.go b/runtime/class/cons/cons.go index 55d21fb..ecc84bf 100644 --- a/runtime/class/cons/cons.go +++ b/runtime/class/cons/cons.go @@ -4,33 +4,53 @@ import ( "fmt" "github.com/ta2gch/gazelle/runtime/class" + "github.com/ta2gch/gazelle/runtime/class/domainerror" ) // Cell is a pair of pointers to Object -type Cell struct { +type cons struct { car class.Instance cdr class.Instance } func New(car class.Instance, cdr class.Instance) class.Instance { - return class.New(class.Cons, Cell{car, cdr}) + return cons{car, cdr} +} + +func (c cons) Class() class.Class { + return class.Cons +} + +func (c cons) Value() class.Value { + return c +} + +func (c cons) IsInstanceOf(cls class.Class) bool { + return class.IsInstanceOf(c, cls) +} + +func (c cons) String() string { + return fmt.Sprintf("(%v . %v)", c.car, c.cdr) } func Car(i class.Instance) (class.Instance, class.Instance) { - if !i.IsInstanceOf(class.List) { - return nil, class.New(class.DomainError, nil) + if i.IsInstanceOf(class.Null) || !i.IsInstanceOf(class.List) { + return nil, domainerror.New(i, class.Cons) } - return i.Value().(Cell).car, nil + return i.(cons).car, nil } func Cdr(i class.Instance) (class.Instance, class.Instance) { if i.IsInstanceOf(class.Null) || !i.IsInstanceOf(class.List) { - return nil, class.New(class.DomainError, nil) + return nil, domainerror.New(i, class.Cons) } - return i.Value().(Cell).cdr, nil + return i.(cons).cdr, nil } func Length(list class.Instance) (int, class.Instance) { + if !list.IsInstanceOf(class.List) { + return 0, domainerror.New(list, class.Cons) + } if list.IsInstanceOf(class.Null) { return 0, nil } @@ -44,7 +64,3 @@ func Length(list class.Instance) (int, class.Instance) { } return 1 + len, nil } - -func (c *Cell) String() string { - return fmt.Sprintf("(%v . %v)", c.car, c.cdr) -} diff --git a/runtime/class/domain-error/domain-error.go b/runtime/class/domain-error/domain-error.go deleted file mode 100644 index fb4ff4b..0000000 --- a/runtime/class/domain-error/domain-error.go +++ /dev/null @@ -1,10 +0,0 @@ -package domainerror - -import ( - "github.com/ta2gch/gazelle/runtime/class" -) - -type DomainError struct { - object class.Instance - expectedClass class.Instance -} diff --git a/runtime/class/domainerror/domainerror.go b/runtime/class/domainerror/domainerror.go new file mode 100644 index 0000000..f0f96e0 --- /dev/null +++ b/runtime/class/domainerror/domainerror.go @@ -0,0 +1,32 @@ +package domainerror + +import ( + "fmt" + + "github.com/ta2gch/gazelle/runtime/class" +) + +type domainerror struct { + object class.Instance + expectedClass class.Class +} + +func New(obj class.Instance, cls class.Class) class.Instance { + return domainerror{obj, cls} +} + +func (e domainerror) Value() class.Value { + return e +} + +func (e domainerror) Class() class.Class { + return class.DomainError +} + +func (e domainerror) IsInstanceOf(cls class.Class) bool { + return class.IsInstanceOf(e, cls) +} + +func (e domainerror) String() string { + return fmt.Sprintf("Domain Error: %v is not a instance of %v", e.object, e.expectedClass) +} diff --git a/runtime/class/function/function.go b/runtime/class/function/function.go index d650dad..79e5e7b 100644 --- a/runtime/class/function/function.go +++ b/runtime/class/function/function.go @@ -2,6 +2,7 @@ package function import ( "github.com/ta2gch/gazelle/runtime/class" + "github.com/ta2gch/gazelle/runtime/class/domainerror" env "github.com/ta2gch/gazelle/runtime/environment" ) @@ -11,7 +12,7 @@ type Function interface { func Apply(fun class.Instance, args class.Instance, local *env.Environment, global *env.Environment) (class.Instance, class.Instance) { if !fun.IsInstanceOf(class.Function) { - return nil, class.New(class.DomainError, nil) + return nil, domainerror.New(fun, class.Function) } obj, err := fun.Value().(Function).Apply(args, local, global) if err != nil { diff --git a/runtime/class/instance.go b/runtime/class/instance.go index e231989..0ebef75 100644 --- a/runtime/class/instance.go +++ b/runtime/class/instance.go @@ -28,7 +28,7 @@ func (i *defaultInstance) Value() Value { } func (i *defaultInstance) IsInstanceOf(class Class) bool { - return isInstanceOf(i, class) + return IsInstanceOf(i, class) } func (i *defaultInstance) String() string { diff --git a/runtime/class/meta.go b/runtime/class/meta.go index 86d28f2..93de327 100644 --- a/runtime/class/meta.go +++ b/runtime/class/meta.go @@ -25,7 +25,7 @@ func (m *meta) New(value ...Value) Instance { } func (m *meta) IsInstanceOf(class Class) bool { - return isInstanceOf(m, class) + return IsInstanceOf(m, class) } var BuiltInClass = &meta{""} diff --git a/runtime/class/parseerror/parseerror.go b/runtime/class/parseerror/parseerror.go new file mode 100644 index 0000000..914ddb3 --- /dev/null +++ b/runtime/class/parseerror/parseerror.go @@ -0,0 +1,32 @@ +package parseerror + +import ( + "fmt" + + "github.com/ta2gch/gazelle/runtime/class" +) + +type parseerror struct { + object class.Instance + expectedClass class.Class +} + +func New(obj class.Instance, cls class.Class) class.Instance { + return parseerror{obj, cls} +} + +func (e parseerror) Value() class.Value { + return e +} + +func (e parseerror) Class() class.Class { + return class.DomainError +} + +func (e parseerror) IsInstanceOf(cls class.Class) bool { + return class.IsInstanceOf(e, cls) +} + +func (e parseerror) String() string { + return fmt.Sprintf("Parse Error: %v is not a instance of %v", e.object, e.expectedClass) +} diff --git a/runtime/eval.go b/runtime/eval.go index 26d582c..0e6267a 100644 --- a/runtime/eval.go +++ b/runtime/eval.go @@ -9,7 +9,7 @@ import ( func evalArguments(args class.Instance, local *env.Environment, global *env.Environment) (class.Instance, class.Instance) { if args.IsInstanceOf(class.Null) { - return class.New(class.Null, nil), nil + return class.Null.New(nil), nil } car, err := cons.Car(args) if err != nil { @@ -113,7 +113,7 @@ func evalFunction(obj class.Instance, local *env.Environment, global *env.Enviro // Eval evaluates any classs func Eval(obj class.Instance, local *env.Environment, global *env.Environment) (class.Instance, class.Instance) { if obj.IsInstanceOf(class.Null) { - return class.New(class.Null, nil), nil + return class.Null.New(nil), nil } if obj.IsInstanceOf(class.Symbol) { if val, ok := local.GetVariable(obj); ok { diff --git a/runtime/eval_test.go b/runtime/eval_test.go index 118d3cd..45648c9 100644 --- a/runtime/eval_test.go +++ b/runtime/eval_test.go @@ -5,11 +5,11 @@ import ( "strings" "testing" + "github.com/ta2gch/gazelle/reader/parser" + "github.com/ta2gch/gazelle/reader/tokenizer" "github.com/ta2gch/gazelle/runtime/class" "github.com/ta2gch/gazelle/runtime/class/cons" env "github.com/ta2gch/gazelle/runtime/environment" - "github.com/ta2gch/gazelle/reader/parser" - "github.com/ta2gch/gazelle/reader/tokenizer" ) func read(s string) class.Instance { @@ -20,16 +20,16 @@ func read(s string) class.Instance { func TestEval(t *testing.T) { local := env.New() global := env.New() - local.SetVariable(class.New(class.Symbol, "pi"), class.New(class.Float, 3.14)) - local.SetFunction(class.New(class.Symbol, "inc"), NewNativeFunction(func(args class.Instance, local *env.Environment, global *env.Environment) (class.Instance, class.Instance) { + local.SetVariable(class.Symbol.New("pi"), class.Float.New(3.14)) + local.SetFunction(class.Symbol.New("inc"), NewNativeFunction(func(args class.Instance, local *env.Environment, global *env.Environment) (class.Instance, class.Instance) { car, _ := cons.Car(args) - return class.New(class.Integer, car.Value().(int)+1), nil + return class.Integer.New(car.Value().(int) + 1), nil })) - local.SetMacro(class.New(class.Symbol, "minc"), NewNativeFunction(func(args class.Instance, local *env.Environment, global *env.Environment) (class.Instance, class.Instance) { - ret, _ := Eval(cons.New(class.New(class.Symbol, "inc"), args), local, global) + local.SetMacro(class.Symbol.New("minc"), NewNativeFunction(func(args class.Instance, local *env.Environment, global *env.Environment) (class.Instance, class.Instance) { + ret, _ := Eval(cons.New(class.Symbol.New("inc"), args), local, global) return ret, nil })) - global.SetMacro(class.New(class.Symbol, "lambda"), NewNativeFunction(func(args class.Instance, local *env.Environment, global *env.Environment) (class.Instance, class.Instance) { + global.SetMacro(class.Symbol.New("lambda"), NewNativeFunction(func(args class.Instance, local *env.Environment, global *env.Environment) (class.Instance, class.Instance) { car, _ := cons.Car(args) cdr, _ := cons.Cdr(args) return NewLambdaFunction(car, cdr, local), nil @@ -47,26 +47,26 @@ func TestEval(t *testing.T) { }{ { name: "local variable", - args: args{class.New(class.Symbol, "pi"), local, global}, - want: class.New(class.Float, 3.14), + args: args{class.Symbol.New("pi"), local, global}, + want: class.Float.New(3.14), wantErr: false, }, { name: "local function", args: args{read("(inc (inc 1))"), local, global}, - want: class.New(class.Integer, 3), + want: class.Integer.New(3), wantErr: false, }, { name: "local macro", args: args{read("(minc (minc 1))"), local, global}, - want: class.New(class.Integer, 3), + want: class.Integer.New(3), wantErr: false, }, { name: "lambda", args: args{read("((lambda (x) (minc x)) 1)"), local, global}, - want: class.New(class.Integer, 2), + want: class.Integer.New(2), wantErr: false, }, } diff --git a/runtime/init.go b/runtime/init.go index 5ce15af..5812e32 100644 --- a/runtime/init.go +++ b/runtime/init.go @@ -7,7 +7,7 @@ import ( ) func init() { - env.TopLevel.SetFunction(class.New(class.Symbol, "functionp"), NewNativeFunction(func(args class.Instance, local *env.Environment, global *env.Environment) (class.Instance, class.Instance) { + env.TopLevel.SetFunction(class.Symbol.New("functionp"), NewNativeFunction(func(args class.Instance, local *env.Environment, global *env.Environment) (class.Instance, class.Instance) { len, err := cons.Length(args) if err != nil { return nil, err @@ -20,8 +20,8 @@ func init() { return nil, err } if car.IsInstanceOf(class.Function) { - return class.New(class.Object, true), nil + return class.Object.New(nil), nil } - return class.New(class.Null, nil), nil + return class.Null.New(nil), nil })) } diff --git a/runtime/lambda.go b/runtime/lambda.go index f51974d..3b978d0 100644 --- a/runtime/lambda.go +++ b/runtime/lambda.go @@ -13,7 +13,7 @@ type LambdaFunction struct { } func NewLambdaFunction(lambdaList class.Instance, forms class.Instance, local *env.Environment) class.Instance { - return class.New(class.Function, LambdaFunction{lambdaList, forms, local}) + return class.Function.New(LambdaFunction{lambdaList, forms, local}) } func (f LambdaFunction) Apply(args class.Instance, local *env.Environment, global *env.Environment) (class.Instance, class.Instance) { @@ -29,7 +29,7 @@ func (f LambdaFunction) Apply(args class.Instance, local *env.Environment, globa if err != nil { return nil, err } - if key == class.New(class.Symbol, ":rest") || key == class.New(class.Symbol, "&rest") { + if key == class.Symbol.New(":rest") || key == class.Symbol.New("&rest") { cdr, err := cons.Cdr(fargs) if err != nil { return nil, err diff --git a/runtime/native.go b/runtime/native.go index 7877c74..4f7c95b 100644 --- a/runtime/native.go +++ b/runtime/native.go @@ -18,5 +18,5 @@ func (f NativeFunction) Apply(args class.Instance, local *env.Environment, globa } func NewNativeFunction(fun func(class.Instance, *env.Environment, *env.Environment) (class.Instance, class.Instance)) class.Instance { - return class.New(class.Function, NativeFunction{fun}) + return class.Function.New(NativeFunction{fun}) } From e9e68ea3682836685443173aa86a3130b0381100 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Sun, 30 Jul 2017 22:21:55 +0900 Subject: [PATCH 070/228] Added ParseError --- reader/parser/parser.go | 5 +++-- reader/tokenizer/tokenizer.go | 3 ++- runtime/class/parseerror/parseerror.go | 8 ++++---- runtime/eval.go | 5 +---- runtime/lambda.go | 3 ++- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/reader/parser/parser.go b/reader/parser/parser.go index 3d51893..b475b99 100644 --- a/reader/parser/parser.go +++ b/reader/parser/parser.go @@ -9,6 +9,7 @@ import ( "github.com/ta2gch/gazelle/reader/tokenizer" "github.com/ta2gch/gazelle/runtime/class" "github.com/ta2gch/gazelle/runtime/class/cons" + "github.com/ta2gch/gazelle/runtime/class/parseerror" ) var eop = class.Object.New("End Of Parentheses") @@ -79,7 +80,7 @@ func parseAtom(tok string) (class.Instance, class.Instance) { if m, _ := regexp.MatchString("^[<>/*=?_!$%[\\]^{}~a-zA-Z][<>/*=?_!$%[\\]^{}~0-9a-zA-Z]*$", tok); m { return class.Symbol.New(tok), nil } - return nil, class.New(class.ParseError, nil) + return nil, parseerror.New(tok, class.Object) } func parseMacro(tok string, t *tokenizer.Tokenizer) (class.Instance, class.Instance) { @@ -97,7 +98,7 @@ func parseMacro(tok string, t *tokenizer.Tokenizer) (class.Instance, class.Insta } v, err := strconv.ParseInt(tok[1:i], 10, 32) if err != nil { - return nil, class.New(class.ParseError, nil) + return nil, parseerror.New(tok, class.Integer) } d := class.Integer.New(int(v)) return cons.New(s, cons.New(d, cons.New(cdr, class.Null.New(nil)))), nil diff --git a/reader/tokenizer/tokenizer.go b/reader/tokenizer/tokenizer.go index 291a7aa..89ec329 100644 --- a/reader/tokenizer/tokenizer.go +++ b/reader/tokenizer/tokenizer.go @@ -6,6 +6,7 @@ import ( "strings" "github.com/ta2gch/gazelle/runtime/class" + "github.com/ta2gch/gazelle/runtime/class/parseerror" ) // Tokenizer interface type is the interface @@ -69,7 +70,7 @@ func (r *Tokenizer) Next() (string, class.Instance) { if buf == "" { p, _, err := r.PeekRune() if err != nil { - return "", class.New(class.ParseError, nil) + return "", parseerror.New(buf, class.Object) } if token.MatchString(string(p)) { buf = string(p) diff --git a/runtime/class/parseerror/parseerror.go b/runtime/class/parseerror/parseerror.go index 914ddb3..9a32d51 100644 --- a/runtime/class/parseerror/parseerror.go +++ b/runtime/class/parseerror/parseerror.go @@ -7,12 +7,12 @@ import ( ) type parseerror struct { - object class.Instance + str string expectedClass class.Class } -func New(obj class.Instance, cls class.Class) class.Instance { - return parseerror{obj, cls} +func New(str string, cls class.Class) class.Instance { + return parseerror{str, cls} } func (e parseerror) Value() class.Value { @@ -28,5 +28,5 @@ func (e parseerror) IsInstanceOf(cls class.Class) bool { } func (e parseerror) String() string { - return fmt.Sprintf("Parse Error: %v is not a instance of %v", e.object, e.expectedClass) + return fmt.Sprintf("Parse Error: %v is not a instance of %v", e.str, e.expectedClass) } diff --git a/runtime/eval.go b/runtime/eval.go index 0e6267a..05e630d 100644 --- a/runtime/eval.go +++ b/runtime/eval.go @@ -131,8 +131,5 @@ func Eval(obj class.Instance, local *env.Environment, global *env.Environment) ( } return ret, nil } - if obj.IsInstanceOf(class.Number) || obj.IsInstanceOf(class.Character) || obj.IsInstanceOf(class.String) { - return obj, nil - } - return nil, class.New(class.ParseError, nil) + return obj, nil } diff --git a/runtime/lambda.go b/runtime/lambda.go index 3b978d0..373d39d 100644 --- a/runtime/lambda.go +++ b/runtime/lambda.go @@ -3,6 +3,7 @@ package runtime import ( "github.com/ta2gch/gazelle/runtime/class" "github.com/ta2gch/gazelle/runtime/class/cons" + "github.com/ta2gch/gazelle/runtime/class/parseerror" env "github.com/ta2gch/gazelle/runtime/environment" ) @@ -43,7 +44,7 @@ func (f LambdaFunction) Apply(args class.Instance, local *env.Environment, globa return nil, err } if !cddr.IsInstanceOf(class.Null) { - return nil, class.New(class.ParseError, nil) + return nil, parseerror.New(fargs.String(), class.List) } local.SetVariable(cadr, aargs) break From 122a3df008c6ba9e19e1b251774b63c5fb8e668a Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Sun, 30 Jul 2017 23:33:22 +0900 Subject: [PATCH 071/228] Update README.md --- README.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 9bb0f7c..9b2ebd2 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,3 @@ -# gazelle -ISLisp on golang -
-
Photo via via Visual Hunt
+# iris + + From c1c1b3271961f3ae17855a12ddce12edd4b28a03 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Mon, 31 Jul 2017 09:05:46 +0900 Subject: [PATCH 072/228] Used bufio.Scanner --- reader/tokenizer/tokenizer.go | 107 ++++++++++------------------- reader/tokenizer/tokenizer_test.go | 59 +++++++++------- 2 files changed, 72 insertions(+), 94 deletions(-) diff --git a/reader/tokenizer/tokenizer.go b/reader/tokenizer/tokenizer.go index 89ec329..c3909bf 100644 --- a/reader/tokenizer/tokenizer.go +++ b/reader/tokenizer/tokenizer.go @@ -1,9 +1,9 @@ package tokenizer import ( + "bufio" "io" "regexp" - "strings" "github.com/ta2gch/gazelle/runtime/class" "github.com/ta2gch/gazelle/runtime/class/parseerror" @@ -11,80 +11,49 @@ import ( // Tokenizer interface type is the interface // for reading string with every token -// Reader is like bufio.Reader but has PeekRune -// which returns a rune without advancing pointer -type Tokenizer struct { - err error - ru rune - sz int - rr io.RuneReader -} -// New creates interal reader from io.RuneReader -func New(r io.RuneReader) *Tokenizer { - b := new(Tokenizer) - b.rr = r - b.ru, b.sz, b.err = r.ReadRune() - return b -} - -// PeekRune returns a rune without advancing pointer -func (r *Tokenizer) PeekRune() (rune, int, error) { - return r.ru, r.sz, r.err +type Tokenizer struct { + sc *bufio.Scanner } -// ReadRune returns a rune with advancing pointer -func (r *Tokenizer) ReadRune() (rune, int, error) { - ru := r.ru - sz := r.sz - err := r.err - r.ru, r.sz, r.err = r.rr.ReadRune() - return ru, sz, err +var re *regexp.Regexp + +func New(r io.Reader) *Tokenizer { + str := "" + str += "[-+]?[[:digit:]]+|" + str += "#[bB][-+]?[01]+|" + str += "#[oO][-+]?[0-7]+|" + str += "#[xX][-+]?[[:xdigit:]]+|" + str += "[-+]?[[:digit:]]+\\.[[:digit:]]+|" + str += "[-+]?[[:digit:]]+(?:\\.[[:digit:]]+)?[eE][-+]?[[:digit:]]+|" + str += "#\\\\newline|" + str += "#\\\\space|" + str += "#\\\\[[:graph:]]|" + str += "\".*\"|" + str += ":[<>/*=?_!$%[\\]^{}~0-9a-zA-Z]+|" + str += "\\|.*\\||" + str += "[<>/*=?_!$%[\\]^{}~a-zA-Z][<>/*=?_!$%[\\]^{}~0-9a-zA-Z]*|" + str += "[.()]|" + str += ",@?|'|`|#[[:digit:]]*[aA]" + re = regexp.MustCompile(str) + sc := bufio.NewScanner(r) + sc.Split(splitter) + return &Tokenizer{sc} } -func concatMatcher(src ...string) *regexp.Regexp { - return regexp.MustCompile("^(?:" + strings.Join(src, ")$|^(?:") + ")$") +func (t *Tokenizer) Next() (string, class.Instance) { + if t.sc.Scan() { + return t.sc.Text(), nil + } + return "", parseerror.New("", class.Object) } -var macro = strings.Join([]string{"#(?:[[:digit:]]+[aA]?)?", ",@?", "'", "`"}, "|") -var integer = strings.Join([]string{"[[:digit:]]+", "[+-][[:digit:]]*", "#(?:[bB][+-]?[01]*)?", "#(?:[oO][+-]?[0-7]*)?", "#(?:[xX][+-]?[[:xdigit:]]*)?"}, "|") -var float = strings.Join([]string{"[[:digit:]]+(?:\\.?[[:digit:]]*(?:[eE](?:[-+]?[[:digit:]]*)?)?)?", "[+-](?:[[:digit:]]+(?:\\.?[[:digit:]]*(?:[eE](?:[-+]?[[:digit:]]*)?)?)?)?"}, "|") -var character = strings.Join([]string{"#(?:\\\\[[:alpha:]]*)?", "#(?:\\\\[[:graph:]]?)?"}, "|") -var str = strings.Join([]string{"\"(?:\\\\\"|[^\"])*\"?"}, "|") -var symbol = strings.Join([]string{"[<>/*=?_!$%[\\]^{}~a-zA-Z][<>/*=?_!$%[\\]^{}~0-9a-zA-Z]*", "\\|(?:\\\\\\||[^|])*\\|?"}, "|") -var parentheses = strings.Join([]string{"\\.", "\\(", "\\)"}, "|") - -var token = concatMatcher( - macro, - integer, - float, - character, - str, - symbol, - parentheses) - -// Next returns error or string as token -func (r *Tokenizer) Next() (string, class.Instance) { - buf := "" - for { - if buf == "" { - p, _, err := r.PeekRune() - if err != nil { - return "", parseerror.New(buf, class.Object) - } - if token.MatchString(string(p)) { - buf = string(p) - } - } else { - p, _, err := r.PeekRune() - if err != nil { - return buf, nil - } - if !token.MatchString(buf + string(p)) { - return buf, nil - } - buf += string(p) - } - r.ReadRune() +func splitter(data []byte, atEOF bool) (advance int, token []byte, err error) { + if atEOF { + return len(data), data, nil + } + if loc := re.FindIndex(data); loc != nil { + return loc[1], data[loc[0]:loc[1]], nil } + return } diff --git a/reader/tokenizer/tokenizer_test.go b/reader/tokenizer/tokenizer_test.go index 4c41a39..638f55b 100644 --- a/reader/tokenizer/tokenizer_test.go +++ b/reader/tokenizer/tokenizer_test.go @@ -1,46 +1,55 @@ package tokenizer import ( - "io" + "bufio" + "reflect" "strings" "testing" + + "github.com/ta2gch/gazelle/runtime/class" ) -func TestReader_ReadToken(t *testing.T) { +func TestTokenizer_Next(t *testing.T) { + tokenizer := New(strings.NewReader("(default)")) type fields struct { - err error - ru rune - sz int - rr io.RuneReader + sc *bufio.Scanner } tests := []struct { - name string - fields fields - want string - wantErr bool + name string + fields fields + want string + want1 class.Instance }{ { - name: "symbol", - fields: fields{nil, 'd', 8, strings.NewReader("efault")}, - want: "default", - wantErr: false, + name: "start", + fields: fields{tokenizer.sc}, + want: "(", + want1: nil, + }, + { + name: "default", + fields: fields{tokenizer.sc}, + want: "default", + want1: nil, + }, + { + name: "end", + fields: fields{tokenizer.sc}, + want: ")", + want1: nil, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - r := &Tokenizer{ - err: tt.fields.err, - ru: tt.fields.ru, - sz: tt.fields.sz, - rr: tt.fields.rr, - } - got, err := r.Next() - if (err != nil) != tt.wantErr { - t.Errorf("Reader.ReadToken() error = %v, wantErr %v", err, tt.wantErr) - return + tok := &Tokenizer{ + sc: tt.fields.sc, } + got, got1 := tok.Next() if got != tt.want { - t.Errorf("Reader.ReadToken() = %v, want %v", got, tt.want) + t.Errorf("Tokenizer.Next() got = %v, want %v", got, tt.want) + } + if !reflect.DeepEqual(got1, tt.want1) { + t.Errorf("Tokenizer.Next() got1 = %v, want %v", got1, tt.want1) } }) } From 33ed9730e675e213273515077e4bea75cb884683 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Mon, 31 Jul 2017 09:05:53 +0900 Subject: [PATCH 073/228] remove debug code --- runtime/eval.go | 1 - 1 file changed, 1 deletion(-) diff --git a/runtime/eval.go b/runtime/eval.go index 05e630d..cffea01 100644 --- a/runtime/eval.go +++ b/runtime/eval.go @@ -36,7 +36,6 @@ func evalFunction(obj class.Instance, local *env.Environment, global *env.Enviro if err != nil { return nil, err } - println("called") // get function arguments cdr, err := cons.Cdr(obj) From 5d7f468183c5409100ec7fc3ece8b9c147054e8b Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Tue, 1 Aug 2017 11:30:33 +0900 Subject: [PATCH 074/228] rename pathname and change interaface name --- reader/parser/parser.go | 8 ++++---- reader/parser/parser_test.go | 2 +- reader/tokenizer/tokenizer.go | 4 ++-- reader/tokenizer/tokenizer_test.go | 2 +- runtime/class/cons/cons.go | 4 ++-- runtime/class/domainerror/domainerror.go | 2 +- runtime/class/function/function.go | 6 +++--- runtime/class/parseerror/parseerror.go | 2 +- runtime/environment/environment.go | 2 +- runtime/eval.go | 8 ++++---- runtime/eval_test.go | 10 +++++----- runtime/init.go | 6 +++--- runtime/lambda.go | 8 ++++---- runtime/native.go | 4 ++-- 14 files changed, 34 insertions(+), 34 deletions(-) diff --git a/reader/parser/parser.go b/reader/parser/parser.go index b475b99..01f7ca1 100644 --- a/reader/parser/parser.go +++ b/reader/parser/parser.go @@ -6,10 +6,10 @@ import ( "strconv" "strings" - "github.com/ta2gch/gazelle/reader/tokenizer" - "github.com/ta2gch/gazelle/runtime/class" - "github.com/ta2gch/gazelle/runtime/class/cons" - "github.com/ta2gch/gazelle/runtime/class/parseerror" + "github.com/ta2gch/iris/reader/tokenizer" + "github.com/ta2gch/iris/runtime/class" + "github.com/ta2gch/iris/runtime/class/cons" + "github.com/ta2gch/iris/runtime/class/parseerror" ) var eop = class.Object.New("End Of Parentheses") diff --git a/reader/parser/parser_test.go b/reader/parser/parser_test.go index 67a242f..a507891 100644 --- a/reader/parser/parser_test.go +++ b/reader/parser/parser_test.go @@ -4,7 +4,7 @@ import ( "reflect" "testing" - "github.com/ta2gch/gazelle/runtime/class" + "github.com/ta2gch/iris/runtime/class" ) func Test_parseAtom(t *testing.T) { diff --git a/reader/tokenizer/tokenizer.go b/reader/tokenizer/tokenizer.go index c3909bf..38256bd 100644 --- a/reader/tokenizer/tokenizer.go +++ b/reader/tokenizer/tokenizer.go @@ -5,8 +5,8 @@ import ( "io" "regexp" - "github.com/ta2gch/gazelle/runtime/class" - "github.com/ta2gch/gazelle/runtime/class/parseerror" + "github.com/ta2gch/iris/runtime/class" + "github.com/ta2gch/iris/runtime/class/parseerror" ) // Tokenizer interface type is the interface diff --git a/reader/tokenizer/tokenizer_test.go b/reader/tokenizer/tokenizer_test.go index 638f55b..e4b0a66 100644 --- a/reader/tokenizer/tokenizer_test.go +++ b/reader/tokenizer/tokenizer_test.go @@ -6,7 +6,7 @@ import ( "strings" "testing" - "github.com/ta2gch/gazelle/runtime/class" + "github.com/ta2gch/iris/runtime/class" ) func TestTokenizer_Next(t *testing.T) { diff --git a/runtime/class/cons/cons.go b/runtime/class/cons/cons.go index ecc84bf..e6cf4a7 100644 --- a/runtime/class/cons/cons.go +++ b/runtime/class/cons/cons.go @@ -3,8 +3,8 @@ package cons import ( "fmt" - "github.com/ta2gch/gazelle/runtime/class" - "github.com/ta2gch/gazelle/runtime/class/domainerror" + "github.com/ta2gch/iris/runtime/class" + "github.com/ta2gch/iris/runtime/class/domainerror" ) // Cell is a pair of pointers to Object diff --git a/runtime/class/domainerror/domainerror.go b/runtime/class/domainerror/domainerror.go index f0f96e0..e353f83 100644 --- a/runtime/class/domainerror/domainerror.go +++ b/runtime/class/domainerror/domainerror.go @@ -3,7 +3,7 @@ package domainerror import ( "fmt" - "github.com/ta2gch/gazelle/runtime/class" + "github.com/ta2gch/iris/runtime/class" ) type domainerror struct { diff --git a/runtime/class/function/function.go b/runtime/class/function/function.go index 79e5e7b..0bd9fd6 100644 --- a/runtime/class/function/function.go +++ b/runtime/class/function/function.go @@ -1,9 +1,9 @@ package function import ( - "github.com/ta2gch/gazelle/runtime/class" - "github.com/ta2gch/gazelle/runtime/class/domainerror" - env "github.com/ta2gch/gazelle/runtime/environment" + "github.com/ta2gch/iris/runtime/class" + "github.com/ta2gch/iris/runtime/class/domainerror" + env "github.com/ta2gch/iris/runtime/environment" ) type Function interface { diff --git a/runtime/class/parseerror/parseerror.go b/runtime/class/parseerror/parseerror.go index 9a32d51..b6edad7 100644 --- a/runtime/class/parseerror/parseerror.go +++ b/runtime/class/parseerror/parseerror.go @@ -3,7 +3,7 @@ package parseerror import ( "fmt" - "github.com/ta2gch/gazelle/runtime/class" + "github.com/ta2gch/iris/runtime/class" ) type parseerror struct { diff --git a/runtime/environment/environment.go b/runtime/environment/environment.go index d1e00fb..e325a5e 100644 --- a/runtime/environment/environment.go +++ b/runtime/environment/environment.go @@ -1,7 +1,7 @@ package environment import ( - "github.com/ta2gch/gazelle/runtime/class" + "github.com/ta2gch/iris/runtime/class" ) // Environment struct is the struct for keeping functions and variables diff --git a/runtime/eval.go b/runtime/eval.go index cffea01..53dfdff 100644 --- a/runtime/eval.go +++ b/runtime/eval.go @@ -1,10 +1,10 @@ package runtime import ( - "github.com/ta2gch/gazelle/runtime/class" - "github.com/ta2gch/gazelle/runtime/class/cons" - "github.com/ta2gch/gazelle/runtime/class/function" - env "github.com/ta2gch/gazelle/runtime/environment" + "github.com/ta2gch/iris/runtime/class" + "github.com/ta2gch/iris/runtime/class/cons" + "github.com/ta2gch/iris/runtime/class/function" + env "github.com/ta2gch/iris/runtime/environment" ) func evalArguments(args class.Instance, local *env.Environment, global *env.Environment) (class.Instance, class.Instance) { diff --git a/runtime/eval_test.go b/runtime/eval_test.go index 45648c9..91df167 100644 --- a/runtime/eval_test.go +++ b/runtime/eval_test.go @@ -5,11 +5,11 @@ import ( "strings" "testing" - "github.com/ta2gch/gazelle/reader/parser" - "github.com/ta2gch/gazelle/reader/tokenizer" - "github.com/ta2gch/gazelle/runtime/class" - "github.com/ta2gch/gazelle/runtime/class/cons" - env "github.com/ta2gch/gazelle/runtime/environment" + "github.com/ta2gch/iris/reader/parser" + "github.com/ta2gch/iris/reader/tokenizer" + "github.com/ta2gch/iris/runtime/class" + "github.com/ta2gch/iris/runtime/class/cons" + env "github.com/ta2gch/iris/runtime/environment" ) func read(s string) class.Instance { diff --git a/runtime/init.go b/runtime/init.go index 5812e32..fb4c2e4 100644 --- a/runtime/init.go +++ b/runtime/init.go @@ -1,9 +1,9 @@ package runtime import ( - "github.com/ta2gch/gazelle/runtime/class" - "github.com/ta2gch/gazelle/runtime/class/cons" - env "github.com/ta2gch/gazelle/runtime/environment" + "github.com/ta2gch/iris/runtime/class" + "github.com/ta2gch/iris/runtime/class/cons" + env "github.com/ta2gch/iris/runtime/environment" ) func init() { diff --git a/runtime/lambda.go b/runtime/lambda.go index 373d39d..3511905 100644 --- a/runtime/lambda.go +++ b/runtime/lambda.go @@ -1,10 +1,10 @@ package runtime import ( - "github.com/ta2gch/gazelle/runtime/class" - "github.com/ta2gch/gazelle/runtime/class/cons" - "github.com/ta2gch/gazelle/runtime/class/parseerror" - env "github.com/ta2gch/gazelle/runtime/environment" + "github.com/ta2gch/iris/runtime/class" + "github.com/ta2gch/iris/runtime/class/cons" + "github.com/ta2gch/iris/runtime/class/parseerror" + env "github.com/ta2gch/iris/runtime/environment" ) type LambdaFunction struct { diff --git a/runtime/native.go b/runtime/native.go index 4f7c95b..00f8ef1 100644 --- a/runtime/native.go +++ b/runtime/native.go @@ -1,8 +1,8 @@ package runtime import ( - "github.com/ta2gch/gazelle/runtime/class" - env "github.com/ta2gch/gazelle/runtime/environment" + "github.com/ta2gch/iris/runtime/class" + env "github.com/ta2gch/iris/runtime/environment" ) type NativeFunction struct { From 967ce0e2bef6e4fecd55d76151919311f09c3b30 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Thu, 3 Aug 2017 00:15:55 +0900 Subject: [PATCH 075/228] rewrite runtime (WIP) --- {runtime => .runtime_old}/class/builtin.go | 0 {runtime => .runtime_old}/class/class.go | 0 {runtime => .runtime_old}/class/cons/cons.go | 0 .../class/domainerror/domainerror.go | 0 .../class/function/function.go | 0 {runtime => .runtime_old}/class/instance.go | 0 {runtime => .runtime_old}/class/meta.go | 0 .../class/parseerror/parseerror.go | 0 .../environment/environment.go | 0 {runtime => .runtime_old}/eval.go | 0 {runtime => .runtime_old}/eval_test.go | 0 {runtime => .runtime_old}/init.go | 0 {runtime => .runtime_old}/lambda.go | 0 {runtime => .runtime_old}/native.go | 0 reader/parser/parser.go | 69 +++---- reader/parser/parser_test.go | 37 ++-- reader/tokenizer/tokenizer.go | 10 +- reader/tokenizer/tokenizer_test.go | 4 +- runtime/ilos/class/class.go | 68 +++++++ runtime/ilos/ilos.go | 44 +++++ runtime/ilos/instance/basic-array.go | 175 ++++++++++++++++++ runtime/ilos/instance/character.go | 31 ++++ runtime/ilos/instance/instance.go | 48 +++++ runtime/ilos/instance/list.go | 93 ++++++++++ runtime/ilos/instance/number.go | 60 ++++++ runtime/ilos/instance/symbol.go | 32 ++++ 26 files changed, 612 insertions(+), 59 deletions(-) rename {runtime => .runtime_old}/class/builtin.go (100%) rename {runtime => .runtime_old}/class/class.go (100%) rename {runtime => .runtime_old}/class/cons/cons.go (100%) rename {runtime => .runtime_old}/class/domainerror/domainerror.go (100%) rename {runtime => .runtime_old}/class/function/function.go (100%) rename {runtime => .runtime_old}/class/instance.go (100%) rename {runtime => .runtime_old}/class/meta.go (100%) rename {runtime => .runtime_old}/class/parseerror/parseerror.go (100%) rename {runtime => .runtime_old}/environment/environment.go (100%) rename {runtime => .runtime_old}/eval.go (100%) rename {runtime => .runtime_old}/eval_test.go (100%) rename {runtime => .runtime_old}/init.go (100%) rename {runtime => .runtime_old}/lambda.go (100%) rename {runtime => .runtime_old}/native.go (100%) create mode 100644 runtime/ilos/class/class.go create mode 100644 runtime/ilos/ilos.go create mode 100644 runtime/ilos/instance/basic-array.go create mode 100644 runtime/ilos/instance/character.go create mode 100644 runtime/ilos/instance/instance.go create mode 100644 runtime/ilos/instance/list.go create mode 100644 runtime/ilos/instance/number.go create mode 100644 runtime/ilos/instance/symbol.go diff --git a/runtime/class/builtin.go b/.runtime_old/class/builtin.go similarity index 100% rename from runtime/class/builtin.go rename to .runtime_old/class/builtin.go diff --git a/runtime/class/class.go b/.runtime_old/class/class.go similarity index 100% rename from runtime/class/class.go rename to .runtime_old/class/class.go diff --git a/runtime/class/cons/cons.go b/.runtime_old/class/cons/cons.go similarity index 100% rename from runtime/class/cons/cons.go rename to .runtime_old/class/cons/cons.go diff --git a/runtime/class/domainerror/domainerror.go b/.runtime_old/class/domainerror/domainerror.go similarity index 100% rename from runtime/class/domainerror/domainerror.go rename to .runtime_old/class/domainerror/domainerror.go diff --git a/runtime/class/function/function.go b/.runtime_old/class/function/function.go similarity index 100% rename from runtime/class/function/function.go rename to .runtime_old/class/function/function.go diff --git a/runtime/class/instance.go b/.runtime_old/class/instance.go similarity index 100% rename from runtime/class/instance.go rename to .runtime_old/class/instance.go diff --git a/runtime/class/meta.go b/.runtime_old/class/meta.go similarity index 100% rename from runtime/class/meta.go rename to .runtime_old/class/meta.go diff --git a/runtime/class/parseerror/parseerror.go b/.runtime_old/class/parseerror/parseerror.go similarity index 100% rename from runtime/class/parseerror/parseerror.go rename to .runtime_old/class/parseerror/parseerror.go diff --git a/runtime/environment/environment.go b/.runtime_old/environment/environment.go similarity index 100% rename from runtime/environment/environment.go rename to .runtime_old/environment/environment.go diff --git a/runtime/eval.go b/.runtime_old/eval.go similarity index 100% rename from runtime/eval.go rename to .runtime_old/eval.go diff --git a/runtime/eval_test.go b/.runtime_old/eval_test.go similarity index 100% rename from runtime/eval_test.go rename to .runtime_old/eval_test.go diff --git a/runtime/init.go b/.runtime_old/init.go similarity index 100% rename from runtime/init.go rename to .runtime_old/init.go diff --git a/runtime/lambda.go b/.runtime_old/lambda.go similarity index 100% rename from runtime/lambda.go rename to .runtime_old/lambda.go diff --git a/runtime/native.go b/.runtime_old/native.go similarity index 100% rename from runtime/native.go rename to .runtime_old/native.go diff --git a/reader/parser/parser.go b/reader/parser/parser.go index 01f7ca1..17ef5f7 100644 --- a/reader/parser/parser.go +++ b/reader/parser/parser.go @@ -6,102 +6,103 @@ import ( "strconv" "strings" + "github.com/ta2gch/iris/runtime/ilos" + "github.com/ta2gch/iris/runtime/ilos/instance" + "github.com/ta2gch/iris/reader/tokenizer" - "github.com/ta2gch/iris/runtime/class" - "github.com/ta2gch/iris/runtime/class/cons" - "github.com/ta2gch/iris/runtime/class/parseerror" + "github.com/ta2gch/iris/runtime/ilos/class" ) -var eop = class.Object.New("End Of Parentheses") -var bod = class.Object.New("Begin Of Dot") +var eop = instance.NewSymbol("End Of Parentheses") +var bod = instance.NewSymbol("Begin Of Dot") -func parseAtom(tok string) (class.Instance, class.Instance) { +func parseAtom(tok string) (ilos.Instance, ilos.Instance) { // // integer // if m, _ := regexp.MatchString("^[-+]?[[:digit:]]+$", tok); m { n, _ := strconv.ParseInt(tok, 10, 64) - return class.Integer.New(int(n)), nil + return instance.NewInteger(int(n)), nil } if r := regexp.MustCompile("^#[bB]([-+]?[01]+)$").FindStringSubmatch(tok); len(r) >= 2 { n, _ := strconv.ParseInt(r[1], 2, 64) - return class.Integer.New(int(n)), nil + return instance.NewInteger(int(n)), nil } if r := regexp.MustCompile("^#[oO]([-+]?[0-7]+)$").FindStringSubmatch(tok); len(r) >= 2 { n, _ := strconv.ParseInt(r[1], 8, 64) - return class.Integer.New(int(n)), nil + return instance.NewInteger(int(n)), nil } if r := regexp.MustCompile("^#[xX]([-+]?[[:xdigit:]]+)$").FindStringSubmatch(tok); len(r) >= 2 { n, _ := strconv.ParseInt(r[1], 16, 64) - return class.Integer.New(int(n)), nil + return instance.NewInteger(int(n)), nil } // // float // if m, _ := regexp.MatchString("^[-+]?[[:digit:]]+\\.[[:digit:]]+$", tok); m { n, _ := strconv.ParseFloat(tok, 64) - return class.Float.New(n), nil + return instance.NewFloat(n), nil } if r := regexp.MustCompile("^([-+]?[[:digit:]]+(?:\\.[[:digit:]]+)?)[eE]([-+]?[[:digit:]]+)$").FindStringSubmatch(tok); len(r) >= 3 { n, _ := strconv.ParseFloat(r[1], 64) e, _ := strconv.ParseInt(r[2], 10, 64) - return class.Float.New(n * math.Pow10(int(e))), nil + return instance.NewFloat(n * math.Pow10(int(e))), nil } // // character // if m, _ := regexp.MatchString("^#\\\\newline$", tok); m { - return class.Character.New('\n'), nil + return instance.NewCharacter('\n'), nil } if m, _ := regexp.MatchString("^#\\\\space$", tok); m { - return class.Character.New(' '), nil + return instance.NewCharacter(' '), nil } if r := regexp.MustCompile("^#\\\\([[:graph:]])$").FindStringSubmatch(tok); len(r) >= 2 { - return class.Character.New(rune(r[1][0])), nil + return instance.NewCharacter(rune(r[1][0])), nil } // // string // if m, _ := regexp.MatchString("^\".*\"$", tok); m { - return class.String.New(tok), nil + return instance.NewString(tok), nil } // // symbol // if "nil" == tok { - return class.Null.New(nil), nil + return instance.NewNull(), nil } if r := regexp.MustCompile("^:([<>/*=?_!$%[\\]^{}~0-9a-zA-Z]+)$").FindStringSubmatch(tok); len(r) >= 2 { - return class.Symbol.New(r[1]), nil + return instance.NewSymbol(strings.ToUpper(r[1])), nil } if m, _ := regexp.MatchString("^\\|.*\\|$", tok); m { - return class.Symbol.New(tok), nil + return instance.NewSymbol(tok), nil } if m, _ := regexp.MatchString("^[<>/*=?_!$%[\\]^{}~a-zA-Z][<>/*=?_!$%[\\]^{}~0-9a-zA-Z]*$", tok); m { - return class.Symbol.New(tok), nil + return instance.NewSymbol(strings.ToUpper(tok)), nil } - return nil, parseerror.New(tok, class.Object) + return nil, instance.NewParseError(tok, class.Object) } -func parseMacro(tok string, t *tokenizer.Tokenizer) (class.Instance, class.Instance) { +func parseMacro(tok string, t *tokenizer.Tokenizer) (ilos.Instance, ilos.Instance) { cdr, err := Parse(t) if err != nil { return nil, err } n := tok if m, _ := regexp.MatchString("#[[:digit:]]*[aA]", tok); m { - s := class.Symbol.New("array") + s := instance.NewSymbol("array") i := strings.IndexRune(strings.ToLower(tok), 'a') if i == 1 { - d := class.Integer.New(1) - return cons.New(s, cons.New(d, cons.New(cdr, class.Null.New(nil)))), nil + d := instance.NewInteger(1) + return instance.NewCons(s, instance.NewCons(d, instance.NewCons(cdr, instance.NewNull()))), nil } v, err := strconv.ParseInt(tok[1:i], 10, 32) if err != nil { - return nil, parseerror.New(tok, class.Integer) + return nil, instance.NewParseError(tok, class.Integer) } - d := class.Integer.New(int(v)) - return cons.New(s, cons.New(d, cons.New(cdr, class.Null.New(nil)))), nil + d := instance.NewInteger(int(v)) + return instance.NewCons(s, instance.NewCons(d, instance.NewCons(cdr, instance.NewNull()))), nil } switch tok { case ",@": @@ -113,13 +114,13 @@ func parseMacro(tok string, t *tokenizer.Tokenizer) (class.Instance, class.Insta case "`": n = "backquote" } - m := class.Symbol.New(n) - return cons.New(m, cons.New(cdr, class.Null.New(nil))), nil + m := instance.NewSymbol(n) + return instance.NewCons(m, instance.NewCons(cdr, instance.NewNull())), nil } -func parseCons(t *tokenizer.Tokenizer) (class.Instance, class.Instance) { +func parseCons(t *tokenizer.Tokenizer) (ilos.Instance, ilos.Instance) { car, err := Parse(t) if err == eop { - return class.Null.New(nil), nil + return instance.NewNull(), nil } if err == bod { cdr, err := Parse(t) @@ -138,11 +139,11 @@ func parseCons(t *tokenizer.Tokenizer) (class.Instance, class.Instance) { if err != nil { return nil, err } - return cons.New(car, cdr), nil + return instance.NewCons(car, cdr), nil } // Parse builds a internal expression from tokens -func Parse(t *tokenizer.Tokenizer) (class.Instance, class.Instance) { +func Parse(t *tokenizer.Tokenizer) (ilos.Instance, ilos.Instance) { tok, err := t.Next() if err != nil { return nil, err diff --git a/reader/parser/parser_test.go b/reader/parser/parser_test.go index a507891..04f1653 100644 --- a/reader/parser/parser_test.go +++ b/reader/parser/parser_test.go @@ -4,7 +4,8 @@ import ( "reflect" "testing" - "github.com/ta2gch/iris/runtime/class" + "github.com/ta2gch/iris/runtime/ilos" + "github.com/ta2gch/iris/runtime/ilos/instance" ) func Test_parseAtom(t *testing.T) { @@ -14,7 +15,7 @@ func Test_parseAtom(t *testing.T) { tests := []struct { name string args args - want class.Instance + want ilos.Instance wantErr bool }{ // @@ -23,31 +24,31 @@ func Test_parseAtom(t *testing.T) { { name: "default", args: args{"3.14"}, - want: class.Float.New(3.14), + want: instance.NewFloat(3.14), wantErr: false, }, { name: "signed", args: args{"-5.0"}, - want: class.Float.New(-5.0), + want: instance.NewFloat(-5.0), wantErr: false, }, { name: "exponential", args: args{"-5.0E3"}, - want: class.Float.New(-5.0 * 1000), + want: instance.NewFloat(-5.0 * 1000), wantErr: false, }, { name: "signed exponential", args: args{"5.0E-3"}, - want: class.Float.New(5.0 * 1.0 / 1000.0), + want: instance.NewFloat(5.0 * 1.0 / 1000.0), wantErr: false, }, { name: "without point", args: args{"5E-3"}, - want: class.Float.New(5.0 * 1.0 / 1000.0), + want: instance.NewFloat(5.0 * 1.0 / 1000.0), wantErr: false, }, { @@ -68,49 +69,49 @@ func Test_parseAtom(t *testing.T) { { name: "default", args: args{"5"}, - want: class.Integer.New(5), + want: instance.NewInteger(5), wantErr: false, }, { name: "signed", args: args{"-5"}, - want: class.Integer.New(-5), + want: instance.NewInteger(-5), wantErr: false, }, { name: "binary", args: args{"#B00101"}, - want: class.Integer.New(5), + want: instance.NewInteger(5), wantErr: false, }, { name: "signed binary", args: args{"#b+00101"}, - want: class.Integer.New(5), + want: instance.NewInteger(5), wantErr: false, }, { name: "octal", args: args{"#o00101"}, - want: class.Integer.New(65), + want: instance.NewInteger(65), wantErr: false, }, { name: "signed octal", args: args{"#O-00101"}, - want: class.Integer.New(-65), + want: instance.NewInteger(-65), wantErr: false, }, { name: "hexadecimal", args: args{"#X00101"}, - want: class.Integer.New(257), + want: instance.NewInteger(257), wantErr: false, }, { name: "signed hexadecimal", args: args{"#x-00101"}, - want: class.Integer.New(-257), + want: instance.NewInteger(-257), wantErr: false, }, { @@ -125,19 +126,19 @@ func Test_parseAtom(t *testing.T) { { name: "default", args: args{"#\\a"}, - want: class.Character.New('a'), + want: instance.NewCharacter('a'), wantErr: false, }, { name: "newline", args: args{"#\\newline"}, - want: class.Character.New('\n'), + want: instance.NewCharacter('\n'), wantErr: false, }, { name: "space", args: args{"#\\space"}, - want: class.Character.New(' '), + want: instance.NewCharacter(' '), wantErr: false, }, { diff --git a/reader/tokenizer/tokenizer.go b/reader/tokenizer/tokenizer.go index 38256bd..5dc6ea9 100644 --- a/reader/tokenizer/tokenizer.go +++ b/reader/tokenizer/tokenizer.go @@ -5,13 +5,13 @@ import ( "io" "regexp" - "github.com/ta2gch/iris/runtime/class" - "github.com/ta2gch/iris/runtime/class/parseerror" + "github.com/ta2gch/iris/runtime/ilos" + "github.com/ta2gch/iris/runtime/ilos/class" + "github.com/ta2gch/iris/runtime/ilos/instance" ) // Tokenizer interface type is the interface // for reading string with every token - type Tokenizer struct { sc *bufio.Scanner } @@ -41,11 +41,11 @@ func New(r io.Reader) *Tokenizer { return &Tokenizer{sc} } -func (t *Tokenizer) Next() (string, class.Instance) { +func (t *Tokenizer) Next() (string, ilos.Instance) { if t.sc.Scan() { return t.sc.Text(), nil } - return "", parseerror.New("", class.Object) + return "", instance.NewParseError(t.sc.Text(), class.Object) } func splitter(data []byte, atEOF bool) (advance int, token []byte, err error) { diff --git a/reader/tokenizer/tokenizer_test.go b/reader/tokenizer/tokenizer_test.go index e4b0a66..687fdda 100644 --- a/reader/tokenizer/tokenizer_test.go +++ b/reader/tokenizer/tokenizer_test.go @@ -6,7 +6,7 @@ import ( "strings" "testing" - "github.com/ta2gch/iris/runtime/class" + "github.com/ta2gch/iris/runtime/ilos" ) func TestTokenizer_Next(t *testing.T) { @@ -18,7 +18,7 @@ func TestTokenizer_Next(t *testing.T) { name string fields fields want string - want1 class.Instance + want1 ilos.Instance }{ { name: "start", diff --git a/runtime/ilos/class/class.go b/runtime/ilos/class/class.go new file mode 100644 index 0000000..e965201 --- /dev/null +++ b/runtime/ilos/class/class.go @@ -0,0 +1,68 @@ +package class + +import "github.com/ta2gch/iris/runtime/ilos" + +type builtinclass struct { + parents []ilos.Class + name string +} + +func (*builtinclass) Class() ilos.Class { + return BuiltInClass +} + +func (p *builtinclass) Parents() []ilos.Class { + return p.parents +} + +func (i *builtinclass) GetSlotValue(key ilos.Instance) (ilos.Instance, bool) { + return nil, false +} + +func (i *builtinclass) SetSlotValue(key ilos.Instance, value ilos.Instance) bool { + return false +} + +func (p *builtinclass) String() string { + return p.name +} + +var Object = &builtinclass{[]ilos.Class{}, ""} +var BuiltInClass = &builtinclass{[]ilos.Class{Object}, ""} +var StandardClass = &builtinclass{[]ilos.Class{Object}, ""} +var BasicArray = &builtinclass{[]ilos.Class{Object}, ""} +var BasicArrayStar = &builtinclass{[]ilos.Class{BasicArray}, ""} +var GeneralArrayStar = &builtinclass{[]ilos.Class{BasicArrayStar}, ""} +var BasicVector = &builtinclass{[]ilos.Class{BasicArray}, ""} +var GeneraVector = &builtinclass{[]ilos.Class{BasicVector}, ""} +var String = &builtinclass{[]ilos.Class{BasicVector}, ""} +var Character = &builtinclass{[]ilos.Class{Object}, ""} +var Function = &builtinclass{[]ilos.Class{Object}, ""} +var GenericFunction = &builtinclass{[]ilos.Class{Function}, ""} +var StandardGenericFunction = &builtinclass{[]ilos.Class{GenericFunction}, ""} +var List = &builtinclass{[]ilos.Class{Object}, ""} +var Cons = &builtinclass{[]ilos.Class{List}, ""} +var Null = &builtinclass{[]ilos.Class{List}, ""} +var Symbol = &builtinclass{[]ilos.Class{Object}, ""} +var Number = &builtinclass{[]ilos.Class{Object}, ""} +var Integer = &builtinclass{[]ilos.Class{Number}, ""} +var Float = &builtinclass{[]ilos.Class{Number}, ""} +var SeriousCondition = &builtinclass{[]ilos.Class{Object}, ""} +var Error = &builtinclass{[]ilos.Class{SeriousCondition}, ""} +var ArithmeticError = &builtinclass{[]ilos.Class{Error}, ""} +var DivisionByZero = &builtinclass{[]ilos.Class{ArithmeticError}, ""} +var FloatingPointOnderflow = &builtinclass{[]ilos.Class{ArithmeticError}, ""} +var FloatingPointUnderflow = &builtinclass{[]ilos.Class{ArithmeticError}, ""} +var ControlError = &builtinclass{[]ilos.Class{Error}, ""} +var ParseError = &builtinclass{[]ilos.Class{Error}, ""} +var ProgramError = &builtinclass{[]ilos.Class{Error}, ""} +var DomainError = &builtinclass{[]ilos.Class{ProgramError}, ""} +var UndefinedEntity = &builtinclass{[]ilos.Class{ProgramError}, ""} +var UndefinedVariable = &builtinclass{[]ilos.Class{UndefinedEntity}, ""} +var UndefinedFunction = &builtinclass{[]ilos.Class{UndefinedEntity}, ""} +var SimpleError = &builtinclass{[]ilos.Class{Error}, ""} +var StreamError = &builtinclass{[]ilos.Class{Error}, ""} +var EndOfStream = &builtinclass{[]ilos.Class{StreamError}, ""} +var StorageExhausted = &builtinclass{[]ilos.Class{SeriousCondition}, ""} +var StandardObject = &builtinclass{[]ilos.Class{Object}, ""} +var Stream = &builtinclass{[]ilos.Class{Object}, ""} diff --git a/runtime/ilos/ilos.go b/runtime/ilos/ilos.go new file mode 100644 index 0000000..e3d77e4 --- /dev/null +++ b/runtime/ilos/ilos.go @@ -0,0 +1,44 @@ +package ilos + +type Class interface { + Class() Class + Parents() []Class + GetSlotValue(Instance) (Instance, bool) + SetSlotValue(Instance, Instance) bool + String() string +} + +type Instance interface { + Class() Class + GetSlotValue(Instance) (Instance, bool) + SetSlotValue(Instance, Instance) bool + String() string +} + +func ChildOf(c, p Class) bool { + var sub func(c, p Class) bool + sub = func(c, p Class) bool { + if c == p { + return true + } + for _, d := range c.Parents() { + if sub(d, p) { + return true + } + } + return false + } + for _, d := range c.Parents() { + if sub(d, p) { + return true + } + } + return false +} + +func InstanceOf(i Instance, p Class) bool { + if i.Class() == p { + return true + } + return ChildOf(i.Class(), p) +} diff --git a/runtime/ilos/instance/basic-array.go b/runtime/ilos/instance/basic-array.go new file mode 100644 index 0000000..883b710 --- /dev/null +++ b/runtime/ilos/instance/basic-array.go @@ -0,0 +1,175 @@ +package instance + +import ( + "fmt" + + "github.com/ta2gch/iris/runtime/ilos" + "github.com/ta2gch/iris/runtime/ilos/class" +) + +// +// General Array Star +// + +type GeneralArrayStar struct { + dimension [128]int + array map[[128]int]ilos.Instance +} + +func NewGeneralArrayStar(key ilos.Instance) ilos.Instance { + dim := [128]int{} + cdr := key + idx := 0 + if !ilos.InstanceOf(key, class.List) { + return nil + } + if cdr.Class() == class.Null { + return &GeneralArrayStar{dim, map[[128]int]ilos.Instance{}} + } + for ilos.Instance(cdr, class.Cons) { + car := UnsafeCar(cdr) + cdr = UnsafeCdr(cdr) + if idx >= 128 || !ilos.InstanceOf(car, class.Integer) || !ilos.InstanceOf(cdr, class.List) || int(car.(Integer)) > 0 { + return nil + } + dim[idx] = int(car.(Integer)) + idx++ + } + return &GeneralArrayStar{dim, map[[128]int]ilos.Instance{}} +} + +func (*GeneralArrayStar) Class() ilos.Class { + return class.GeneralArrayStar +} + +func (a *GeneralArrayStar) GetSlotValue(key ilos.Instance) (ilos.Instance, bool) { + dim := [128]int{} + cdr := key + idx := 0 + if !ilos.InstanceOf(key, class.List) { + return nil, false + } + if a.dimension == dim && key.Class() == class.Null { + return a.array[dim], true + } + for ilos.Instance(cdr, class.Cons) { + car := UnsafeCar(cdr) + cdr = UnsafeCdr(cdr) + if idx >= 128 || !ilos.InstanceOf(car, class.Integer) || !ilos.InstanceOf(cdr, class.List) { + return nil, false + } + dim[idx] = int(car.(Integer)) + idx++ + } + for i := range a.dimension { + if 0 >= dim[i] || dim[i] >= a.dimension[i] { + return nil, false + } + } + return a.array[dim], true +} + +func (a *GeneralArrayStar) SetSlotValue(key ilos.Instance, value ilos.Instance) bool { + dim := [128]int{} + cdr := key + idx := 0 + if !ilos.InstanceOf(key, class.List) { + return false + } + if a.dimension == dim && ilos.InstanceOf(key, class.Null) { + a.array[dim] = value + return true + } + for ilos.InstanceOf(cdr, class.Cons) { + car := UnsafeCar(cdr) + cdr = UnsafeCdr(cdr) + if idx >= 128 || !ilos.InstanceOf(key, class.Integer) || !ilos.InstanceOf(cdr, class.List) { + return false + } + dim[idx] = int(car.(Integer)) + idx++ + } + for i := range a.dimension { + if 0 >= dim[i] || dim[i] >= a.dimension[i] { + return false + } + } + a.array[dim] = value + return true +} + +func (a *GeneralArrayStar) String() string { + return fmt.Sprint(a.array) +} + +// +// General Vector +// + +type GeneralVector []ilos.Instance + +func NewGeneralVector(i []ilos.Instance) ilos.Instance { + return GeneralVector(i) +} + +func (GeneralVector) Class() ilos.Class { + return class.GeneraVector +} + +func (i GeneralVector) GetSlotValue(key ilos.Instance) (ilos.Instance, bool) { + if ilos.InstanceOf(key, class.Symbol) && key.(Symbol) == "length" { + return Integer(len(i)), true + } + if ilos.InstanceOf(key, class.Integer) && int(key.(Integer)) < len(i) { + return i[key.(Integer)], true + } + return nil, false +} + +func (i GeneralVector) SetSlotValue(key ilos.Instance, value ilos.Instance) bool { + if ilos.InstanceOf(key, class.Integer) && int(key.(Integer)) < len(i) { + i[key.(Integer)] = value + return true + } + return false +} + +func (i GeneralVector) String() string { + return fmt.Sprint([]ilos.Instance(i)) +} + +// +// String +// + +type String []rune + +func NewString(a string) ilos.Instance { + return String([]rune(a)) +} + +func (String) Class() ilos.Class { + return class.String +} + +func (i String) GetSlotValue(key ilos.Instance) (ilos.Instance, bool) { + if ilos.InstanceOf(key, class.Symbol) && key.(Symbol) == "length" { + return Integer(len(i)), true + } + if ilos.InstanceOf(key, class.Integer) && int(key.(Integer)) < len(i) { + return Character(i[key.(Integer)]), true + } + return nil, false +} + +func (i String) SetSlotValue(key ilos.Instance, value ilos.Instance) bool { + if ilos.InstanceOf(key, class.Integer) && int(key.(Integer)) < len(i) { + i[key.(Integer)] = rune(value.(Character)) + return true + } + return false +} + +func (i String) String() string { + return string(i) +} diff --git a/runtime/ilos/instance/character.go b/runtime/ilos/instance/character.go new file mode 100644 index 0000000..d6c5148 --- /dev/null +++ b/runtime/ilos/instance/character.go @@ -0,0 +1,31 @@ +package instance + +import ( + "github.com/ta2gch/iris/runtime/ilos" + "github.com/ta2gch/iris/runtime/ilos/class" +) + +// +// Character +// + +type Character rune + +func NewCharacter(n rune) ilos.Instance { + return Character(n) +} + +func (Character) Class() ilos.Class { + return class.Character +} + +func (i Character) GetSlotValue(key ilos.Instance) (ilos.Instance, bool) { + return nil, false +} + +func (i Character) SetSlotValue(key ilos.Instance, value ilos.Instance) bool { + return false +} +func (i Character) String() string { + return string(i) +} diff --git a/runtime/ilos/instance/instance.go b/runtime/ilos/instance/instance.go new file mode 100644 index 0000000..30e761c --- /dev/null +++ b/runtime/ilos/instance/instance.go @@ -0,0 +1,48 @@ +package instance + +import ( + "fmt" + + "github.com/ta2gch/iris/runtime/ilos" + "github.com/ta2gch/iris/runtime/ilos/class" +) + +// +// instance +// + +type instance struct { + class ilos.Class + slots map[ilos.Instance]ilos.Instance +} + +func (i *instance) Class() ilos.Class { + return i.class +} + +func (i *instance) GetSlotValue(key ilos.Instance) (ilos.Instance, bool) { + v, ok := i.slots[key] + return v, ok +} + +func (i *instance) SetSlotValue(key ilos.Instance, value ilos.Instance) bool { + i.slots[key.(Symbol)] = value + return true +} + +func (i *instance) String() string { + return fmt.Sprintf("#INSTANCE[%v %v]", i.class, i.slots) +} + +// +// ParseError +// + +func NewParseError(s string, ec ilos.Class) ilos.Instance { + i := new(instance) + i.class = class.ParseError + i.slots = map[ilos.Instance]ilos.Instance{} + i.slots[NewSymbol("STRING")] = NewString(s) + i.slots[NewSymbol("EXPECTED-CLASS")] = ec + return i +} diff --git a/runtime/ilos/instance/list.go b/runtime/ilos/instance/list.go new file mode 100644 index 0000000..5afff33 --- /dev/null +++ b/runtime/ilos/instance/list.go @@ -0,0 +1,93 @@ +package instance + +import ( + "fmt" + + "github.com/ta2gch/iris/runtime/ilos" + "github.com/ta2gch/iris/runtime/ilos/class" +) + +// +// Cons +// + +type Cons struct { + car ilos.Instance + cdr ilos.Instance +} + +func NewCons(car ilos.Instance, cdr ilos.Instance) ilos.Instance { + return &Cons{car, cdr} +} + +func (*Cons) Class() ilos.Class { + return class.Cons +} + +func (i *Cons) GetSlotValue(key ilos.Instance) (ilos.Instance, bool) { + if !ilos.InstanceOf(key, class.Symbol) { + return nil, false + } + switch key.(Symbol) { + case "CAR": + return i.car, true + case "CDR": + return i.cdr, true + default: + return nil, false + } +} + +func (i *Cons) SetSlotValue(key ilos.Instance, value ilos.Instance) bool { + if !ilos.InstanceOf(key, class.Symbol) { + return false + } + switch key.(Symbol) { + case "CAR": + i.car = value + return true + case "CDR": + i.cdr = value + return true + default: + return false + } +} + +func (i *Cons) String() string { + return fmt.Sprintf("(%v . %v)", i.car, i.cdr) +} + +func UnsafeCar(i ilos.Instance) ilos.Instance { + return i.(*Cons).car +} + +func UnsafeCdr(i ilos.Instance) ilos.Instance { + return i.(*Cons).cdr +} + +// +// Null +// + +type Null struct{} + +func NewNull() ilos.Instance { + return &Null{} +} + +func (*Null) Class() ilos.Class { + return class.Null +} + +func (i *Null) GetSlotValue(key ilos.Instance) (ilos.Instance, bool) { + return nil, false +} + +func (i *Null) SetSlotValue(key ilos.Instance, value ilos.Instance) bool { + return false +} + +func (*Null) String() string { + return "nil" +} diff --git a/runtime/ilos/instance/number.go b/runtime/ilos/instance/number.go new file mode 100644 index 0000000..fc1acbf --- /dev/null +++ b/runtime/ilos/instance/number.go @@ -0,0 +1,60 @@ +package instance + +import ( + "fmt" + + "github.com/ta2gch/iris/runtime/ilos" + "github.com/ta2gch/iris/runtime/ilos/class" +) + +// +// Integer +// + +type Integer int + +func NewInteger(n int) ilos.Instance { + return Integer(n) +} + +func (Integer) Class() ilos.Class { + return class.Integer +} + +func (i Integer) GetSlotValue(key ilos.Instance) (ilos.Instance, bool) { + return nil, false +} + +func (i Integer) SetSlotValue(key ilos.Instance, value ilos.Instance) bool { + return false +} + +func (i Integer) String() string { + return fmt.Sprint(int(i)) +} + +// +// Float +// + +type Float float64 + +func NewFloat(n float64) ilos.Instance { + return Float(n) +} + +func (Float) Class() ilos.Class { + return class.Float +} + +func (i Float) GetSlotValue(key ilos.Instance) (ilos.Instance, bool) { + return nil, false +} + +func (i Float) SetSlotValue(key ilos.Instance, value ilos.Instance) bool { + return false +} + +func (i Float) String() string { + return fmt.Sprint(float64(i)) +} diff --git a/runtime/ilos/instance/symbol.go b/runtime/ilos/instance/symbol.go new file mode 100644 index 0000000..cb895ed --- /dev/null +++ b/runtime/ilos/instance/symbol.go @@ -0,0 +1,32 @@ +package instance + +import ( + "github.com/ta2gch/iris/runtime/ilos" + "github.com/ta2gch/iris/runtime/ilos/class" +) + +// +// Symbol +// + +type Symbol string + +func NewSymbol(n string) ilos.Instance { + return Symbol(n) +} + +func (Symbol) Class() ilos.Class { + return class.Symbol +} + +func (i Symbol) GetSlotValue(key ilos.Instance) (ilos.Instance, bool) { + return nil, false +} + +func (i Symbol) SetSlotValue(key ilos.Instance, value ilos.Instance) bool { + return false +} + +func (i Symbol) String() string { + return string(i) +} From 088926ce84b4da9054a1f506c53be853d872f817 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Thu, 3 Aug 2017 11:55:39 +0900 Subject: [PATCH 076/228] Updated ilos --- .runtime_old/environment/environment.go | 113 ------------------- reader/parser/parser.go | 4 +- reader/tokenizer/tokenizer.go | 2 +- runtime/environment/environment.go | 111 ++++++++++++++++++ runtime/ilos/class/class.go | 7 +- runtime/ilos/ilos.go | 8 +- runtime/ilos/instance/basic-array.go | 144 ++++++++---------------- runtime/ilos/instance/character.go | 8 +- runtime/ilos/instance/function.go | 93 +++++++++++++++ runtime/ilos/instance/instance.go | 27 +---- runtime/ilos/instance/list.go | 36 +----- runtime/ilos/instance/number.go | 16 +-- runtime/ilos/instance/serious-error.go | 63 +++++++++++ runtime/ilos/instance/symbol.go | 8 +- 14 files changed, 353 insertions(+), 287 deletions(-) delete mode 100644 .runtime_old/environment/environment.go create mode 100644 runtime/environment/environment.go create mode 100644 runtime/ilos/instance/function.go create mode 100644 runtime/ilos/instance/serious-error.go diff --git a/.runtime_old/environment/environment.go b/.runtime_old/environment/environment.go deleted file mode 100644 index e325a5e..0000000 --- a/.runtime_old/environment/environment.go +++ /dev/null @@ -1,113 +0,0 @@ -package environment - -import ( - "github.com/ta2gch/iris/runtime/class" -) - -// Environment struct is the struct for keeping functions and variables -type Environment struct { - Macro []map[class.Value]class.Instance - Function []map[class.Value]class.Instance - Variable []map[class.Value]class.Instance - DynamicVariable []map[class.Value]class.Instance // deep biding -} - -// New creates new environment -func New() *Environment { - env := new(Environment) - env.Macro = []map[class.Value]class.Instance{map[class.Value]class.Instance{}} - env.Function = []map[class.Value]class.Instance{map[class.Value]class.Instance{}} - env.Variable = []map[class.Value]class.Instance{map[class.Value]class.Instance{}} - env.DynamicVariable = []map[class.Value]class.Instance{map[class.Value]class.Instance{}} - return env -} - -func (e *Environment) MergeDynamicVariable(f *Environment) { - e.DynamicVariable = append(e.DynamicVariable, f.DynamicVariable...) -} - -func (e *Environment) MergeAll(f *Environment) { - e.Variable = append(e.Variable, f.Variable...) - e.Function = append(e.Function, f.Function...) - e.Macro = append(e.Macro, f.Macro...) - e.DynamicVariable = append(e.DynamicVariable, f.DynamicVariable...) -} - -func (e *Environment) GetVariable(key class.Instance) (class.Instance, bool) { - for _, vars := range e.Variable { - if v, ok := vars[key.Value()]; ok { - return v, ok - } - } - return nil, false -} - -func (e *Environment) SetVariable(key class.Instance, value class.Instance) { - for _, vars := range e.Variable { - if _, ok := vars[key.Value()]; ok { - vars[key.Value()] = value - return - } - } - e.Variable[0][key.Value()] = value -} - -func (e *Environment) GetFunction(key class.Instance) (class.Instance, bool) { - for _, vars := range e.Function { - if v, ok := vars[key.Value()]; ok { - return v, ok - } - } - return nil, false -} - -func (e *Environment) SetFunction(key class.Instance, value class.Instance) { - for _, vars := range e.Function { - if _, ok := vars[key.Value()]; ok { - vars[key.Value()] = value - return - } - } - e.Function[0][key.Value()] = value -} - -func (e *Environment) GetMacro(key class.Instance) (class.Instance, bool) { - for _, vars := range e.Macro { - if v, ok := vars[key.Value()]; ok { - return v, ok - } - } - return nil, false -} - -func (e *Environment) SetMacro(key class.Instance, value class.Instance) { - for _, vars := range e.Macro { - if _, ok := vars[key.Value()]; ok { - vars[key.Value()] = value - return - } - } - e.Macro[0][key.Value()] = value -} - -func (e *Environment) GetDynamicVariable(key class.Instance) (class.Instance, bool) { - for _, vars := range e.DynamicVariable { - if v, ok := vars[key.Value()]; ok { - return v, ok - } - } - return nil, false -} - -func (e *Environment) SetDynamicVariable(key class.Instance, value class.Instance) { - for _, vars := range e.DynamicVariable { - if _, ok := vars[key.Value()]; ok { - vars[key.Value()] = value - return - } - } - e.DynamicVariable[0][key.Value()] = value -} - -// TopLevel is a global environment -var TopLevel = New() diff --git a/reader/parser/parser.go b/reader/parser/parser.go index 17ef5f7..3022c3e 100644 --- a/reader/parser/parser.go +++ b/reader/parser/parser.go @@ -81,7 +81,7 @@ func parseAtom(tok string) (ilos.Instance, ilos.Instance) { if m, _ := regexp.MatchString("^[<>/*=?_!$%[\\]^{}~a-zA-Z][<>/*=?_!$%[\\]^{}~0-9a-zA-Z]*$", tok); m { return instance.NewSymbol(strings.ToUpper(tok)), nil } - return nil, instance.NewParseError(tok, class.Object) + return nil, instance.NewParseError(instance.NewString(tok), class.Object) } func parseMacro(tok string, t *tokenizer.Tokenizer) (ilos.Instance, ilos.Instance) { @@ -99,7 +99,7 @@ func parseMacro(tok string, t *tokenizer.Tokenizer) (ilos.Instance, ilos.Instanc } v, err := strconv.ParseInt(tok[1:i], 10, 32) if err != nil { - return nil, instance.NewParseError(tok, class.Integer) + return nil, instance.NewParseError(instance.NewString(tok), class.Integer) } d := instance.NewInteger(int(v)) return instance.NewCons(s, instance.NewCons(d, instance.NewCons(cdr, instance.NewNull()))), nil diff --git a/reader/tokenizer/tokenizer.go b/reader/tokenizer/tokenizer.go index 5dc6ea9..1c2c3f3 100644 --- a/reader/tokenizer/tokenizer.go +++ b/reader/tokenizer/tokenizer.go @@ -45,7 +45,7 @@ func (t *Tokenizer) Next() (string, ilos.Instance) { if t.sc.Scan() { return t.sc.Text(), nil } - return "", instance.NewParseError(t.sc.Text(), class.Object) + return "", instance.NewParseError(instance.NewString(t.sc.Text()), class.Object) } func splitter(data []byte, atEOF bool) (advance int, token []byte, err error) { diff --git a/runtime/environment/environment.go b/runtime/environment/environment.go new file mode 100644 index 0000000..9c4b084 --- /dev/null +++ b/runtime/environment/environment.go @@ -0,0 +1,111 @@ +package environment + +import "github.com/ta2gch/iris/runtime/ilos" + +// Environment struct is the struct for keeping functions and variables +type Environment struct { + Macro []map[ilos.Instance]ilos.Instance + Function []map[ilos.Instance]ilos.Instance + Variable []map[ilos.Instance]ilos.Instance + DynamicVariable []map[ilos.Instance]ilos.Instance // deep biding +} + +// New creates new environment +func New() *Environment { + env := new(Environment) + env.Macro = []map[ilos.Instance]ilos.Instance{map[ilos.Instance]ilos.Instance{}} + env.Function = []map[ilos.Instance]ilos.Instance{map[ilos.Instance]ilos.Instance{}} + env.Variable = []map[ilos.Instance]ilos.Instance{map[ilos.Instance]ilos.Instance{}} + env.DynamicVariable = []map[ilos.Instance]ilos.Instance{map[ilos.Instance]ilos.Instance{}} + return env +} + +func (e *Environment) MergeDynamicVariable(f *Environment) { + e.DynamicVariable = append(e.DynamicVariable, f.DynamicVariable...) +} + +func (e *Environment) MergeAll(f *Environment) { + e.Variable = append(e.Variable, f.Variable...) + e.Function = append(e.Function, f.Function...) + e.Macro = append(e.Macro, f.Macro...) + e.DynamicVariable = append(e.DynamicVariable, f.DynamicVariable...) +} + +func (e *Environment) GetVariable(key ilos.Instance) (ilos.Instance, bool) { + for _, vars := range e.Variable { + if v, ok := vars[key]; ok { + return v, ok + } + } + return nil, false +} + +func (e *Environment) SetVariable(key ilos.Instance, value ilos.Instance) { + for _, vars := range e.Variable { + if _, ok := vars[key]; ok { + vars[key] = value + return + } + } + e.Variable[0][key] = value +} + +func (e *Environment) GetFunction(key ilos.Instance) (ilos.Instance, bool) { + for _, vars := range e.Function { + if v, ok := vars[key]; ok { + return v, ok + } + } + return nil, false +} + +func (e *Environment) SetFunction(key ilos.Instance, value ilos.Instance) { + for _, vars := range e.Function { + if _, ok := vars[key]; ok { + vars[key] = value + return + } + } + e.Function[0][key] = value +} + +func (e *Environment) GetMacro(key ilos.Instance) (ilos.Instance, bool) { + for _, vars := range e.Macro { + if v, ok := vars[key]; ok { + return v, ok + } + } + return nil, false +} + +func (e *Environment) SetMacro(key ilos.Instance, value ilos.Instance) { + for _, vars := range e.Macro { + if _, ok := vars[key]; ok { + vars[key] = value + return + } + } + e.Macro[0][key] = value +} + +func (e *Environment) GetDynamicVariable(key ilos.Instance) (ilos.Instance, bool) { + for _, vars := range e.DynamicVariable { + if v, ok := vars[key]; ok { + return v, ok + } + } + return nil, false +} + +func (e *Environment) SetDynamicVariable(key ilos.Instance, value ilos.Instance) { + for _, vars := range e.DynamicVariable { + if _, ok := vars[key]; ok { + vars[key] = value + return + } + } + e.DynamicVariable[0][key] = value +} + +// TopLevel is a global environment +var TopLevel = New() diff --git a/runtime/ilos/class/class.go b/runtime/ilos/class/class.go index e965201..d02b4e4 100644 --- a/runtime/ilos/class/class.go +++ b/runtime/ilos/class/class.go @@ -15,12 +15,11 @@ func (p *builtinclass) Parents() []ilos.Class { return p.parents } -func (i *builtinclass) GetSlotValue(key ilos.Instance) (ilos.Instance, bool) { - return nil, false +func (i *builtinclass) GetSlotValue(key string) ilos.Instance { + return nil } -func (i *builtinclass) SetSlotValue(key ilos.Instance, value ilos.Instance) bool { - return false +func (i *builtinclass) SetSlotValue(key string, value ilos.Instance) { } func (p *builtinclass) String() string { diff --git a/runtime/ilos/ilos.go b/runtime/ilos/ilos.go index e3d77e4..0b84447 100644 --- a/runtime/ilos/ilos.go +++ b/runtime/ilos/ilos.go @@ -3,15 +3,15 @@ package ilos type Class interface { Class() Class Parents() []Class - GetSlotValue(Instance) (Instance, bool) - SetSlotValue(Instance, Instance) bool + GetSlotValue(string) Instance + SetSlotValue(string, Instance) String() string } type Instance interface { Class() Class - GetSlotValue(Instance) (Instance, bool) - SetSlotValue(Instance, Instance) bool + GetSlotValue(string) Instance + SetSlotValue(string, Instance) String() string } diff --git a/runtime/ilos/instance/basic-array.go b/runtime/ilos/instance/basic-array.go index 883b710..1a0ab1f 100644 --- a/runtime/ilos/instance/basic-array.go +++ b/runtime/ilos/instance/basic-array.go @@ -16,24 +16,10 @@ type GeneralArrayStar struct { array map[[128]int]ilos.Instance } -func NewGeneralArrayStar(key ilos.Instance) ilos.Instance { +func NewGeneralArrayStar(key []ilos.Instance) ilos.Instance { dim := [128]int{} - cdr := key - idx := 0 - if !ilos.InstanceOf(key, class.List) { - return nil - } - if cdr.Class() == class.Null { - return &GeneralArrayStar{dim, map[[128]int]ilos.Instance{}} - } - for ilos.Instance(cdr, class.Cons) { - car := UnsafeCar(cdr) - cdr = UnsafeCdr(cdr) - if idx >= 128 || !ilos.InstanceOf(car, class.Integer) || !ilos.InstanceOf(cdr, class.List) || int(car.(Integer)) > 0 { - return nil - } - dim[idx] = int(car.(Integer)) - idx++ + for i, d := range key { + dim[i] = int(d.(Integer)) } return &GeneralArrayStar{dim, map[[128]int]ilos.Instance{}} } @@ -42,102 +28,79 @@ func (*GeneralArrayStar) Class() ilos.Class { return class.GeneralArrayStar } -func (a *GeneralArrayStar) GetSlotValue(key ilos.Instance) (ilos.Instance, bool) { - dim := [128]int{} - cdr := key - idx := 0 - if !ilos.InstanceOf(key, class.List) { - return nil, false - } - if a.dimension == dim && key.Class() == class.Null { - return a.array[dim], true - } - for ilos.Instance(cdr, class.Cons) { - car := UnsafeCar(cdr) - cdr = UnsafeCdr(cdr) - if idx >= 128 || !ilos.InstanceOf(car, class.Integer) || !ilos.InstanceOf(cdr, class.List) { - return nil, false +func (a *GeneralArrayStar) GetSlotValue(key string) ilos.Instance { + if key == "LENGTH" { + var r []ilos.Instance + for d := range a.dimension { + if d != 0 { + r = append(r, NewInteger(d)) + } } - dim[idx] = int(car.(Integer)) - idx++ - } - for i := range a.dimension { - if 0 >= dim[i] || dim[i] >= a.dimension[i] { - return nil, false + v := NewGeneralVector(len(r)) + for i, d := range r { + v.(GeneralVector)[i] = d } + return v } - return a.array[dim], true + return nil } -func (a *GeneralArrayStar) SetSlotValue(key ilos.Instance, value ilos.Instance) bool { - dim := [128]int{} - cdr := key - idx := 0 - if !ilos.InstanceOf(key, class.List) { - return false - } - if a.dimension == dim && ilos.InstanceOf(key, class.Null) { - a.array[dim] = value - return true - } - for ilos.InstanceOf(cdr, class.Cons) { - car := UnsafeCar(cdr) - cdr = UnsafeCdr(cdr) - if idx >= 128 || !ilos.InstanceOf(key, class.Integer) || !ilos.InstanceOf(cdr, class.List) { - return false - } - dim[idx] = int(car.(Integer)) - idx++ - } - for i := range a.dimension { - if 0 >= dim[i] || dim[i] >= a.dimension[i] { - return false - } - } - a.array[dim] = value - return true +func (a *GeneralArrayStar) SetSlotValue(key string, value ilos.Instance) { } func (a *GeneralArrayStar) String() string { return fmt.Sprint(a.array) } +func UnsafeGeneralArrayStarAccess(a ilos.Instance, k ilos.Instance) ilos.Instance { + var dim [128]int + for i, d := range k.(GeneralVector) { + dim[i] = int(d.(Integer)) + } + return a.(*GeneralArrayStar).array[dim] +} + +func UnsafeGeneralArrayStarAsign(a ilos.Instance, k ilos.Instance, v ilos.Instance) { + var dim [128]int + for i, d := range k.(GeneralVector) { + dim[i] = int(d.(Integer)) + } + a.(*GeneralArrayStar).array[dim] = v +} + // // General Vector // type GeneralVector []ilos.Instance -func NewGeneralVector(i []ilos.Instance) ilos.Instance { - return GeneralVector(i) +func NewGeneralVector(n int) ilos.Instance { + return GeneralVector(make([]ilos.Instance, n)) } func (GeneralVector) Class() ilos.Class { return class.GeneraVector } -func (i GeneralVector) GetSlotValue(key ilos.Instance) (ilos.Instance, bool) { - if ilos.InstanceOf(key, class.Symbol) && key.(Symbol) == "length" { - return Integer(len(i)), true - } - if ilos.InstanceOf(key, class.Integer) && int(key.(Integer)) < len(i) { - return i[key.(Integer)], true - } - return nil, false +func (i GeneralVector) GetSlotValue(key string) ilos.Instance { + return nil } -func (i GeneralVector) SetSlotValue(key ilos.Instance, value ilos.Instance) bool { - if ilos.InstanceOf(key, class.Integer) && int(key.(Integer)) < len(i) { - i[key.(Integer)] = value - return true - } - return false +func (i GeneralVector) SetSlotValue(key string, value ilos.Instance) { } func (i GeneralVector) String() string { return fmt.Sprint([]ilos.Instance(i)) } +func UnsafeGeneralVectorAccess(a ilos.Instance, k ilos.Instance) ilos.Instance { + return a.(GeneralVector)[k.(Integer)] +} + +func UnsafeGeneralVectorAsign(a ilos.Instance, k ilos.Instance, v ilos.Instance) { + a.(GeneralVector)[k.(Integer)] = v +} + // // String // @@ -152,22 +115,11 @@ func (String) Class() ilos.Class { return class.String } -func (i String) GetSlotValue(key ilos.Instance) (ilos.Instance, bool) { - if ilos.InstanceOf(key, class.Symbol) && key.(Symbol) == "length" { - return Integer(len(i)), true - } - if ilos.InstanceOf(key, class.Integer) && int(key.(Integer)) < len(i) { - return Character(i[key.(Integer)]), true - } - return nil, false +func (i String) GetSlotValue(key string) ilos.Instance { + return nil } -func (i String) SetSlotValue(key ilos.Instance, value ilos.Instance) bool { - if ilos.InstanceOf(key, class.Integer) && int(key.(Integer)) < len(i) { - i[key.(Integer)] = rune(value.(Character)) - return true - } - return false +func (i String) SetSlotValue(key string, value ilos.Instance) { } func (i String) String() string { diff --git a/runtime/ilos/instance/character.go b/runtime/ilos/instance/character.go index d6c5148..fc0fec8 100644 --- a/runtime/ilos/instance/character.go +++ b/runtime/ilos/instance/character.go @@ -19,13 +19,13 @@ func (Character) Class() ilos.Class { return class.Character } -func (i Character) GetSlotValue(key ilos.Instance) (ilos.Instance, bool) { - return nil, false +func (i Character) GetSlotValue(key string) ilos.Instance { + return nil } -func (i Character) SetSlotValue(key ilos.Instance, value ilos.Instance) bool { - return false +func (i Character) SetSlotValue(key string, value ilos.Instance) { } + func (i Character) String() string { return string(i) } diff --git a/runtime/ilos/instance/function.go b/runtime/ilos/instance/function.go new file mode 100644 index 0000000..d4bfa13 --- /dev/null +++ b/runtime/ilos/instance/function.go @@ -0,0 +1,93 @@ +package instance + +import ( + "fmt" + + "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/ilos" + "github.com/ta2gch/iris/runtime/ilos/class" +) + +type Function func(ilos.Instance, environment.Environment, environment.Environment) (ilos.Instance, ilos.Instance) + +func NewFunction(f func(ilos.Instance, environment.Environment, environment.Environment) (ilos.Instance, ilos.Instance)) ilos.Instance { + return Function(f) +} + +func (Function) Class() ilos.Class { + return class.Function +} + +func (Function) GetSlotValue(key string) ilos.Instance { + return nil +} + +func (Function) SetSlotValue(key string, value ilos.Instance) { +} + +func (f Function) String() string { + return fmt.Sprintf("#instance[%v]", f.Class()) +} + +func UnsafeFunctionCall(f ilos.Instance, a ilos.Instance, l environment.Environment, g environment.Environment) (ilos.Instance, ilos.Instance) { + success, fail := f.(Function)(a, l, g) + return success, fail +} + +type GenericFunction map[[128]ilos.Class]Function + +func (GenericFunction) Class() ilos.Class { + return class.GenericFunction +} + +func (GenericFunction) GetSlotValue(key string) ilos.Instance { + return nil +} + +func (GenericFunction) SetSlotValue(key string, value ilos.Instance) { +} + +func (f GenericFunction) String() string { + return fmt.Sprintf("#instance[%v]", f.Class()) +} + +func UnsafeGenericFunctionCall(f ilos.Instance, a ilos.Instance, l environment.Environment, g environment.Environment) (ilos.Instance, ilos.Instance) { + var types [128]ilos.Class + cdr := a + idx := 0 + for ilos.InstanceOf(cdr, class.Cons) { + types[idx] = cdr.Class() + idx++ + } + success, fail := f.(GenericFunction)[types](a, l, g) + return success, fail +} + +type StandardGenericFunction map[[128]ilos.Class]Function + +func (StandardGenericFunction) Class() ilos.Class { + return class.StandardGenericFunction +} + +func (StandardGenericFunction) GetSlotValue(key string) ilos.Instance { + return nil +} + +func (StandardGenericFunction) SetSlotValue(key string, value ilos.Instance) { +} + +func (f StandardGenericFunction) String() string { + return fmt.Sprintf("#instance[%v]", f.Class()) +} + +func UnsafeStandardGenericFunctionCall(f ilos.Instance, a ilos.Instance, l environment.Environment, g environment.Environment) (ilos.Instance, ilos.Instance) { + var types [128]ilos.Class + cdr := a + idx := 0 + for ilos.InstanceOf(cdr, class.Cons) { + types[idx] = cdr.Class() + idx++ + } + success, fail := f.(StandardGenericFunction)[types](a, l, g) + return success, fail +} diff --git a/runtime/ilos/instance/instance.go b/runtime/ilos/instance/instance.go index 30e761c..0725051 100644 --- a/runtime/ilos/instance/instance.go +++ b/runtime/ilos/instance/instance.go @@ -4,7 +4,6 @@ import ( "fmt" "github.com/ta2gch/iris/runtime/ilos" - "github.com/ta2gch/iris/runtime/ilos/class" ) // @@ -13,36 +12,22 @@ import ( type instance struct { class ilos.Class - slots map[ilos.Instance]ilos.Instance + slots map[string]ilos.Instance } func (i *instance) Class() ilos.Class { return i.class } -func (i *instance) GetSlotValue(key ilos.Instance) (ilos.Instance, bool) { - v, ok := i.slots[key] - return v, ok +func (i *instance) GetSlotValue(key string) ilos.Instance { + v, _ := i.slots[key] + return v } -func (i *instance) SetSlotValue(key ilos.Instance, value ilos.Instance) bool { - i.slots[key.(Symbol)] = value - return true +func (i *instance) SetSlotValue(key string, value ilos.Instance) { + i.slots[key] = value } func (i *instance) String() string { return fmt.Sprintf("#INSTANCE[%v %v]", i.class, i.slots) } - -// -// ParseError -// - -func NewParseError(s string, ec ilos.Class) ilos.Instance { - i := new(instance) - i.class = class.ParseError - i.slots = map[ilos.Instance]ilos.Instance{} - i.slots[NewSymbol("STRING")] = NewString(s) - i.slots[NewSymbol("EXPECTED-CLASS")] = ec - return i -} diff --git a/runtime/ilos/instance/list.go b/runtime/ilos/instance/list.go index 5afff33..533d7ea 100644 --- a/runtime/ilos/instance/list.go +++ b/runtime/ilos/instance/list.go @@ -24,34 +24,11 @@ func (*Cons) Class() ilos.Class { return class.Cons } -func (i *Cons) GetSlotValue(key ilos.Instance) (ilos.Instance, bool) { - if !ilos.InstanceOf(key, class.Symbol) { - return nil, false - } - switch key.(Symbol) { - case "CAR": - return i.car, true - case "CDR": - return i.cdr, true - default: - return nil, false - } +func (i *Cons) GetSlotValue(key string) ilos.Instance { + return nil } -func (i *Cons) SetSlotValue(key ilos.Instance, value ilos.Instance) bool { - if !ilos.InstanceOf(key, class.Symbol) { - return false - } - switch key.(Symbol) { - case "CAR": - i.car = value - return true - case "CDR": - i.cdr = value - return true - default: - return false - } +func (i *Cons) SetSlotValue(key string, value ilos.Instance) { } func (i *Cons) String() string { @@ -80,12 +57,11 @@ func (*Null) Class() ilos.Class { return class.Null } -func (i *Null) GetSlotValue(key ilos.Instance) (ilos.Instance, bool) { - return nil, false +func (i *Null) GetSlotValue(key string) ilos.Instance { + return nil } -func (i *Null) SetSlotValue(key ilos.Instance, value ilos.Instance) bool { - return false +func (i *Null) SetSlotValue(key string, value ilos.Instance) { } func (*Null) String() string { diff --git a/runtime/ilos/instance/number.go b/runtime/ilos/instance/number.go index fc1acbf..7ac4905 100644 --- a/runtime/ilos/instance/number.go +++ b/runtime/ilos/instance/number.go @@ -21,12 +21,12 @@ func (Integer) Class() ilos.Class { return class.Integer } -func (i Integer) GetSlotValue(key ilos.Instance) (ilos.Instance, bool) { - return nil, false +func (i Integer) GetSlotValue(key string) ilos.Instance { + return nil } -func (i Integer) SetSlotValue(key ilos.Instance, value ilos.Instance) bool { - return false +func (i Integer) SetSlotValue(key string, value ilos.Instance) { + return } func (i Integer) String() string { @@ -47,12 +47,12 @@ func (Float) Class() ilos.Class { return class.Float } -func (i Float) GetSlotValue(key ilos.Instance) (ilos.Instance, bool) { - return nil, false +func (i Float) GetSlotValue(key string) ilos.Instance { + return nil } -func (i Float) SetSlotValue(key ilos.Instance, value ilos.Instance) bool { - return false +func (i Float) SetSlotValue(key string, value ilos.Instance) { + return } func (i Float) String() string { diff --git a/runtime/ilos/instance/serious-error.go b/runtime/ilos/instance/serious-error.go new file mode 100644 index 0000000..e2fe073 --- /dev/null +++ b/runtime/ilos/instance/serious-error.go @@ -0,0 +1,63 @@ +package instance + +import ( + "github.com/ta2gch/iris/runtime/ilos" + "github.com/ta2gch/iris/runtime/ilos/class" +) + +// +// ParseError +// + +func NewArithmeticError(operation, operands ilos.Instance) ilos.Instance { + i := new(instance) + i.class = class.ArithmeticError + i.slots = map[string]ilos.Instance{} + i.slots["OPERATION"] = operation + i.slots["OPERANDS"] = operands + return i +} + +func NewDomainError(object, expectedClass ilos.Instance) ilos.Instance { + i := new(instance) + i.class = class.DomainError + i.slots = map[string]ilos.Instance{} + i.slots["STRING"] = object + i.slots["EXPECTED-CLASS"] = expectedClass + return i +} + +func NewParseError(str, expectedClass ilos.Instance) ilos.Instance { + i := new(instance) + i.class = class.ParseError + i.slots = map[string]ilos.Instance{} + i.slots["STRING"] = str + i.slots["EXPECTED-CLASS"] = expectedClass + return i +} + +func NewSimpleError(formatString, formatArguments ilos.Instance) ilos.Instance { + i := new(instance) + i.class = class.SimpleError + i.slots = map[string]ilos.Instance{} + i.slots["FORMAT-STRING"] = formatString + i.slots["FORMAT-ARGUMENTS"] = formatArguments + return i +} + +func NewStreamError(stream ilos.Instance) ilos.Instance { + i := new(instance) + i.class = class.StreamError + i.slots = map[string]ilos.Instance{} + i.slots["stream"] = stream + return i +} + +func NewUndefinedEntityError(name, namespace ilos.Instance) ilos.Instance { + i := new(instance) + i.class = class.StreamError + i.slots = map[string]ilos.Instance{} + i.slots["NAME"] = name + i.slots["NAMESPACE"] = namespace + return i +} diff --git a/runtime/ilos/instance/symbol.go b/runtime/ilos/instance/symbol.go index cb895ed..507b6e0 100644 --- a/runtime/ilos/instance/symbol.go +++ b/runtime/ilos/instance/symbol.go @@ -19,12 +19,12 @@ func (Symbol) Class() ilos.Class { return class.Symbol } -func (i Symbol) GetSlotValue(key ilos.Instance) (ilos.Instance, bool) { - return nil, false +func (i Symbol) GetSlotValue(key string) ilos.Instance { + return nil } -func (i Symbol) SetSlotValue(key ilos.Instance, value ilos.Instance) bool { - return false +func (i Symbol) SetSlotValue(key string, value ilos.Instance) { + return } func (i Symbol) String() string { From 2ea1acabafa4410e69781631f4c3e0ad4fc6c3b7 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Thu, 3 Aug 2017 12:34:00 +0900 Subject: [PATCH 077/228] Updated new ILOS --- runtime/ilos/class/class.go | 4 +- runtime/ilos/ilos.go | 8 +-- runtime/ilos/instance/basic-array.go | 90 ++++++++++++++++------------ runtime/ilos/instance/character.go | 4 +- runtime/ilos/instance/function.go | 73 +++++++++++----------- runtime/ilos/instance/instance.go | 8 +-- runtime/ilos/instance/list.go | 8 +-- runtime/ilos/instance/number.go | 8 +-- runtime/ilos/instance/symbol.go | 4 +- 9 files changed, 110 insertions(+), 97 deletions(-) diff --git a/runtime/ilos/class/class.go b/runtime/ilos/class/class.go index d02b4e4..176247e 100644 --- a/runtime/ilos/class/class.go +++ b/runtime/ilos/class/class.go @@ -15,11 +15,11 @@ func (p *builtinclass) Parents() []ilos.Class { return p.parents } -func (i *builtinclass) GetSlotValue(key string) ilos.Instance { +func (i *builtinclass) GetSlotValue(key ilos.Instance) ilos.Instance { return nil } -func (i *builtinclass) SetSlotValue(key string, value ilos.Instance) { +func (i *builtinclass) SetSlotValue(key ilos.Instance, value ilos.Instance) { } func (p *builtinclass) String() string { diff --git a/runtime/ilos/ilos.go b/runtime/ilos/ilos.go index 0b84447..94ad35e 100644 --- a/runtime/ilos/ilos.go +++ b/runtime/ilos/ilos.go @@ -3,15 +3,15 @@ package ilos type Class interface { Class() Class Parents() []Class - GetSlotValue(string) Instance - SetSlotValue(string, Instance) + GetSlotValue(Instance) Instance + SetSlotValue(Instance, Instance) String() string } type Instance interface { Class() Class - GetSlotValue(string) Instance - SetSlotValue(string, Instance) + GetSlotValue(Instance) Instance + SetSlotValue(Instance, Instance) String() string } diff --git a/runtime/ilos/instance/basic-array.go b/runtime/ilos/instance/basic-array.go index 1a0ab1f..7eaa5b6 100644 --- a/runtime/ilos/instance/basic-array.go +++ b/runtime/ilos/instance/basic-array.go @@ -28,46 +28,48 @@ func (*GeneralArrayStar) Class() ilos.Class { return class.GeneralArrayStar } -func (a *GeneralArrayStar) GetSlotValue(key string) ilos.Instance { - if key == "LENGTH" { - var r []ilos.Instance - for d := range a.dimension { - if d != 0 { - r = append(r, NewInteger(d)) +func (a *GeneralArrayStar) GetSlotValue(key ilos.Instance) ilos.Instance { + if ilos.InstanceOf(key, class.Symbol) && key.(Symbol) == "LENGTH" { + cons := NewNull() + for i := 128; i > 0; i-- { + if a.dimension[i-1] != 0 { + cons = NewCons(NewInteger(a.dimension[i-1]), cons) } } - v := NewGeneralVector(len(r)) - for i, d := range r { - v.(GeneralVector)[i] = d + return cons + } + if ilos.InstanceOf(key, class.List) { + dim := [128]int{} + idx := 0 + cdr := key + for ilos.InstanceOf(cdr, class.Cons) { + dim[idx] = int(UnsafeCar(cdr).(Integer)) + cdr = UnsafeCdr(cdr) + idx++ } - return v + return a.array[dim] } return nil } -func (a *GeneralArrayStar) SetSlotValue(key string, value ilos.Instance) { +func (a *GeneralArrayStar) SetSlotValue(key ilos.Instance, value ilos.Instance) { + if ilos.InstanceOf(key, class.List) { + dim := [128]int{} + idx := 0 + cdr := key + for ilos.InstanceOf(cdr, class.Cons) { + dim[idx] = int(UnsafeCar(cdr).(Integer)) + cdr = UnsafeCdr(cdr) + idx++ + } + a.array[dim] = value + } } func (a *GeneralArrayStar) String() string { return fmt.Sprint(a.array) } -func UnsafeGeneralArrayStarAccess(a ilos.Instance, k ilos.Instance) ilos.Instance { - var dim [128]int - for i, d := range k.(GeneralVector) { - dim[i] = int(d.(Integer)) - } - return a.(*GeneralArrayStar).array[dim] -} - -func UnsafeGeneralArrayStarAsign(a ilos.Instance, k ilos.Instance, v ilos.Instance) { - var dim [128]int - for i, d := range k.(GeneralVector) { - dim[i] = int(d.(Integer)) - } - a.(*GeneralArrayStar).array[dim] = v -} - // // General Vector // @@ -82,25 +84,26 @@ func (GeneralVector) Class() ilos.Class { return class.GeneraVector } -func (i GeneralVector) GetSlotValue(key string) ilos.Instance { +func (i GeneralVector) GetSlotValue(key ilos.Instance) ilos.Instance { + if ilos.InstanceOf(key, class.Symbol) && key.(Symbol) == "LENGTH" { + return NewInteger(len(i)) + } + if ilos.InstanceOf(key, class.Integer) { + return i[int(key.(Integer))] + } return nil } -func (i GeneralVector) SetSlotValue(key string, value ilos.Instance) { +func (i GeneralVector) SetSlotValue(key ilos.Instance, value ilos.Instance) { + if ilos.InstanceOf(key, class.Integer) { + i[int(key.(Integer))] = value + } } func (i GeneralVector) String() string { return fmt.Sprint([]ilos.Instance(i)) } -func UnsafeGeneralVectorAccess(a ilos.Instance, k ilos.Instance) ilos.Instance { - return a.(GeneralVector)[k.(Integer)] -} - -func UnsafeGeneralVectorAsign(a ilos.Instance, k ilos.Instance, v ilos.Instance) { - a.(GeneralVector)[k.(Integer)] = v -} - // // String // @@ -115,11 +118,20 @@ func (String) Class() ilos.Class { return class.String } -func (i String) GetSlotValue(key string) ilos.Instance { +func (i String) GetSlotValue(key ilos.Instance) ilos.Instance { + if ilos.InstanceOf(key, class.Symbol) && key.(Symbol) == "LENGTH" { + return NewInteger(len(i)) + } + if ilos.InstanceOf(key, class.Integer) { + return NewCharacter(i[int(key.(Integer))]) + } return nil } -func (i String) SetSlotValue(key string, value ilos.Instance) { +func (i String) SetSlotValue(key ilos.Instance, value ilos.Instance) { + if ilos.InstanceOf(key, class.Integer) { + i[int(key.(Integer))] = rune(value.(Character)) + } } func (i String) String() string { diff --git a/runtime/ilos/instance/character.go b/runtime/ilos/instance/character.go index fc0fec8..e5704dd 100644 --- a/runtime/ilos/instance/character.go +++ b/runtime/ilos/instance/character.go @@ -19,11 +19,11 @@ func (Character) Class() ilos.Class { return class.Character } -func (i Character) GetSlotValue(key string) ilos.Instance { +func (i Character) GetSlotValue(key ilos.Instance) ilos.Instance { return nil } -func (i Character) SetSlotValue(key string, value ilos.Instance) { +func (i Character) SetSlotValue(key ilos.Instance, value ilos.Instance) { } func (i Character) String() string { diff --git a/runtime/ilos/instance/function.go b/runtime/ilos/instance/function.go index d4bfa13..477b810 100644 --- a/runtime/ilos/instance/function.go +++ b/runtime/ilos/instance/function.go @@ -18,49 +18,47 @@ func (Function) Class() ilos.Class { return class.Function } -func (Function) GetSlotValue(key string) ilos.Instance { - return nil +func (f Function) GetSlotValue(key ilos.Instance) ilos.Instance { + return f } -func (Function) SetSlotValue(key string, value ilos.Instance) { +func (Function) SetSlotValue(key ilos.Instance, value ilos.Instance) { } func (f Function) String() string { return fmt.Sprintf("#instance[%v]", f.Class()) } -func UnsafeFunctionCall(f ilos.Instance, a ilos.Instance, l environment.Environment, g environment.Environment) (ilos.Instance, ilos.Instance) { - success, fail := f.(Function)(a, l, g) - return success, fail -} - type GenericFunction map[[128]ilos.Class]Function func (GenericFunction) Class() ilos.Class { return class.GenericFunction } -func (GenericFunction) GetSlotValue(key string) ilos.Instance { - return nil -} - -func (GenericFunction) SetSlotValue(key string, value ilos.Instance) { -} - -func (f GenericFunction) String() string { - return fmt.Sprintf("#instance[%v]", f.Class()) +func (f GenericFunction) GetSlotValue(key ilos.Instance) ilos.Instance { + types := [128]ilos.Class{} + cdr := key + idx := 0 + for ilos.InstanceOf(cdr, class.Cons) { + types[idx] = cdr.Class() + idx++ + } + return f[types] } -func UnsafeGenericFunctionCall(f ilos.Instance, a ilos.Instance, l environment.Environment, g environment.Environment) (ilos.Instance, ilos.Instance) { - var types [128]ilos.Class - cdr := a +func (f GenericFunction) SetSlotValue(key ilos.Instance, value ilos.Instance) { + types := [128]ilos.Class{} + cdr := key idx := 0 for ilos.InstanceOf(cdr, class.Cons) { types[idx] = cdr.Class() idx++ } - success, fail := f.(GenericFunction)[types](a, l, g) - return success, fail + f[types] = value.(Function) +} + +func (f GenericFunction) String() string { + return fmt.Sprintf("#instance[%v]", f.Class()) } type StandardGenericFunction map[[128]ilos.Class]Function @@ -69,25 +67,28 @@ func (StandardGenericFunction) Class() ilos.Class { return class.StandardGenericFunction } -func (StandardGenericFunction) GetSlotValue(key string) ilos.Instance { - return nil -} - -func (StandardGenericFunction) SetSlotValue(key string, value ilos.Instance) { -} - -func (f StandardGenericFunction) String() string { - return fmt.Sprintf("#instance[%v]", f.Class()) +func (f StandardGenericFunction) GetSlotValue(key ilos.Instance) ilos.Instance { + types := [128]ilos.Class{} + cdr := key + idx := 0 + for ilos.InstanceOf(cdr, class.Cons) { + types[idx] = cdr.Class() + idx++ + } + return f[types] } -func UnsafeStandardGenericFunctionCall(f ilos.Instance, a ilos.Instance, l environment.Environment, g environment.Environment) (ilos.Instance, ilos.Instance) { - var types [128]ilos.Class - cdr := a +func (f StandardGenericFunction) SetSlotValue(key ilos.Instance, value ilos.Instance) { + types := [128]ilos.Class{} + cdr := key idx := 0 for ilos.InstanceOf(cdr, class.Cons) { types[idx] = cdr.Class() idx++ } - success, fail := f.(StandardGenericFunction)[types](a, l, g) - return success, fail + f[types] = value.(Function) +} + +func (f StandardGenericFunction) String() string { + return fmt.Sprintf("#instance[%v]", f.Class()) } diff --git a/runtime/ilos/instance/instance.go b/runtime/ilos/instance/instance.go index 0725051..f8fa6c0 100644 --- a/runtime/ilos/instance/instance.go +++ b/runtime/ilos/instance/instance.go @@ -19,13 +19,13 @@ func (i *instance) Class() ilos.Class { return i.class } -func (i *instance) GetSlotValue(key string) ilos.Instance { - v, _ := i.slots[key] +func (i *instance) GetSlotValue(key ilos.Instance) ilos.Instance { + v, _ := i.slots[string(key.(Symbol))] return v } -func (i *instance) SetSlotValue(key string, value ilos.Instance) { - i.slots[key] = value +func (i *instance) SetSlotValue(key ilos.Instance, value ilos.Instance) { + i.slots[string(key.(Symbol))] = value } func (i *instance) String() string { diff --git a/runtime/ilos/instance/list.go b/runtime/ilos/instance/list.go index 533d7ea..72984ca 100644 --- a/runtime/ilos/instance/list.go +++ b/runtime/ilos/instance/list.go @@ -24,11 +24,11 @@ func (*Cons) Class() ilos.Class { return class.Cons } -func (i *Cons) GetSlotValue(key string) ilos.Instance { +func (i *Cons) GetSlotValue(key ilos.Instance) ilos.Instance { return nil } -func (i *Cons) SetSlotValue(key string, value ilos.Instance) { +func (i *Cons) SetSlotValue(key ilos.Instance, value ilos.Instance) { } func (i *Cons) String() string { @@ -57,11 +57,11 @@ func (*Null) Class() ilos.Class { return class.Null } -func (i *Null) GetSlotValue(key string) ilos.Instance { +func (i *Null) GetSlotValue(key ilos.Instance) ilos.Instance { return nil } -func (i *Null) SetSlotValue(key string, value ilos.Instance) { +func (i *Null) SetSlotValue(key ilos.Instance, value ilos.Instance) { } func (*Null) String() string { diff --git a/runtime/ilos/instance/number.go b/runtime/ilos/instance/number.go index 7ac4905..03f6f29 100644 --- a/runtime/ilos/instance/number.go +++ b/runtime/ilos/instance/number.go @@ -21,11 +21,11 @@ func (Integer) Class() ilos.Class { return class.Integer } -func (i Integer) GetSlotValue(key string) ilos.Instance { +func (i Integer) GetSlotValue(key ilos.Instance) ilos.Instance { return nil } -func (i Integer) SetSlotValue(key string, value ilos.Instance) { +func (i Integer) SetSlotValue(key ilos.Instance, value ilos.Instance) { return } @@ -47,11 +47,11 @@ func (Float) Class() ilos.Class { return class.Float } -func (i Float) GetSlotValue(key string) ilos.Instance { +func (i Float) GetSlotValue(key ilos.Instance) ilos.Instance { return nil } -func (i Float) SetSlotValue(key string, value ilos.Instance) { +func (i Float) SetSlotValue(key ilos.Instance, value ilos.Instance) { return } diff --git a/runtime/ilos/instance/symbol.go b/runtime/ilos/instance/symbol.go index 507b6e0..e04c9d1 100644 --- a/runtime/ilos/instance/symbol.go +++ b/runtime/ilos/instance/symbol.go @@ -19,11 +19,11 @@ func (Symbol) Class() ilos.Class { return class.Symbol } -func (i Symbol) GetSlotValue(key string) ilos.Instance { +func (i Symbol) GetSlotValue(key ilos.Instance) ilos.Instance { return nil } -func (i Symbol) SetSlotValue(key string, value ilos.Instance) { +func (i Symbol) SetSlotValue(key ilos.Instance, value ilos.Instance) { return } From 187516e5ccdb96cf0dd740372c8f0ef2a55bfb19 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Thu, 3 Aug 2017 14:02:22 +0900 Subject: [PATCH 078/228] function and variable --- .runtime_old/eval_test.go | 85 ------------------ runtime/eval.go | 120 +++++++++++++++++++++++++ runtime/eval_test.go | 75 ++++++++++++++++ runtime/ilos/instance/basic-array.go | 7 +- runtime/ilos/instance/function.go | 4 +- runtime/ilos/instance/serious-error.go | 2 +- 6 files changed, 201 insertions(+), 92 deletions(-) delete mode 100644 .runtime_old/eval_test.go create mode 100644 runtime/eval.go create mode 100644 runtime/eval_test.go diff --git a/.runtime_old/eval_test.go b/.runtime_old/eval_test.go deleted file mode 100644 index 91df167..0000000 --- a/.runtime_old/eval_test.go +++ /dev/null @@ -1,85 +0,0 @@ -package runtime - -import ( - "reflect" - "strings" - "testing" - - "github.com/ta2gch/iris/reader/parser" - "github.com/ta2gch/iris/reader/tokenizer" - "github.com/ta2gch/iris/runtime/class" - "github.com/ta2gch/iris/runtime/class/cons" - env "github.com/ta2gch/iris/runtime/environment" -) - -func read(s string) class.Instance { - e, _ := parser.Parse(tokenizer.New(strings.NewReader(s))) - return e -} - -func TestEval(t *testing.T) { - local := env.New() - global := env.New() - local.SetVariable(class.Symbol.New("pi"), class.Float.New(3.14)) - local.SetFunction(class.Symbol.New("inc"), NewNativeFunction(func(args class.Instance, local *env.Environment, global *env.Environment) (class.Instance, class.Instance) { - car, _ := cons.Car(args) - return class.Integer.New(car.Value().(int) + 1), nil - })) - local.SetMacro(class.Symbol.New("minc"), NewNativeFunction(func(args class.Instance, local *env.Environment, global *env.Environment) (class.Instance, class.Instance) { - ret, _ := Eval(cons.New(class.Symbol.New("inc"), args), local, global) - return ret, nil - })) - global.SetMacro(class.Symbol.New("lambda"), NewNativeFunction(func(args class.Instance, local *env.Environment, global *env.Environment) (class.Instance, class.Instance) { - car, _ := cons.Car(args) - cdr, _ := cons.Cdr(args) - return NewLambdaFunction(car, cdr, local), nil - })) - type args struct { - obj class.Instance - local *env.Environment - global *env.Environment - } - tests := []struct { - name string - args args - want class.Instance - wantErr bool - }{ - { - name: "local variable", - args: args{class.Symbol.New("pi"), local, global}, - want: class.Float.New(3.14), - wantErr: false, - }, - { - name: "local function", - args: args{read("(inc (inc 1))"), local, global}, - want: class.Integer.New(3), - wantErr: false, - }, - { - name: "local macro", - args: args{read("(minc (minc 1))"), local, global}, - want: class.Integer.New(3), - wantErr: false, - }, - { - name: "lambda", - args: args{read("((lambda (x) (minc x)) 1)"), local, global}, - want: class.Integer.New(2), - wantErr: false, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, err := Eval(tt.args.obj, tt.args.local, tt.args.global) - if (err != nil) != tt.wantErr { - t.Errorf("Eval() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !reflect.DeepEqual(got, tt.want) { - t.Errorf("Eval() = %v, want %v", got, tt.want) - } - }) - } -} diff --git a/runtime/eval.go b/runtime/eval.go new file mode 100644 index 0000000..e05a023 --- /dev/null +++ b/runtime/eval.go @@ -0,0 +1,120 @@ +package runtime + +import ( + env "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/ilos" + "github.com/ta2gch/iris/runtime/ilos/class" + "github.com/ta2gch/iris/runtime/ilos/instance" +) + +func evalArguments(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { + if ilos.InstanceOf(args, class.Null) { + return instance.NewNull(), nil + } + car := instance.UnsafeCar(args) + cdr := instance.UnsafeCdr(args) + a, err := Eval(car, local, global) + if err != nil { + return nil, err + } + b, err := evalArguments(cdr, local, global) + if err != nil { + return nil, err + } + return instance.NewCons(a, b), nil +} + +func evalFunction(obj ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { + // get function symbol + car := instance.UnsafeCar(obj) + + // get function arguments + cdr := instance.UnsafeCdr(obj) + + // eval if lambda form + if ilos.InstanceOf(car, class.Cons) { + caar := instance.UnsafeCar(car) + if caar == instance.NewSymbol("lambda") { + fun, err := Eval(car, local, global) + if err != nil { + return nil, err + } + args, err := evalArguments(cdr, local, global) + if err != nil { + return nil, err + } + env := env.New() + env.MergeDynamicVariable(local) + ret, err := fun.(instance.Function)(args, env, global) + if err != nil { + return nil, err + } + return ret, nil + } + } + + if !ilos.InstanceOf(car, class.Symbol) { + return nil, instance.NewDomainError(car, class.Symbol) + } + // get macro instance has value of Function interface + var mac ilos.Instance + if m, ok := local.GetMacro(car); ok { + mac = m + } + if m, ok := global.GetMacro(car); ok { + mac = m + } + if mac != nil { + ret, err := mac.(instance.Function)(cdr, local, global) + if err != nil { + return nil, err + } + return ret, nil + } + // get function instance has value of Function interface + var fun ilos.Instance + if f, ok := local.GetFunction(car); ok { + fun = f + } + if f, ok := global.GetFunction(car); ok { + fun = f + } + if fun != nil { + args, err := evalArguments(cdr, local, global) + if err != nil { + return nil, err + } + env := env.New() + env.MergeDynamicVariable(local) + ret, err := fun.(instance.Function)(args, env, global) + if err != nil { + return nil, err + } + return ret, nil + } + return nil, instance.NewUndefinedEntityError(nil, nil) +} + +// Eval evaluates any classs +func Eval(obj ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { + if ilos.InstanceOf(obj, class.Null) { + return instance.NewNull(), nil + } + if ilos.InstanceOf(obj, class.Symbol) { + if val, ok := local.GetVariable(obj); ok { + return val, nil + } + if val, ok := global.GetVariable(obj); ok { + return val, nil + } + return nil, instance.NewUndefinedEntityError(nil, nil) + } + if ilos.InstanceOf(obj, class.Cons) { + ret, err := evalFunction(obj, local, global) + if err != nil { + return nil, err + } + return ret, nil + } + return obj, nil +} diff --git a/runtime/eval_test.go b/runtime/eval_test.go new file mode 100644 index 0000000..19e93b9 --- /dev/null +++ b/runtime/eval_test.go @@ -0,0 +1,75 @@ +package runtime + +import ( + "reflect" + "strings" + "testing" + + "github.com/ta2gch/iris/reader/parser" + "github.com/ta2gch/iris/reader/tokenizer" + + env "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/ilos" + "github.com/ta2gch/iris/runtime/ilos/instance" +) + +func read(s string) ilos.Instance { + e, _ := parser.Parse(tokenizer.New(strings.NewReader(s))) + return e +} + +func TestEval(t *testing.T) { + local := env.New() + global := env.New() + local.SetVariable(instance.NewSymbol("PI"), instance.NewFloat(3.14)) + local.SetFunction(instance.NewSymbol("INC"), instance.NewFunction(func(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { + car := instance.UnsafeCar(args) + return instance.NewInteger(int(car.(instance.Integer)) + 1), nil + })) + local.SetMacro(instance.NewSymbol("MINC"), instance.NewFunction(func(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { + ret, _ := Eval(instance.NewCons(instance.NewSymbol("INC"), args), local, global) + return ret, nil + })) + type args struct { + obj ilos.Instance + local *env.Environment + global *env.Environment + } + tests := []struct { + name string + args args + want ilos.Instance + wantErr bool + }{ + { + name: "local variable", + args: args{instance.NewSymbol("PI"), local, global}, + want: instance.NewFloat(3.14), + wantErr: false, + }, + { + name: "local function", + args: args{read("(inc (inc 1))"), local, global}, + want: instance.NewInteger(3), + wantErr: false, + }, + { + name: "local macro", + args: args{read("(minc (minc 1))"), local, global}, + want: instance.NewInteger(3), + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := Eval(tt.args.obj, tt.args.local, tt.args.global) + if (err != nil) != tt.wantErr { + t.Errorf("Eval() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("Eval() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/runtime/ilos/instance/basic-array.go b/runtime/ilos/instance/basic-array.go index 7eaa5b6..c6aacfd 100644 --- a/runtime/ilos/instance/basic-array.go +++ b/runtime/ilos/instance/basic-array.go @@ -1,8 +1,7 @@ package instance import ( - "fmt" - + "github.com/k0kubun/pp" "github.com/ta2gch/iris/runtime/ilos" "github.com/ta2gch/iris/runtime/ilos/class" ) @@ -67,7 +66,7 @@ func (a *GeneralArrayStar) SetSlotValue(key ilos.Instance, value ilos.Instance) } func (a *GeneralArrayStar) String() string { - return fmt.Sprint(a.array) + return pp.Sprint(a.array) } // @@ -101,7 +100,7 @@ func (i GeneralVector) SetSlotValue(key ilos.Instance, value ilos.Instance) { } func (i GeneralVector) String() string { - return fmt.Sprint([]ilos.Instance(i)) + return pp.Sprint([]ilos.Instance(i)) } // diff --git a/runtime/ilos/instance/function.go b/runtime/ilos/instance/function.go index 477b810..1a4005e 100644 --- a/runtime/ilos/instance/function.go +++ b/runtime/ilos/instance/function.go @@ -8,9 +8,9 @@ import ( "github.com/ta2gch/iris/runtime/ilos/class" ) -type Function func(ilos.Instance, environment.Environment, environment.Environment) (ilos.Instance, ilos.Instance) +type Function func(ilos.Instance, *environment.Environment, *environment.Environment) (ilos.Instance, ilos.Instance) -func NewFunction(f func(ilos.Instance, environment.Environment, environment.Environment) (ilos.Instance, ilos.Instance)) ilos.Instance { +func NewFunction(f func(ilos.Instance, *environment.Environment, *environment.Environment) (ilos.Instance, ilos.Instance)) ilos.Instance { return Function(f) } diff --git a/runtime/ilos/instance/serious-error.go b/runtime/ilos/instance/serious-error.go index e2fe073..98d6af7 100644 --- a/runtime/ilos/instance/serious-error.go +++ b/runtime/ilos/instance/serious-error.go @@ -55,7 +55,7 @@ func NewStreamError(stream ilos.Instance) ilos.Instance { func NewUndefinedEntityError(name, namespace ilos.Instance) ilos.Instance { i := new(instance) - i.class = class.StreamError + i.class = class.UndefinedEntity i.slots = map[string]ilos.Instance{} i.slots["NAME"] = name i.slots["NAMESPACE"] = namespace From 0eb28a6e8f0c2c7cc3f8f6f6318fced5bddbb0d7 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Thu, 3 Aug 2017 14:48:13 +0900 Subject: [PATCH 079/228] Added lambda form --- .runtime_old/class/builtin.go | 68 --------- .runtime_old/class/class.go | 41 ------ .runtime_old/class/cons/cons.go | 66 --------- .runtime_old/class/domainerror/domainerror.go | 32 ----- .runtime_old/class/function/function.go | 22 --- .runtime_old/class/instance.go | 36 ----- .runtime_old/class/meta.go | 32 ----- .runtime_old/class/parseerror/parseerror.go | 32 ----- .runtime_old/eval.go | 134 ------------------ .runtime_old/init.go | 27 ---- .runtime_old/lambda.go | 79 ----------- .runtime_old/native.go | 22 --- runtime/eval.go | 2 +- runtime/eval_test.go | 9 ++ runtime/lambda.go | 44 ++++++ 15 files changed, 54 insertions(+), 592 deletions(-) delete mode 100644 .runtime_old/class/builtin.go delete mode 100644 .runtime_old/class/class.go delete mode 100644 .runtime_old/class/cons/cons.go delete mode 100644 .runtime_old/class/domainerror/domainerror.go delete mode 100644 .runtime_old/class/function/function.go delete mode 100644 .runtime_old/class/instance.go delete mode 100644 .runtime_old/class/meta.go delete mode 100644 .runtime_old/class/parseerror/parseerror.go delete mode 100644 .runtime_old/eval.go delete mode 100644 .runtime_old/init.go delete mode 100644 .runtime_old/lambda.go delete mode 100644 .runtime_old/native.go create mode 100644 runtime/lambda.go diff --git a/.runtime_old/class/builtin.go b/.runtime_old/class/builtin.go deleted file mode 100644 index 1eb3247..0000000 --- a/.runtime_old/class/builtin.go +++ /dev/null @@ -1,68 +0,0 @@ -package class - -type builtin struct { - parents []Class - name string -} - -func (c *builtin) String() string { - return c.name -} - -func (c *builtin) Parents() []Class { - return c.parents -} - -func (c *builtin) Class() Class { - return BuiltInClass -} - -func (c *builtin) Value() Value { - return c -} - -func (c *builtin) New(value ...Value) Instance { - return &defaultInstance{c, value[0]} -} - -func (c *builtin) IsInstanceOf(class Class) bool { - return IsInstanceOf(c, class) -} - -var Object = &builtin{[]Class{}, ""} -var BasicArray = BuiltInClass.New(Object, "").(Class) -var BasicArrayStar = BuiltInClass.New(BasicArray, "").(Class) -var GeneralArrayStar = BuiltInClass.New(BasicArrayStar, "").(Class) -var BasicVector = BuiltInClass.New(BasicArray, "").(Class) -var GeneraVector = BuiltInClass.New(BasicVector, "").(Class) -var String = BuiltInClass.New(BasicVector, "").(Class) -var Character = BuiltInClass.New(Object, "").(Class) -var Function = BuiltInClass.New(Object, "").(Class) -var GenericFunction = BuiltInClass.New(Function, "").(Class) -var StandardGenericFunction = BuiltInClass.New(GenericFunction, "").(Class) -var List = BuiltInClass.New(Object, "").(Class) -var Cons = BuiltInClass.New(List, "").(Class) -var Null = BuiltInClass.New(List, "").(Class) -var Symbol = BuiltInClass.New(Object, "").(Class) -var Number = BuiltInClass.New(Object, "").(Class) -var Integer = BuiltInClass.New(Number, "").(Class) -var Float = BuiltInClass.New(Number, "").(Class) -var SeriousCondition = BuiltInClass.New(Object, "").(Class) -var Error = BuiltInClass.New(SeriousCondition, "").(Class) -var ArithmeticError = BuiltInClass.New(Error, "").(Class) -var DivisionByZero = BuiltInClass.New(ArithmeticError, "").(Class) -var FloatingPointOnderflow = BuiltInClass.New(ArithmeticError, "").(Class) -var FloatingPointUnderflow = BuiltInClass.New(ArithmeticError, "").(Class) -var ControlError = BuiltInClass.New(Error, "").(Class) -var ParseError = BuiltInClass.New(Error, "").(Class) -var ProgramError = BuiltInClass.New(Error, "").(Class) -var DomainError = BuiltInClass.New(ProgramError, "").(Class) -var UndefinedEntity = BuiltInClass.New(ProgramError, "").(Class) -var UndefinedVariable = BuiltInClass.New(UndefinedEntity, "").(Class) -var UndefinedFunction = BuiltInClass.New(UndefinedEntity, "").(Class) -var SimpleError = BuiltInClass.New(Error, "").(Class) -var StreamError = BuiltInClass.New(Error, "").(Class) -var EndOfStream = BuiltInClass.New(StreamError, "").(Class) -var StorageExhausted = BuiltInClass.New(SeriousCondition, "").(Class) -var StandardObject = BuiltInClass.New(Object, "").(Class) -var Stream = BuiltInClass.New(Object, "").(Class) diff --git a/.runtime_old/class/class.go b/.runtime_old/class/class.go deleted file mode 100644 index e7a2d82..0000000 --- a/.runtime_old/class/class.go +++ /dev/null @@ -1,41 +0,0 @@ -package class - -type Class interface { - // For Instance interface - Class() Class - Value() Value - IsInstanceOf(Class) bool - String() string - // Class main interface - Parents() []Class - New(...Value) Instance -} - -// Test function for IsInstanceOf -func test(child Class, parent Class) bool { - if child == parent { - return true - } - for _, p := range child.Parents() { - if test(p, parent) { - return true - } - } - return false -} - -func IsInstanceOf(i Instance, class Class) bool { - if i.Class() == class { - return true - } - for _, p := range i.Class().Parents() { - if test(p, class) { - return true - } - } - return false -} - -func New(class Class, value ...Value) Instance { - return class.New(value...) -} diff --git a/.runtime_old/class/cons/cons.go b/.runtime_old/class/cons/cons.go deleted file mode 100644 index e6cf4a7..0000000 --- a/.runtime_old/class/cons/cons.go +++ /dev/null @@ -1,66 +0,0 @@ -package cons - -import ( - "fmt" - - "github.com/ta2gch/iris/runtime/class" - "github.com/ta2gch/iris/runtime/class/domainerror" -) - -// Cell is a pair of pointers to Object -type cons struct { - car class.Instance - cdr class.Instance -} - -func New(car class.Instance, cdr class.Instance) class.Instance { - return cons{car, cdr} -} - -func (c cons) Class() class.Class { - return class.Cons -} - -func (c cons) Value() class.Value { - return c -} - -func (c cons) IsInstanceOf(cls class.Class) bool { - return class.IsInstanceOf(c, cls) -} - -func (c cons) String() string { - return fmt.Sprintf("(%v . %v)", c.car, c.cdr) -} - -func Car(i class.Instance) (class.Instance, class.Instance) { - if i.IsInstanceOf(class.Null) || !i.IsInstanceOf(class.List) { - return nil, domainerror.New(i, class.Cons) - } - return i.(cons).car, nil -} - -func Cdr(i class.Instance) (class.Instance, class.Instance) { - if i.IsInstanceOf(class.Null) || !i.IsInstanceOf(class.List) { - return nil, domainerror.New(i, class.Cons) - } - return i.(cons).cdr, nil -} - -func Length(list class.Instance) (int, class.Instance) { - if !list.IsInstanceOf(class.List) { - return 0, domainerror.New(list, class.Cons) - } - if list.IsInstanceOf(class.Null) { - return 0, nil - } - cdr, err := Cdr(list) - if err != nil { - return 0, err - } - len, err := Length(cdr) - if err != nil { - return 0, err - } - return 1 + len, nil -} diff --git a/.runtime_old/class/domainerror/domainerror.go b/.runtime_old/class/domainerror/domainerror.go deleted file mode 100644 index e353f83..0000000 --- a/.runtime_old/class/domainerror/domainerror.go +++ /dev/null @@ -1,32 +0,0 @@ -package domainerror - -import ( - "fmt" - - "github.com/ta2gch/iris/runtime/class" -) - -type domainerror struct { - object class.Instance - expectedClass class.Class -} - -func New(obj class.Instance, cls class.Class) class.Instance { - return domainerror{obj, cls} -} - -func (e domainerror) Value() class.Value { - return e -} - -func (e domainerror) Class() class.Class { - return class.DomainError -} - -func (e domainerror) IsInstanceOf(cls class.Class) bool { - return class.IsInstanceOf(e, cls) -} - -func (e domainerror) String() string { - return fmt.Sprintf("Domain Error: %v is not a instance of %v", e.object, e.expectedClass) -} diff --git a/.runtime_old/class/function/function.go b/.runtime_old/class/function/function.go deleted file mode 100644 index 0bd9fd6..0000000 --- a/.runtime_old/class/function/function.go +++ /dev/null @@ -1,22 +0,0 @@ -package function - -import ( - "github.com/ta2gch/iris/runtime/class" - "github.com/ta2gch/iris/runtime/class/domainerror" - env "github.com/ta2gch/iris/runtime/environment" -) - -type Function interface { - Apply(args class.Instance, local *env.Environment, global *env.Environment) (class.Instance, class.Instance) -} - -func Apply(fun class.Instance, args class.Instance, local *env.Environment, global *env.Environment) (class.Instance, class.Instance) { - if !fun.IsInstanceOf(class.Function) { - return nil, domainerror.New(fun, class.Function) - } - obj, err := fun.Value().(Function).Apply(args, local, global) - if err != nil { - return nil, err - } - return obj, nil -} diff --git a/.runtime_old/class/instance.go b/.runtime_old/class/instance.go deleted file mode 100644 index 0ebef75..0000000 --- a/.runtime_old/class/instance.go +++ /dev/null @@ -1,36 +0,0 @@ -package class - -import ( - "fmt" -) - -type Value interface{} - -// Instance struct type is the struct for the internal representations -type Instance interface { - Class() Class - Value() Value - IsInstanceOf(Class) bool - String() string -} - -type defaultInstance struct { - class Class - value Value -} - -func (i *defaultInstance) Class() Class { - return i.class -} - -func (i *defaultInstance) Value() Value { - return i.value -} - -func (i *defaultInstance) IsInstanceOf(class Class) bool { - return IsInstanceOf(i, class) -} - -func (i *defaultInstance) String() string { - return fmt.Sprintf("%v", i.Value()) -} diff --git a/.runtime_old/class/meta.go b/.runtime_old/class/meta.go deleted file mode 100644 index 93de327..0000000 --- a/.runtime_old/class/meta.go +++ /dev/null @@ -1,32 +0,0 @@ -package class - -type meta struct { - name string -} - -func (m *meta) String() string { - return m.name -} - -func (*meta) Parents() []Class { - return []Class{Object} -} - -func (*meta) Class() Class { - return BuiltInClass -} - -func (m *meta) Value() Value { - return m -} - -func (m *meta) New(value ...Value) Instance { - return &builtin{[]Class{value[0].(Class)}, value[1].(string)} -} - -func (m *meta) IsInstanceOf(class Class) bool { - return IsInstanceOf(m, class) -} - -var BuiltInClass = &meta{""} -var StandardClass = &meta{""} diff --git a/.runtime_old/class/parseerror/parseerror.go b/.runtime_old/class/parseerror/parseerror.go deleted file mode 100644 index b6edad7..0000000 --- a/.runtime_old/class/parseerror/parseerror.go +++ /dev/null @@ -1,32 +0,0 @@ -package parseerror - -import ( - "fmt" - - "github.com/ta2gch/iris/runtime/class" -) - -type parseerror struct { - str string - expectedClass class.Class -} - -func New(str string, cls class.Class) class.Instance { - return parseerror{str, cls} -} - -func (e parseerror) Value() class.Value { - return e -} - -func (e parseerror) Class() class.Class { - return class.DomainError -} - -func (e parseerror) IsInstanceOf(cls class.Class) bool { - return class.IsInstanceOf(e, cls) -} - -func (e parseerror) String() string { - return fmt.Sprintf("Parse Error: %v is not a instance of %v", e.str, e.expectedClass) -} diff --git a/.runtime_old/eval.go b/.runtime_old/eval.go deleted file mode 100644 index 53dfdff..0000000 --- a/.runtime_old/eval.go +++ /dev/null @@ -1,134 +0,0 @@ -package runtime - -import ( - "github.com/ta2gch/iris/runtime/class" - "github.com/ta2gch/iris/runtime/class/cons" - "github.com/ta2gch/iris/runtime/class/function" - env "github.com/ta2gch/iris/runtime/environment" -) - -func evalArguments(args class.Instance, local *env.Environment, global *env.Environment) (class.Instance, class.Instance) { - if args.IsInstanceOf(class.Null) { - return class.Null.New(nil), nil - } - car, err := cons.Car(args) - if err != nil { - return nil, err - } - cdr, err := cons.Cdr(args) - if err != nil { - return nil, err - } - a, err := Eval(car, local, global) - if err != nil { - return nil, err - } - b, err := evalArguments(cdr, local, global) - if err != nil { - return nil, err - } - return cons.New(a, b), nil -} - -func evalFunction(obj class.Instance, local *env.Environment, global *env.Environment) (class.Instance, class.Instance) { - // get function symbol - car, err := cons.Car(obj) - if err != nil { - return nil, err - } - - // get function arguments - cdr, err := cons.Cdr(obj) - if err != nil { - return nil, err - } - // eval if lambda form - if car.IsInstanceOf(class.Cons) { - caar, err := cons.Car(car) - if err != nil { - return nil, err - } - if caar.Value() == "lambda" { - fun, err := Eval(car, local, global) - if err != nil { - return nil, err - } - args, err := evalArguments(cdr, local, global) - if err != nil { - return nil, err - } - env := env.New() - env.MergeDynamicVariable(local) - ret, err := function.Apply(fun, args, env, global) - if err != nil { - return nil, err - } - return ret, nil - } - } - - if !car.IsInstanceOf(class.Symbol) { - return nil, class.New(class.DomainError, nil) - } - // get macro instance has value of Function interface - var mac class.Instance - if m, ok := local.GetMacro(car); ok { - mac = m - } - if m, ok := global.GetMacro(car); ok { - mac = m - } - if mac != nil { - ret, err := function.Apply(mac, cdr, local, global) - if err != nil { - return nil, err - } - return ret, nil - } - // get function instance has value of Function interface - var fun class.Instance - if f, ok := local.GetFunction(car); ok { - fun = f - } - if f, ok := global.GetFunction(car); ok { - fun = f - } - if fun != nil { - args, err := evalArguments(cdr, local, global) - if err != nil { - return nil, err - } - env := env.New() - env.MergeDynamicVariable(local) - ret, err := function.Apply(fun, args, env, global) - if err != nil { - return nil, err - } - return ret, nil - } - return nil, class.New(class.UndefinedFunction, nil) -} - -// Eval evaluates any classs -func Eval(obj class.Instance, local *env.Environment, global *env.Environment) (class.Instance, class.Instance) { - if obj.IsInstanceOf(class.Null) { - return class.Null.New(nil), nil - } - if obj.IsInstanceOf(class.Symbol) { - if val, ok := local.GetVariable(obj); ok { - return val, nil - } - if val, ok := global.GetVariable(obj); ok { - return val, nil - } - return nil, class.New(class.UndefinedVariable, nil) - } - if obj.IsInstanceOf(class.Cons) { - ret, err := evalFunction(obj, local, global) - if err != nil { - return nil, err - } - return ret, nil - } - return obj, nil -} diff --git a/.runtime_old/init.go b/.runtime_old/init.go deleted file mode 100644 index fb4c2e4..0000000 --- a/.runtime_old/init.go +++ /dev/null @@ -1,27 +0,0 @@ -package runtime - -import ( - "github.com/ta2gch/iris/runtime/class" - "github.com/ta2gch/iris/runtime/class/cons" - env "github.com/ta2gch/iris/runtime/environment" -) - -func init() { - env.TopLevel.SetFunction(class.Symbol.New("functionp"), NewNativeFunction(func(args class.Instance, local *env.Environment, global *env.Environment) (class.Instance, class.Instance) { - len, err := cons.Length(args) - if err != nil { - return nil, err - } - if len != 1 { - return nil, class.New(class.UndefinedFunction, nil) - } - car, err := cons.Car(args) - if err != nil { - return nil, err - } - if car.IsInstanceOf(class.Function) { - return class.Object.New(nil), nil - } - return class.Null.New(nil), nil - })) -} diff --git a/.runtime_old/lambda.go b/.runtime_old/lambda.go deleted file mode 100644 index 3511905..0000000 --- a/.runtime_old/lambda.go +++ /dev/null @@ -1,79 +0,0 @@ -package runtime - -import ( - "github.com/ta2gch/iris/runtime/class" - "github.com/ta2gch/iris/runtime/class/cons" - "github.com/ta2gch/iris/runtime/class/parseerror" - env "github.com/ta2gch/iris/runtime/environment" -) - -type LambdaFunction struct { - lambdaList class.Instance - forms class.Instance - local *env.Environment -} - -func NewLambdaFunction(lambdaList class.Instance, forms class.Instance, local *env.Environment) class.Instance { - return class.Function.New(LambdaFunction{lambdaList, forms, local}) -} - -func (f LambdaFunction) Apply(args class.Instance, local *env.Environment, global *env.Environment) (class.Instance, class.Instance) { - local.MergeAll(f.local) - fargs := f.lambdaList - aargs := args - for !fargs.IsInstanceOf(class.Null) { - key, err := cons.Car(fargs) - if err != nil { - return nil, err - } - value, err := cons.Car(aargs) - if err != nil { - return nil, err - } - if key == class.Symbol.New(":rest") || key == class.Symbol.New("&rest") { - cdr, err := cons.Cdr(fargs) - if err != nil { - return nil, err - } - cadr, err := cons.Car(cdr) - if err != nil { - return nil, err - } - cddr, err := cons.Cdr(cdr) - if err != nil { - return nil, err - } - if !cddr.IsInstanceOf(class.Null) { - return nil, parseerror.New(fargs.String(), class.List) - } - local.SetVariable(cadr, aargs) - break - } - local.SetVariable(key, value) - fargs, err = cons.Cdr(fargs) - if err != nil { - return nil, err - } - aargs, err = cons.Cdr(aargs) - if err != nil { - return nil, err - } - } - body := f.forms - var ret class.Instance - for !body.IsInstanceOf(class.Null) { - exp, err := cons.Car(body) - if err != nil { - return nil, err - } - ret, err = Eval(exp, local, global) - if err != nil { - return nil, err - } - body, err = cons.Cdr(body) - if err != nil { - return nil, err - } - } - return ret, nil -} diff --git a/.runtime_old/native.go b/.runtime_old/native.go deleted file mode 100644 index 00f8ef1..0000000 --- a/.runtime_old/native.go +++ /dev/null @@ -1,22 +0,0 @@ -package runtime - -import ( - "github.com/ta2gch/iris/runtime/class" - env "github.com/ta2gch/iris/runtime/environment" -) - -type NativeFunction struct { - fun func(class.Instance, *env.Environment, *env.Environment) (class.Instance, class.Instance) -} - -func (f NativeFunction) Apply(args class.Instance, local *env.Environment, global *env.Environment) (class.Instance, class.Instance) { - obj, err := f.fun(args, local, global) - if err != nil { - return nil, err - } - return obj, nil -} - -func NewNativeFunction(fun func(class.Instance, *env.Environment, *env.Environment) (class.Instance, class.Instance)) class.Instance { - return class.Function.New(NativeFunction{fun}) -} diff --git a/runtime/eval.go b/runtime/eval.go index e05a023..13bc134 100644 --- a/runtime/eval.go +++ b/runtime/eval.go @@ -34,7 +34,7 @@ func evalFunction(obj ilos.Instance, local *env.Environment, global *env.Environ // eval if lambda form if ilos.InstanceOf(car, class.Cons) { caar := instance.UnsafeCar(car) - if caar == instance.NewSymbol("lambda") { + if caar == instance.NewSymbol("LAMBDA") { fun, err := Eval(car, local, global) if err != nil { return nil, err diff --git a/runtime/eval_test.go b/runtime/eval_test.go index 19e93b9..02ceabb 100644 --- a/runtime/eval_test.go +++ b/runtime/eval_test.go @@ -30,6 +30,9 @@ func TestEval(t *testing.T) { ret, _ := Eval(instance.NewCons(instance.NewSymbol("INC"), args), local, global) return ret, nil })) + local.SetMacro(instance.NewSymbol("LAMBDA"), instance.NewFunction(func(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { + return NewLambdaFunction(instance.UnsafeCar(args), instance.UnsafeCdr(args), local), nil + })) type args struct { obj ilos.Instance local *env.Environment @@ -59,6 +62,12 @@ func TestEval(t *testing.T) { want: instance.NewInteger(3), wantErr: false, }, + { + name: "lambda form", + args: args{read("((lambda (x) (inc x)) 1)"), local, global}, + want: instance.NewInteger(2), + wantErr: false, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/runtime/lambda.go b/runtime/lambda.go new file mode 100644 index 0000000..8b1806a --- /dev/null +++ b/runtime/lambda.go @@ -0,0 +1,44 @@ +package runtime + +import ( + env "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/ilos" + "github.com/ta2gch/iris/runtime/ilos/class" + "github.com/ta2gch/iris/runtime/ilos/instance" +) + +func NewLambdaFunction(lambdaList ilos.Instance, forms ilos.Instance, lexical *env.Environment) ilos.Instance { + return instance.NewFunction(func(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { + local.MergeAll(lexical) + fargs := lambdaList + aargs := args + for !ilos.InstanceOf(fargs, class.Null) { + key := instance.UnsafeCar(fargs) + value := instance.UnsafeCar(aargs) + if key == instance.NewSymbol(":rest") || key == instance.NewSymbol("&rest") { + cdr := instance.UnsafeCdr(fargs) + cadr := instance.UnsafeCar(cdr) + cddr := instance.UnsafeCdr(cdr) + if !ilos.InstanceOf(cddr, class.Null) { + return nil, instance.NewParseError(instance.NewString(fargs.String()), class.List) + } + local.SetVariable(cadr, aargs) + break + } + local.SetVariable(key, value) + fargs = instance.UnsafeCdr(fargs) + aargs = instance.UnsafeCdr(aargs) + } + body := forms + var ret, err ilos.Instance + for !ilos.InstanceOf(body, class.Null) { + exp := instance.UnsafeCar(body) + ret, err = Eval(exp, local, global) + if err != nil { + return nil, err + } + body = instance.UnsafeCdr(body) + } + return ret, nil + }) +} From ee8fb65f91b4fbbc4850c9877fecf23315efd0f0 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Thu, 3 Aug 2017 15:23:00 +0900 Subject: [PATCH 080/228] Updated stringify method --- runtime/eval_test.go | 4 +- runtime/ilos/class/class.go | 78 +++++++++++++++---------------- runtime/ilos/instance/function.go | 6 +-- runtime/ilos/instance/instance.go | 4 +- runtime/ilos/instance/list.go | 13 +++++- 5 files changed, 59 insertions(+), 46 deletions(-) diff --git a/runtime/eval_test.go b/runtime/eval_test.go index 02ceabb..85969e2 100644 --- a/runtime/eval_test.go +++ b/runtime/eval_test.go @@ -27,8 +27,8 @@ func TestEval(t *testing.T) { return instance.NewInteger(int(car.(instance.Integer)) + 1), nil })) local.SetMacro(instance.NewSymbol("MINC"), instance.NewFunction(func(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { - ret, _ := Eval(instance.NewCons(instance.NewSymbol("INC"), args), local, global) - return ret, nil + ret, err := Eval(instance.NewCons(instance.NewSymbol("INC"), args), local, global) + return ret, err })) local.SetMacro(instance.NewSymbol("LAMBDA"), instance.NewFunction(func(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { return NewLambdaFunction(instance.UnsafeCar(args), instance.UnsafeCdr(args), local), nil diff --git a/runtime/ilos/class/class.go b/runtime/ilos/class/class.go index 176247e..ede4a0c 100644 --- a/runtime/ilos/class/class.go +++ b/runtime/ilos/class/class.go @@ -26,42 +26,42 @@ func (p *builtinclass) String() string { return p.name } -var Object = &builtinclass{[]ilos.Class{}, ""} -var BuiltInClass = &builtinclass{[]ilos.Class{Object}, ""} -var StandardClass = &builtinclass{[]ilos.Class{Object}, ""} -var BasicArray = &builtinclass{[]ilos.Class{Object}, ""} -var BasicArrayStar = &builtinclass{[]ilos.Class{BasicArray}, ""} -var GeneralArrayStar = &builtinclass{[]ilos.Class{BasicArrayStar}, ""} -var BasicVector = &builtinclass{[]ilos.Class{BasicArray}, ""} -var GeneraVector = &builtinclass{[]ilos.Class{BasicVector}, ""} -var String = &builtinclass{[]ilos.Class{BasicVector}, ""} -var Character = &builtinclass{[]ilos.Class{Object}, ""} -var Function = &builtinclass{[]ilos.Class{Object}, ""} -var GenericFunction = &builtinclass{[]ilos.Class{Function}, ""} -var StandardGenericFunction = &builtinclass{[]ilos.Class{GenericFunction}, ""} -var List = &builtinclass{[]ilos.Class{Object}, ""} -var Cons = &builtinclass{[]ilos.Class{List}, ""} -var Null = &builtinclass{[]ilos.Class{List}, ""} -var Symbol = &builtinclass{[]ilos.Class{Object}, ""} -var Number = &builtinclass{[]ilos.Class{Object}, ""} -var Integer = &builtinclass{[]ilos.Class{Number}, ""} -var Float = &builtinclass{[]ilos.Class{Number}, ""} -var SeriousCondition = &builtinclass{[]ilos.Class{Object}, ""} -var Error = &builtinclass{[]ilos.Class{SeriousCondition}, ""} -var ArithmeticError = &builtinclass{[]ilos.Class{Error}, ""} -var DivisionByZero = &builtinclass{[]ilos.Class{ArithmeticError}, ""} -var FloatingPointOnderflow = &builtinclass{[]ilos.Class{ArithmeticError}, ""} -var FloatingPointUnderflow = &builtinclass{[]ilos.Class{ArithmeticError}, ""} -var ControlError = &builtinclass{[]ilos.Class{Error}, ""} -var ParseError = &builtinclass{[]ilos.Class{Error}, ""} -var ProgramError = &builtinclass{[]ilos.Class{Error}, ""} -var DomainError = &builtinclass{[]ilos.Class{ProgramError}, ""} -var UndefinedEntity = &builtinclass{[]ilos.Class{ProgramError}, ""} -var UndefinedVariable = &builtinclass{[]ilos.Class{UndefinedEntity}, ""} -var UndefinedFunction = &builtinclass{[]ilos.Class{UndefinedEntity}, ""} -var SimpleError = &builtinclass{[]ilos.Class{Error}, ""} -var StreamError = &builtinclass{[]ilos.Class{Error}, ""} -var EndOfStream = &builtinclass{[]ilos.Class{StreamError}, ""} -var StorageExhausted = &builtinclass{[]ilos.Class{SeriousCondition}, ""} -var StandardObject = &builtinclass{[]ilos.Class{Object}, ""} -var Stream = &builtinclass{[]ilos.Class{Object}, ""} +var Object = &builtinclass{[]ilos.Class{}, ""} +var BuiltInClass = &builtinclass{[]ilos.Class{Object}, ""} +var StandardClass = &builtinclass{[]ilos.Class{Object}, ""} +var BasicArray = &builtinclass{[]ilos.Class{Object}, ""} +var BasicArrayStar = &builtinclass{[]ilos.Class{BasicArray}, ""} +var GeneralArrayStar = &builtinclass{[]ilos.Class{BasicArrayStar}, ""} +var BasicVector = &builtinclass{[]ilos.Class{BasicArray}, ""} +var GeneraVector = &builtinclass{[]ilos.Class{BasicVector}, ""} +var String = &builtinclass{[]ilos.Class{BasicVector}, ""} +var Character = &builtinclass{[]ilos.Class{Object}, ""} +var Function = &builtinclass{[]ilos.Class{Object}, ""} +var GenericFunction = &builtinclass{[]ilos.Class{Function}, ""} +var StandardGenericFunction = &builtinclass{[]ilos.Class{GenericFunction}, ""} +var List = &builtinclass{[]ilos.Class{Object}, ""} +var Cons = &builtinclass{[]ilos.Class{List}, ""} +var Null = &builtinclass{[]ilos.Class{List}, ""} +var Symbol = &builtinclass{[]ilos.Class{Object}, ""} +var Number = &builtinclass{[]ilos.Class{Object}, ""} +var Integer = &builtinclass{[]ilos.Class{Number}, ""} +var Float = &builtinclass{[]ilos.Class{Number}, ""} +var SeriousCondition = &builtinclass{[]ilos.Class{Object}, ""} +var Error = &builtinclass{[]ilos.Class{SeriousCondition}, ""} +var ArithmeticError = &builtinclass{[]ilos.Class{Error}, ""} +var DivisionByZero = &builtinclass{[]ilos.Class{ArithmeticError}, ""} +var FloatingPointOnderflow = &builtinclass{[]ilos.Class{ArithmeticError}, ""} +var FloatingPointUnderflow = &builtinclass{[]ilos.Class{ArithmeticError}, ""} +var ControlError = &builtinclass{[]ilos.Class{Error}, ""} +var ParseError = &builtinclass{[]ilos.Class{Error}, ""} +var ProgramError = &builtinclass{[]ilos.Class{Error}, ""} +var DomainError = &builtinclass{[]ilos.Class{ProgramError}, ""} +var UndefinedEntity = &builtinclass{[]ilos.Class{ProgramError}, ""} +var UndefinedVariable = &builtinclass{[]ilos.Class{UndefinedEntity}, ""} +var UndefinedFunction = &builtinclass{[]ilos.Class{UndefinedEntity}, ""} +var SimpleError = &builtinclass{[]ilos.Class{Error}, ""} +var StreamError = &builtinclass{[]ilos.Class{Error}, ""} +var EndOfStream = &builtinclass{[]ilos.Class{StreamError}, ""} +var StorageExhausted = &builtinclass{[]ilos.Class{SeriousCondition}, ""} +var StandardObject = &builtinclass{[]ilos.Class{Object}, ""} +var Stream = &builtinclass{[]ilos.Class{Object}, ""} diff --git a/runtime/ilos/instance/function.go b/runtime/ilos/instance/function.go index 1a4005e..4101d4b 100644 --- a/runtime/ilos/instance/function.go +++ b/runtime/ilos/instance/function.go @@ -26,7 +26,7 @@ func (Function) SetSlotValue(key ilos.Instance, value ilos.Instance) { } func (f Function) String() string { - return fmt.Sprintf("#instance[%v]", f.Class()) + return fmt.Sprintf("#%v[]", f.Class()) } type GenericFunction map[[128]ilos.Class]Function @@ -58,7 +58,7 @@ func (f GenericFunction) SetSlotValue(key ilos.Instance, value ilos.Instance) { } func (f GenericFunction) String() string { - return fmt.Sprintf("#instance[%v]", f.Class()) + return fmt.Sprintf("#%v[]", f.Class()) } type StandardGenericFunction map[[128]ilos.Class]Function @@ -90,5 +90,5 @@ func (f StandardGenericFunction) SetSlotValue(key ilos.Instance, value ilos.Inst } func (f StandardGenericFunction) String() string { - return fmt.Sprintf("#instance[%v]", f.Class()) + return fmt.Sprintf("#%v[]", f.Class()) } diff --git a/runtime/ilos/instance/instance.go b/runtime/ilos/instance/instance.go index f8fa6c0..330a8c1 100644 --- a/runtime/ilos/instance/instance.go +++ b/runtime/ilos/instance/instance.go @@ -29,5 +29,7 @@ func (i *instance) SetSlotValue(key ilos.Instance, value ilos.Instance) { } func (i *instance) String() string { - return fmt.Sprintf("#INSTANCE[%v %v]", i.class, i.slots) + class := fmt.Sprint(i.class) + + return fmt.Sprintf("#%v %v>", class[:len(class)-1], i.slots) } diff --git a/runtime/ilos/instance/list.go b/runtime/ilos/instance/list.go index 72984ca..baf0fe6 100644 --- a/runtime/ilos/instance/list.go +++ b/runtime/ilos/instance/list.go @@ -32,7 +32,18 @@ func (i *Cons) SetSlotValue(key ilos.Instance, value ilos.Instance) { } func (i *Cons) String() string { - return fmt.Sprintf("(%v . %v)", i.car, i.cdr) + str := "(" + fmt.Sprint(i.car) + cdr := i.cdr + for ilos.InstanceOf(cdr, class.Cons) { + str += fmt.Sprintf(" %v", UnsafeCar(cdr)) + cdr = UnsafeCdr(cdr) + } + if ilos.InstanceOf(cdr, class.Null) { + str += ")" + } else { + str += fmt.Sprintf(" . %v)", cdr) + } + return str } func UnsafeCar(i ilos.Instance) ilos.Instance { From 817117f14a33f95cf90342661eed099b56b64399 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Thu, 3 Aug 2017 17:24:23 +0900 Subject: [PATCH 081/228] Make SlotValue more safety --- runtime/ilos/class/class.go | 7 +-- runtime/ilos/ilos.go | 8 +-- runtime/ilos/instance/basic-array.go | 74 +++++++++++++++++----------- runtime/ilos/instance/character.go | 7 +-- runtime/ilos/instance/function.go | 33 ++++++++----- runtime/ilos/instance/instance.go | 20 +++++--- runtime/ilos/instance/list.go | 36 +++++++++++--- runtime/ilos/instance/number.go | 16 +++--- runtime/ilos/instance/symbol.go | 10 ++-- 9 files changed, 132 insertions(+), 79 deletions(-) diff --git a/runtime/ilos/class/class.go b/runtime/ilos/class/class.go index ede4a0c..03757b5 100644 --- a/runtime/ilos/class/class.go +++ b/runtime/ilos/class/class.go @@ -15,11 +15,12 @@ func (p *builtinclass) Parents() []ilos.Class { return p.parents } -func (i *builtinclass) GetSlotValue(key ilos.Instance) ilos.Instance { - return nil +func (i *builtinclass) GetSlotValue(key ilos.Instance) (ilos.Instance, bool) { + return nil, false } -func (i *builtinclass) SetSlotValue(key ilos.Instance, value ilos.Instance) { +func (i *builtinclass) SetSlotValue(key ilos.Instance, value ilos.Instance) bool { + return false } func (p *builtinclass) String() string { diff --git a/runtime/ilos/ilos.go b/runtime/ilos/ilos.go index 94ad35e..e3d77e4 100644 --- a/runtime/ilos/ilos.go +++ b/runtime/ilos/ilos.go @@ -3,15 +3,15 @@ package ilos type Class interface { Class() Class Parents() []Class - GetSlotValue(Instance) Instance - SetSlotValue(Instance, Instance) + GetSlotValue(Instance) (Instance, bool) + SetSlotValue(Instance, Instance) bool String() string } type Instance interface { Class() Class - GetSlotValue(Instance) Instance - SetSlotValue(Instance, Instance) + GetSlotValue(Instance) (Instance, bool) + SetSlotValue(Instance, Instance) bool String() string } diff --git a/runtime/ilos/instance/basic-array.go b/runtime/ilos/instance/basic-array.go index c6aacfd..db96065 100644 --- a/runtime/ilos/instance/basic-array.go +++ b/runtime/ilos/instance/basic-array.go @@ -15,27 +15,23 @@ type GeneralArrayStar struct { array map[[128]int]ilos.Instance } -func NewGeneralArrayStar(key []ilos.Instance) ilos.Instance { - dim := [128]int{} - for i, d := range key { - dim[i] = int(d.(Integer)) - } - return &GeneralArrayStar{dim, map[[128]int]ilos.Instance{}} +func NewGeneralArrayStar(key [128]int) ilos.Instance { + return &GeneralArrayStar{key, map[[128]int]ilos.Instance{}} } func (*GeneralArrayStar) Class() ilos.Class { return class.GeneralArrayStar } -func (a *GeneralArrayStar) GetSlotValue(key ilos.Instance) ilos.Instance { - if ilos.InstanceOf(key, class.Symbol) && key.(Symbol) == "LENGTH" { +func (a *GeneralArrayStar) GetSlotValue(key ilos.Instance) (ilos.Instance, bool) { + if symbol, ok := key.(Symbol); ok && symbol == "LENGTH" { cons := NewNull() for i := 128; i > 0; i-- { if a.dimension[i-1] != 0 { cons = NewCons(NewInteger(a.dimension[i-1]), cons) } } - return cons + return cons, true } if ilos.InstanceOf(key, class.List) { dim := [128]int{} @@ -46,12 +42,17 @@ func (a *GeneralArrayStar) GetSlotValue(key ilos.Instance) ilos.Instance { cdr = UnsafeCdr(cdr) idx++ } - return a.array[dim] + for i := 0; i < 128; i++ { + if a.dimension[i] != 0 && dim[i] >= a.dimension[i] { + return nil, false + } + } + return a.array[dim], true } - return nil + return nil, false } -func (a *GeneralArrayStar) SetSlotValue(key ilos.Instance, value ilos.Instance) { +func (a *GeneralArrayStar) SetSlotValue(key ilos.Instance, value ilos.Instance) bool { if ilos.InstanceOf(key, class.List) { dim := [128]int{} idx := 0 @@ -61,8 +62,15 @@ func (a *GeneralArrayStar) SetSlotValue(key ilos.Instance, value ilos.Instance) cdr = UnsafeCdr(cdr) idx++ } + for i := 0; i < 128; i++ { + if a.dimension[i] != 0 && dim[i] >= a.dimension[i] { + return false + } + } a.array[dim] = value + return true } + return false } func (a *GeneralArrayStar) String() string { @@ -83,20 +91,22 @@ func (GeneralVector) Class() ilos.Class { return class.GeneraVector } -func (i GeneralVector) GetSlotValue(key ilos.Instance) ilos.Instance { - if ilos.InstanceOf(key, class.Symbol) && key.(Symbol) == "LENGTH" { - return NewInteger(len(i)) +func (i GeneralVector) GetSlotValue(key ilos.Instance) (ilos.Instance, bool) { + if symbol, ok := key.(Symbol); ok && symbol == "LENGTH" { + return NewInteger(len(i)), true } - if ilos.InstanceOf(key, class.Integer) { - return i[int(key.(Integer))] + if index, ok := key.(Integer); ok && int(index) < len(i) { + return i[int(index)], true } - return nil + return nil, false } -func (i GeneralVector) SetSlotValue(key ilos.Instance, value ilos.Instance) { - if ilos.InstanceOf(key, class.Integer) { - i[int(key.(Integer))] = value +func (i GeneralVector) SetSlotValue(key ilos.Instance, value ilos.Instance) bool { + if index, ok := key.(Integer); ok && int(index) < len(i) { + i[int(index)] = value + return true } + return false } func (i GeneralVector) String() string { @@ -117,20 +127,24 @@ func (String) Class() ilos.Class { return class.String } -func (i String) GetSlotValue(key ilos.Instance) ilos.Instance { - if ilos.InstanceOf(key, class.Symbol) && key.(Symbol) == "LENGTH" { - return NewInteger(len(i)) +func (i String) GetSlotValue(key ilos.Instance) (ilos.Instance, bool) { + if symbol, ok := key.(Symbol); ok && symbol == "LENGTH" { + return NewInteger(len(i)), true } - if ilos.InstanceOf(key, class.Integer) { - return NewCharacter(i[int(key.(Integer))]) + if index, ok := key.(Integer); ok && int(index) < len(i) { + return NewCharacter(i[int(index)]), true } - return nil + return nil, false } -func (i String) SetSlotValue(key ilos.Instance, value ilos.Instance) { - if ilos.InstanceOf(key, class.Integer) { - i[int(key.(Integer))] = rune(value.(Character)) +func (i String) SetSlotValue(key ilos.Instance, value ilos.Instance) bool { + if index, ok := key.(Integer); ok && int(index) < len(i) { + if character, ok := value.(Character); ok { + i[index] = rune(character) + return true + } } + return false } func (i String) String() string { diff --git a/runtime/ilos/instance/character.go b/runtime/ilos/instance/character.go index e5704dd..e04ebcc 100644 --- a/runtime/ilos/instance/character.go +++ b/runtime/ilos/instance/character.go @@ -19,11 +19,12 @@ func (Character) Class() ilos.Class { return class.Character } -func (i Character) GetSlotValue(key ilos.Instance) ilos.Instance { - return nil +func (i Character) GetSlotValue(key ilos.Instance) (ilos.Instance, bool) { + return nil, false } -func (i Character) SetSlotValue(key ilos.Instance, value ilos.Instance) { +func (i Character) SetSlotValue(key ilos.Instance, value ilos.Instance) bool { + return false } func (i Character) String() string { diff --git a/runtime/ilos/instance/function.go b/runtime/ilos/instance/function.go index 4101d4b..28b7857 100644 --- a/runtime/ilos/instance/function.go +++ b/runtime/ilos/instance/function.go @@ -18,15 +18,16 @@ func (Function) Class() ilos.Class { return class.Function } -func (f Function) GetSlotValue(key ilos.Instance) ilos.Instance { - return f +func (f Function) GetSlotValue(key ilos.Instance) (ilos.Instance, bool) { + return nil, false } -func (Function) SetSlotValue(key ilos.Instance, value ilos.Instance) { +func (Function) SetSlotValue(key ilos.Instance, value ilos.Instance) bool { + return false } func (f Function) String() string { - return fmt.Sprintf("#%v[]", f.Class()) + return fmt.Sprintf("#%v", f.Class()) } type GenericFunction map[[128]ilos.Class]Function @@ -35,7 +36,7 @@ func (GenericFunction) Class() ilos.Class { return class.GenericFunction } -func (f GenericFunction) GetSlotValue(key ilos.Instance) ilos.Instance { +func (f GenericFunction) GetSlotValue(key ilos.Instance) (ilos.Instance, bool) { types := [128]ilos.Class{} cdr := key idx := 0 @@ -43,10 +44,13 @@ func (f GenericFunction) GetSlotValue(key ilos.Instance) ilos.Instance { types[idx] = cdr.Class() idx++ } - return f[types] + if v, ok := f[types]; ok { + return v, true + } + return nil, false } -func (f GenericFunction) SetSlotValue(key ilos.Instance, value ilos.Instance) { +func (f GenericFunction) SetSlotValue(key ilos.Instance, value ilos.Instance) bool { types := [128]ilos.Class{} cdr := key idx := 0 @@ -55,10 +59,11 @@ func (f GenericFunction) SetSlotValue(key ilos.Instance, value ilos.Instance) { idx++ } f[types] = value.(Function) + return true } func (f GenericFunction) String() string { - return fmt.Sprintf("#%v[]", f.Class()) + return fmt.Sprintf("#%v", f.Class()) } type StandardGenericFunction map[[128]ilos.Class]Function @@ -67,7 +72,7 @@ func (StandardGenericFunction) Class() ilos.Class { return class.StandardGenericFunction } -func (f StandardGenericFunction) GetSlotValue(key ilos.Instance) ilos.Instance { +func (f StandardGenericFunction) GetSlotValue(key ilos.Instance) (ilos.Instance, bool) { types := [128]ilos.Class{} cdr := key idx := 0 @@ -75,10 +80,13 @@ func (f StandardGenericFunction) GetSlotValue(key ilos.Instance) ilos.Instance { types[idx] = cdr.Class() idx++ } - return f[types] + if v, ok := f[types]; ok { + return v, true + } + return nil, false } -func (f StandardGenericFunction) SetSlotValue(key ilos.Instance, value ilos.Instance) { +func (f StandardGenericFunction) SetSlotValue(key ilos.Instance, value ilos.Instance) bool { types := [128]ilos.Class{} cdr := key idx := 0 @@ -87,8 +95,9 @@ func (f StandardGenericFunction) SetSlotValue(key ilos.Instance, value ilos.Inst idx++ } f[types] = value.(Function) + return true } func (f StandardGenericFunction) String() string { - return fmt.Sprintf("#%v[]", f.Class()) + return fmt.Sprintf("#%v", f.Class()) } diff --git a/runtime/ilos/instance/instance.go b/runtime/ilos/instance/instance.go index 330a8c1..00f070b 100644 --- a/runtime/ilos/instance/instance.go +++ b/runtime/ilos/instance/instance.go @@ -19,17 +19,25 @@ func (i *instance) Class() ilos.Class { return i.class } -func (i *instance) GetSlotValue(key ilos.Instance) ilos.Instance { - v, _ := i.slots[string(key.(Symbol))] - return v +func (i *instance) GetSlotValue(key ilos.Instance) (ilos.Instance, bool) { + if symbol, ok := key.(Symbol); ok { + v, ok := i.slots[string(symbol)] + return v, ok + } + return nil, false } -func (i *instance) SetSlotValue(key ilos.Instance, value ilos.Instance) { - i.slots[string(key.(Symbol))] = value +func (i *instance) SetSlotValue(key ilos.Instance, value ilos.Instance) bool { + if symbol, ok := key.(Symbol); ok { + if _, ok := i.slots[string(symbol)]; ok { + i.slots[string(symbol)] = value + return true + } + } + return false } func (i *instance) String() string { class := fmt.Sprint(i.class) - return fmt.Sprintf("#%v %v>", class[:len(class)-1], i.slots) } diff --git a/runtime/ilos/instance/list.go b/runtime/ilos/instance/list.go index baf0fe6..ed5e95a 100644 --- a/runtime/ilos/instance/list.go +++ b/runtime/ilos/instance/list.go @@ -24,11 +24,30 @@ func (*Cons) Class() ilos.Class { return class.Cons } -func (i *Cons) GetSlotValue(key ilos.Instance) ilos.Instance { - return nil +func (i *Cons) GetSlotValue(key ilos.Instance) (ilos.Instance, bool) { + if symbol, ok := key.(Symbol); ok { + switch symbol { + case "CAR": + return i.car, true + case "CDR": + return i.cdr, true + } + } + return nil, false } -func (i *Cons) SetSlotValue(key ilos.Instance, value ilos.Instance) { +func (i *Cons) SetSlotValue(key ilos.Instance, value ilos.Instance) bool { + if symbol, ok := key.(Symbol); ok { + switch symbol { + case "CAR": + i.car = value + return true + case "CDR": + i.cdr = value + return true + } + } + return false } func (i *Cons) String() string { @@ -64,17 +83,18 @@ func NewNull() ilos.Instance { return &Null{} } -func (*Null) Class() ilos.Class { +func (Null) Class() ilos.Class { return class.Null } -func (i *Null) GetSlotValue(key ilos.Instance) ilos.Instance { - return nil +func (i Null) GetSlotValue(key ilos.Instance) (ilos.Instance, bool) { + return nil, false } -func (i *Null) SetSlotValue(key ilos.Instance, value ilos.Instance) { +func (i Null) SetSlotValue(key ilos.Instance, value ilos.Instance) bool { + return false } -func (*Null) String() string { +func (Null) String() string { return "nil" } diff --git a/runtime/ilos/instance/number.go b/runtime/ilos/instance/number.go index 03f6f29..fc1acbf 100644 --- a/runtime/ilos/instance/number.go +++ b/runtime/ilos/instance/number.go @@ -21,12 +21,12 @@ func (Integer) Class() ilos.Class { return class.Integer } -func (i Integer) GetSlotValue(key ilos.Instance) ilos.Instance { - return nil +func (i Integer) GetSlotValue(key ilos.Instance) (ilos.Instance, bool) { + return nil, false } -func (i Integer) SetSlotValue(key ilos.Instance, value ilos.Instance) { - return +func (i Integer) SetSlotValue(key ilos.Instance, value ilos.Instance) bool { + return false } func (i Integer) String() string { @@ -47,12 +47,12 @@ func (Float) Class() ilos.Class { return class.Float } -func (i Float) GetSlotValue(key ilos.Instance) ilos.Instance { - return nil +func (i Float) GetSlotValue(key ilos.Instance) (ilos.Instance, bool) { + return nil, false } -func (i Float) SetSlotValue(key ilos.Instance, value ilos.Instance) { - return +func (i Float) SetSlotValue(key ilos.Instance, value ilos.Instance) bool { + return false } func (i Float) String() string { diff --git a/runtime/ilos/instance/symbol.go b/runtime/ilos/instance/symbol.go index e04c9d1..e266f51 100644 --- a/runtime/ilos/instance/symbol.go +++ b/runtime/ilos/instance/symbol.go @@ -19,14 +19,14 @@ func (Symbol) Class() ilos.Class { return class.Symbol } -func (i Symbol) GetSlotValue(key ilos.Instance) ilos.Instance { - return nil +func (i Symbol) GetSlotValue(key ilos.Instance) (ilos.Instance, bool) { + return nil, false } -func (i Symbol) SetSlotValue(key ilos.Instance, value ilos.Instance) { - return +func (i Symbol) SetSlotValue(key ilos.Instance, value ilos.Instance) bool { + return false } func (i Symbol) String() string { - return string(i) + return string("\"" + i + "\"") } From 995cf615c1271551ee3cf26a0ddad0f1b5a1d651 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Thu, 3 Aug 2017 17:36:46 +0900 Subject: [PATCH 082/228] Change keys of instance --- runtime/ilos/instance/instance.go | 17 +++++-------- runtime/ilos/instance/serious-error.go | 34 +++++++++++++------------- 2 files changed, 23 insertions(+), 28 deletions(-) diff --git a/runtime/ilos/instance/instance.go b/runtime/ilos/instance/instance.go index 00f070b..a5d5be7 100644 --- a/runtime/ilos/instance/instance.go +++ b/runtime/ilos/instance/instance.go @@ -12,7 +12,7 @@ import ( type instance struct { class ilos.Class - slots map[string]ilos.Instance + slots map[ilos.Instance]ilos.Instance } func (i *instance) Class() ilos.Class { @@ -20,19 +20,14 @@ func (i *instance) Class() ilos.Class { } func (i *instance) GetSlotValue(key ilos.Instance) (ilos.Instance, bool) { - if symbol, ok := key.(Symbol); ok { - v, ok := i.slots[string(symbol)] - return v, ok - } - return nil, false + v, ok := i.slots[key] + return v, ok } func (i *instance) SetSlotValue(key ilos.Instance, value ilos.Instance) bool { - if symbol, ok := key.(Symbol); ok { - if _, ok := i.slots[string(symbol)]; ok { - i.slots[string(symbol)] = value - return true - } + if _, ok := i.slots[key]; ok { + i.slots[key] = value + return true } return false } diff --git a/runtime/ilos/instance/serious-error.go b/runtime/ilos/instance/serious-error.go index 98d6af7..7182d7c 100644 --- a/runtime/ilos/instance/serious-error.go +++ b/runtime/ilos/instance/serious-error.go @@ -12,52 +12,52 @@ import ( func NewArithmeticError(operation, operands ilos.Instance) ilos.Instance { i := new(instance) i.class = class.ArithmeticError - i.slots = map[string]ilos.Instance{} - i.slots["OPERATION"] = operation - i.slots["OPERANDS"] = operands + i.slots = map[ilos.Instance]ilos.Instance{} + i.slots[NewSymbol("OPERATION")] = operation + i.slots[NewSymbol("OPERANDS")] = operands return i } func NewDomainError(object, expectedClass ilos.Instance) ilos.Instance { i := new(instance) i.class = class.DomainError - i.slots = map[string]ilos.Instance{} - i.slots["STRING"] = object - i.slots["EXPECTED-CLASS"] = expectedClass + i.slots = map[ilos.Instance]ilos.Instance{} + i.slots[NewSymbol("STRING")] = object + i.slots[NewSymbol("EXPECTED-CLASS")] = expectedClass return i } func NewParseError(str, expectedClass ilos.Instance) ilos.Instance { i := new(instance) i.class = class.ParseError - i.slots = map[string]ilos.Instance{} - i.slots["STRING"] = str - i.slots["EXPECTED-CLASS"] = expectedClass + i.slots = map[ilos.Instance]ilos.Instance{} + i.slots[NewSymbol("STRING")] = str + i.slots[NewSymbol("EXPECTED-CLASS")] = expectedClass return i } func NewSimpleError(formatString, formatArguments ilos.Instance) ilos.Instance { i := new(instance) i.class = class.SimpleError - i.slots = map[string]ilos.Instance{} - i.slots["FORMAT-STRING"] = formatString - i.slots["FORMAT-ARGUMENTS"] = formatArguments + i.slots = map[ilos.Instance]ilos.Instance{} + i.slots[NewSymbol("FORMAT-STRING")] = formatString + i.slots[NewSymbol("FORMAT-ARGUMENTS")] = formatArguments return i } func NewStreamError(stream ilos.Instance) ilos.Instance { i := new(instance) i.class = class.StreamError - i.slots = map[string]ilos.Instance{} - i.slots["stream"] = stream + i.slots = map[ilos.Instance]ilos.Instance{} + i.slots[NewSymbol("stream")] = stream return i } func NewUndefinedEntityError(name, namespace ilos.Instance) ilos.Instance { i := new(instance) i.class = class.UndefinedEntity - i.slots = map[string]ilos.Instance{} - i.slots["NAME"] = name - i.slots["NAMESPACE"] = namespace + i.slots = map[ilos.Instance]ilos.Instance{} + i.slots[NewSymbol("NAME")] = name + i.slots[NewSymbol("NAMESPACE")] = namespace return i } From aecd8a380222d1bee9230112a5e46dc88d6317a5 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Thu, 3 Aug 2017 18:27:48 +0900 Subject: [PATCH 083/228] Added Define* --- runtime/environment/environment.go | 44 ++++++++++++++++++++---------- runtime/eval.go | 12 ++++---- runtime/eval_test.go | 14 ++++------ runtime/lambda.go | 16 +++++++---- 4 files changed, 52 insertions(+), 34 deletions(-) diff --git a/runtime/environment/environment.go b/runtime/environment/environment.go index 9c4b084..df712b2 100644 --- a/runtime/environment/environment.go +++ b/runtime/environment/environment.go @@ -20,11 +20,11 @@ func New() *Environment { return env } -func (e *Environment) MergeDynamicVariable(f *Environment) { +func AppendDynamicVariable(e *Environment, f *Environment) { e.DynamicVariable = append(e.DynamicVariable, f.DynamicVariable...) } -func (e *Environment) MergeAll(f *Environment) { +func AppendAll(e *Environment, f *Environment) { e.Variable = append(e.Variable, f.Variable...) e.Function = append(e.Function, f.Function...) e.Macro = append(e.Macro, f.Macro...) @@ -34,76 +34,92 @@ func (e *Environment) MergeAll(f *Environment) { func (e *Environment) GetVariable(key ilos.Instance) (ilos.Instance, bool) { for _, vars := range e.Variable { if v, ok := vars[key]; ok { - return v, ok + return v, true } } return nil, false } -func (e *Environment) SetVariable(key ilos.Instance, value ilos.Instance) { +func (e *Environment) SetVariable(key, value ilos.Instance) bool { for _, vars := range e.Variable { if _, ok := vars[key]; ok { vars[key] = value - return + return true } } + return false +} + +func (e *Environment) DefineVariable(key, value ilos.Instance) { e.Variable[0][key] = value } func (e *Environment) GetFunction(key ilos.Instance) (ilos.Instance, bool) { for _, vars := range e.Function { if v, ok := vars[key]; ok { - return v, ok + return v, true } } return nil, false } -func (e *Environment) SetFunction(key ilos.Instance, value ilos.Instance) { +func (e *Environment) SetFunction(key, value ilos.Instance) bool { for _, vars := range e.Function { if _, ok := vars[key]; ok { vars[key] = value - return + return true } } + return false +} + +func (e *Environment) DefineFunction(key, value ilos.Instance) { e.Function[0][key] = value } func (e *Environment) GetMacro(key ilos.Instance) (ilos.Instance, bool) { for _, vars := range e.Macro { if v, ok := vars[key]; ok { - return v, ok + return v, true } } return nil, false } -func (e *Environment) SetMacro(key ilos.Instance, value ilos.Instance) { +func (e *Environment) SetMacro(key, value ilos.Instance) bool { for _, vars := range e.Macro { if _, ok := vars[key]; ok { vars[key] = value - return + return true } } + return false +} + +func (e *Environment) DefineMacro(key, value ilos.Instance) { e.Macro[0][key] = value } func (e *Environment) GetDynamicVariable(key ilos.Instance) (ilos.Instance, bool) { for _, vars := range e.DynamicVariable { if v, ok := vars[key]; ok { - return v, ok + return v, true } } return nil, false } -func (e *Environment) SetDynamicVariable(key ilos.Instance, value ilos.Instance) { +func (e *Environment) SetDynamicVariable(key, value ilos.Instance) bool { for _, vars := range e.DynamicVariable { if _, ok := vars[key]; ok { vars[key] = value - return + return true } } + return false +} + +func (e *Environment) DefineDynamicVariable(key, value ilos.Instance) { e.DynamicVariable[0][key] = value } diff --git a/runtime/eval.go b/runtime/eval.go index 13bc134..4222ef6 100644 --- a/runtime/eval.go +++ b/runtime/eval.go @@ -43,9 +43,9 @@ func evalFunction(obj ilos.Instance, local *env.Environment, global *env.Environ if err != nil { return nil, err } - env := env.New() - env.MergeDynamicVariable(local) - ret, err := fun.(instance.Function)(args, env, global) + e := env.New() + env.AppendDynamicVariable(e, local) + ret, err := fun.(instance.Function)(args, e, global) if err != nil { return nil, err } @@ -84,9 +84,9 @@ func evalFunction(obj ilos.Instance, local *env.Environment, global *env.Environ if err != nil { return nil, err } - env := env.New() - env.MergeDynamicVariable(local) - ret, err := fun.(instance.Function)(args, env, global) + e := env.New() + env.AppendDynamicVariable(e, local) + ret, err := fun.(instance.Function)(args, e, global) if err != nil { return nil, err } diff --git a/runtime/eval_test.go b/runtime/eval_test.go index 85969e2..4a43b19 100644 --- a/runtime/eval_test.go +++ b/runtime/eval_test.go @@ -21,18 +21,16 @@ func read(s string) ilos.Instance { func TestEval(t *testing.T) { local := env.New() global := env.New() - local.SetVariable(instance.NewSymbol("PI"), instance.NewFloat(3.14)) - local.SetFunction(instance.NewSymbol("INC"), instance.NewFunction(func(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { + local.DefineVariable(instance.NewSymbol("PI"), instance.NewFloat(3.14)) + local.DefineFunction(instance.NewSymbol("INC"), instance.NewFunction(func(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { car := instance.UnsafeCar(args) return instance.NewInteger(int(car.(instance.Integer)) + 1), nil })) - local.SetMacro(instance.NewSymbol("MINC"), instance.NewFunction(func(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { + local.DefineMacro(instance.NewSymbol("MINC"), instance.NewFunction(func(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { ret, err := Eval(instance.NewCons(instance.NewSymbol("INC"), args), local, global) return ret, err })) - local.SetMacro(instance.NewSymbol("LAMBDA"), instance.NewFunction(func(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { - return NewLambdaFunction(instance.UnsafeCar(args), instance.UnsafeCdr(args), local), nil - })) + local.DefineMacro(instance.NewSymbol("LAMBDA"), instance.NewFunction(lambda)) type args struct { obj ilos.Instance local *env.Environment @@ -64,8 +62,8 @@ func TestEval(t *testing.T) { }, { name: "lambda form", - args: args{read("((lambda (x) (inc x)) 1)"), local, global}, - want: instance.NewInteger(2), + args: args{read("((lambda (x)) 1)"), local, global}, + want: instance.NewNull(), wantErr: false, }, } diff --git a/runtime/lambda.go b/runtime/lambda.go index 8b1806a..b846051 100644 --- a/runtime/lambda.go +++ b/runtime/lambda.go @@ -7,9 +7,12 @@ import ( "github.com/ta2gch/iris/runtime/ilos/instance" ) -func NewLambdaFunction(lambdaList ilos.Instance, forms ilos.Instance, lexical *env.Environment) ilos.Instance { +func lambda(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { + lambdaList := instance.UnsafeCar(args) + forms := instance.UnsafeCdr(args) + lexical := local return instance.NewFunction(func(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { - local.MergeAll(lexical) + env.AppendAll(local, lexical) fargs := lambdaList aargs := args for !ilos.InstanceOf(fargs, class.Null) { @@ -22,15 +25,16 @@ func NewLambdaFunction(lambdaList ilos.Instance, forms ilos.Instance, lexical *e if !ilos.InstanceOf(cddr, class.Null) { return nil, instance.NewParseError(instance.NewString(fargs.String()), class.List) } - local.SetVariable(cadr, aargs) + local.DefineVariable(cadr, aargs) break } - local.SetVariable(key, value) + local.DefineVariable(key, value) fargs = instance.UnsafeCdr(fargs) aargs = instance.UnsafeCdr(aargs) } body := forms - var ret, err ilos.Instance + ret := instance.NewNull() + var err ilos.Instance for !ilos.InstanceOf(body, class.Null) { exp := instance.UnsafeCar(body) ret, err = Eval(exp, local, global) @@ -40,5 +44,5 @@ func NewLambdaFunction(lambdaList ilos.Instance, forms ilos.Instance, lexical *e body = instance.UnsafeCdr(body) } return ret, nil - }) + }), nil } From 97ad12fd287901a2926512912aac4c74f133a382 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Thu, 3 Aug 2017 18:28:10 +0900 Subject: [PATCH 084/228] ptr -> value --- runtime/ilos/instance/list.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/ilos/instance/list.go b/runtime/ilos/instance/list.go index ed5e95a..b5f09d3 100644 --- a/runtime/ilos/instance/list.go +++ b/runtime/ilos/instance/list.go @@ -80,7 +80,7 @@ func UnsafeCdr(i ilos.Instance) ilos.Instance { type Null struct{} func NewNull() ilos.Instance { - return &Null{} + return Null{} } func (Null) Class() ilos.Class { From a6c4e451ddda87a43f1950faa7a32fd1b06263a2 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Thu, 3 Aug 2017 21:18:03 +0900 Subject: [PATCH 085/228] Added dynamic arguments support --- reader/parser/parser.go | 5 ++- runtime/eval_test.go | 6 +++ runtime/ilos/instance/symbol.go | 2 +- runtime/lambda.go | 68 +++++++++++++++++++++++++-------- runtime/util.go | 28 ++++++++++++++ 5 files changed, 91 insertions(+), 18 deletions(-) create mode 100644 runtime/util.go diff --git a/reader/parser/parser.go b/reader/parser/parser.go index 3022c3e..9e91d9b 100644 --- a/reader/parser/parser.go +++ b/reader/parser/parser.go @@ -73,7 +73,10 @@ func parseAtom(tok string) (ilos.Instance, ilos.Instance) { return instance.NewNull(), nil } if r := regexp.MustCompile("^:([<>/*=?_!$%[\\]^{}~0-9a-zA-Z]+)$").FindStringSubmatch(tok); len(r) >= 2 { - return instance.NewSymbol(strings.ToUpper(r[1])), nil + return instance.NewSymbol(strings.ToUpper(r[0])), nil + } + if r := regexp.MustCompile("^&([<>/*=?_!$%[\\]^{}~0-9a-zA-Z]+)$").FindStringSubmatch(tok); len(r) >= 2 { + return instance.NewSymbol(strings.ToUpper(r[0])), nil } if m, _ := regexp.MatchString("^\\|.*\\|$", tok); m { return instance.NewSymbol(tok), nil diff --git a/runtime/eval_test.go b/runtime/eval_test.go index 4a43b19..35ce044 100644 --- a/runtime/eval_test.go +++ b/runtime/eval_test.go @@ -66,6 +66,12 @@ func TestEval(t *testing.T) { want: instance.NewNull(), wantErr: false, }, + { + name: "lambda form", + args: args{read("((lambda (:rest xs) xs) 1 2)"), local, global}, + want: read("(1 2)"), + wantErr: false, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/runtime/ilos/instance/symbol.go b/runtime/ilos/instance/symbol.go index e266f51..cb895ed 100644 --- a/runtime/ilos/instance/symbol.go +++ b/runtime/ilos/instance/symbol.go @@ -28,5 +28,5 @@ func (i Symbol) SetSlotValue(key ilos.Instance, value ilos.Instance) bool { } func (i Symbol) String() string { - return string("\"" + i + "\"") + return string(i) } diff --git a/runtime/lambda.go b/runtime/lambda.go index b846051..71f64ea 100644 --- a/runtime/lambda.go +++ b/runtime/lambda.go @@ -8,40 +8,76 @@ import ( ) func lambda(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { + // args must be a instance of Cons, not Null, and ends with nil + if !ilos.InstanceOf(args, class.Cons) || !UnsafeEndOfListIsNil(args) { // Checked at the head of test + return nil, instance.NewParseError(args, class.Cons) + } lambdaList := instance.UnsafeCar(args) - forms := instance.UnsafeCdr(args) + // lambda-list must be a instance of list and ends with nil + if !ilos.InstanceOf(lambdaList, class.List) || !UnsafeEndOfListIsNil(lambdaList) { // Checked at the head of test + return nil, instance.NewParseError(lambdaList, class.List) + } + forms := instance.UnsafeCdr(args) // Checked at the top of this function. (EndOfListIsNil) lexical := local return instance.NewFunction(func(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { env.AppendAll(local, lexical) + + // args must be a instance of list and end with nil + if !ilos.InstanceOf(args, class.List) || !UnsafeEndOfListIsNil(args) { // Checked at the head of test + return nil, instance.NewParseError(args, class.List) + } + cdr := lambdaList + ok := false + for ilos.InstanceOf(cdr, class.Cons) { + car := instance.UnsafeCar(cdr) // Checked at the top of this loop. + cdr = instance.UnsafeCdr(cdr) // Checked at the top of this loop. + if car == instance.NewSymbol(":REST") || car == instance.NewSymbol("&REST") { + // fargs has only one symbol after &rest or :rest symbol. + if ilos.InstanceOf(cdr, class.List) && UnsafeListLength(cdr) == 1 { // Checked at the head of test + // If fargs has :rest or &rest symbol, The length of aargs must be greater than or equal to 'the length of fargs' - 2. + // aargs is a instance of list and ends with nil becauseof the checking at this function. + // lambda-list is a instance of list and ends with nil becauseof the checking at the function, lambda. + if UnsafeListLength(lambdaList)-2 <= UnsafeListLength(args) { + ok = true + break + } else { + return nil, instance.NewParseError(args, class.List) + } + } else { + return nil, instance.NewParseError(lambdaList, class.List) + } + } + } + // If fargs doesn't have them, The length of aargs must be equal to the length of fargs. + // aargs is a instance of list and ends nil becauseof the checking at this function. + // lambda-list is a instance of list and ends nil becauseof the checking at the function, lambda. + if !ok && UnsafeListLength(lambdaList) != UnsafeListLength(args) { + return nil, instance.NewParseError(args, class.List) + } fargs := lambdaList aargs := args - for !ilos.InstanceOf(fargs, class.Null) { - key := instance.UnsafeCar(fargs) - value := instance.UnsafeCar(aargs) - if key == instance.NewSymbol(":rest") || key == instance.NewSymbol("&rest") { - cdr := instance.UnsafeCdr(fargs) - cadr := instance.UnsafeCar(cdr) - cddr := instance.UnsafeCdr(cdr) - if !ilos.InstanceOf(cddr, class.Null) { - return nil, instance.NewParseError(instance.NewString(fargs.String()), class.List) - } + for ilos.InstanceOf(fargs, class.Cons) && ilos.InstanceOf(aargs, class.Cons) { + key := instance.UnsafeCar(fargs) // Checked at the top of this loop. + value := instance.UnsafeCar(aargs) // Checked at the top of this loop. + if key == instance.NewSymbol(":REST") || key == instance.NewSymbol("&REST") { + cadr := instance.UnsafeCar(instance.UnsafeCdr(fargs)) // Checked before type checking secion local.DefineVariable(cadr, aargs) break } local.DefineVariable(key, value) - fargs = instance.UnsafeCdr(fargs) - aargs = instance.UnsafeCdr(aargs) + fargs = instance.UnsafeCdr(fargs) // Checked at the top of this loop + aargs = instance.UnsafeCdr(aargs) // Checked at the top of this loop } body := forms ret := instance.NewNull() var err ilos.Instance - for !ilos.InstanceOf(body, class.Null) { - exp := instance.UnsafeCar(body) + for ilos.InstanceOf(body, class.Cons) { + exp := instance.UnsafeCar(body) // Checked at the top of this loop ret, err = Eval(exp, local, global) if err != nil { return nil, err } - body = instance.UnsafeCdr(body) + body = instance.UnsafeCdr(body) // Checked at the top of this loop } return ret, nil }), nil diff --git a/runtime/util.go b/runtime/util.go new file mode 100644 index 0000000..514aeb6 --- /dev/null +++ b/runtime/util.go @@ -0,0 +1,28 @@ +package runtime + +import ( + "github.com/ta2gch/iris/runtime/ilos" + "github.com/ta2gch/iris/runtime/ilos/class" + "github.com/ta2gch/iris/runtime/ilos/instance" +) + +func UnsafeEndOfListIsNil(i ilos.Instance) bool { + cdr := i + for ilos.InstanceOf(cdr, class.Cons) { + cdr = instance.UnsafeCdr(cdr) // Checked at the top of this loop + } + if ilos.InstanceOf(cdr, class.Null) { + return true + } + return false +} + +func UnsafeListLength(i ilos.Instance) int { + cdr := i + cnt := 0 + for ilos.InstanceOf(cdr, class.Cons) { + cdr = instance.UnsafeCdr(cdr) // Checked at the top of this loop + cnt++ + } + return cnt +} From 1aea7b64f98a74f7ea7a66c91cb5d50418c0edbe Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Thu, 3 Aug 2017 21:18:35 +0900 Subject: [PATCH 086/228] Changed display of string --- runtime/ilos/instance/basic-array.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/ilos/instance/basic-array.go b/runtime/ilos/instance/basic-array.go index db96065..2e0d99b 100644 --- a/runtime/ilos/instance/basic-array.go +++ b/runtime/ilos/instance/basic-array.go @@ -148,5 +148,5 @@ func (i String) SetSlotValue(key ilos.Instance, value ilos.Instance) bool { } func (i String) String() string { - return string(i) + return "\"" + string(i) + "\"" } From bd948cb6bd1113e11098207cb5524c98c43891df Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Thu, 3 Aug 2017 21:33:43 +0900 Subject: [PATCH 087/228] Check for unsafe functions --- runtime/eval.go | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/runtime/eval.go b/runtime/eval.go index 4222ef6..74e06e2 100644 --- a/runtime/eval.go +++ b/runtime/eval.go @@ -8,11 +8,16 @@ import ( ) func evalArguments(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { + // if args ends here if ilos.InstanceOf(args, class.Null) { return instance.NewNull(), nil } - car := instance.UnsafeCar(args) - cdr := instance.UnsafeCdr(args) + // args must be a instance of list and ends with nil + if !ilos.InstanceOf(args, class.List) || !UnsafeEndOfListIsNil(args) { + return nil, instance.NewParseError(args, class.List) + } + car := instance.UnsafeCar(args) // Checked there + cdr := instance.UnsafeCdr(args) // Checked there a, err := Eval(car, local, global) if err != nil { return nil, err @@ -22,23 +27,29 @@ func evalArguments(args ilos.Instance, local *env.Environment, global *env.Envir return nil, err } return instance.NewCons(a, b), nil + } func evalFunction(obj ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { + // obj, function call form, must be a instance of Cons, NOT Null, and ends with nil + if !ilos.InstanceOf(obj, class.Cons) || !UnsafeEndOfListIsNil(obj) { + return nil, instance.NewParseError(obj, class.Cons) + } // get function symbol - car := instance.UnsafeCar(obj) + car := instance.UnsafeCar(obj) // Checked at the top of this function // get function arguments - cdr := instance.UnsafeCdr(obj) + cdr := instance.UnsafeCdr(obj) // Checked at the top of this function // eval if lambda form if ilos.InstanceOf(car, class.Cons) { - caar := instance.UnsafeCar(car) + caar := instance.UnsafeCar(car) // Checked at the top of this sentence if caar == instance.NewSymbol("LAMBDA") { fun, err := Eval(car, local, global) if err != nil { return nil, err } + args, err := evalArguments(cdr, local, global) if err != nil { return nil, err @@ -52,7 +63,7 @@ func evalFunction(obj ilos.Instance, local *env.Environment, global *env.Environ return ret, nil } } - + // if function is not a lambda special form, first element must be a symbol if !ilos.InstanceOf(car, class.Symbol) { return nil, instance.NewDomainError(car, class.Symbol) } From cc470bc70f5a74ebf8a833746cf4d6873a5ff3d8 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Fri, 4 Aug 2017 08:42:44 +0900 Subject: [PATCH 088/228] Added some comments --- runtime/util.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/runtime/util.go b/runtime/util.go index 514aeb6..6e436d2 100644 --- a/runtime/util.go +++ b/runtime/util.go @@ -6,6 +6,9 @@ import ( "github.com/ta2gch/iris/runtime/ilos/instance" ) +// UnsafeEndOfListIsNil test a given instance ends with nil +// but doesn't work correctly if the given instance isn't a instance of list +// So you have to check the instance. func UnsafeEndOfListIsNil(i ilos.Instance) bool { cdr := i for ilos.InstanceOf(cdr, class.Cons) { @@ -17,6 +20,9 @@ func UnsafeEndOfListIsNil(i ilos.Instance) bool { return false } +// UnsafeListLength return a length of list +// but doesn't work correctly if the given instance aren't a instance of list. +// So you have to check the instance. func UnsafeListLength(i ilos.Instance) int { cdr := i cnt := 0 From 94393e5ae832cd0a9d0e63e604ea38858f299b1a Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Fri, 4 Aug 2017 10:44:57 +0900 Subject: [PATCH 089/228] added tyr catch --- reader/parser/parser.go | 4 +-- runtime/catch.go | 39 ++++++++++++++++++++++++++++++ runtime/environment/environment.go | 30 +++++++++++++++++++++++ runtime/eval.go | 2 ++ runtime/eval_test.go | 10 ++++++-- runtime/function.go | 27 +++++++++++++++++++++ runtime/ilos/class/class.go | 1 + runtime/ilos/instance/throw.go | 15 ++++++++++++ runtime/quote.go | 16 ++++++++++++ runtime/runtime.go | 13 ++++++++++ runtime/throw.go | 21 ++++++++++++++++ 11 files changed, 174 insertions(+), 4 deletions(-) create mode 100644 runtime/catch.go create mode 100644 runtime/function.go create mode 100644 runtime/ilos/instance/throw.go create mode 100644 runtime/quote.go create mode 100644 runtime/runtime.go create mode 100644 runtime/throw.go diff --git a/reader/parser/parser.go b/reader/parser/parser.go index 9e91d9b..21b898b 100644 --- a/reader/parser/parser.go +++ b/reader/parser/parser.go @@ -113,9 +113,9 @@ func parseMacro(tok string, t *tokenizer.Tokenizer) (ilos.Instance, ilos.Instanc case ",": n = "comma" case "'": - n = "quote" + n = "QUOTE" case "`": - n = "backquote" + n = "BACKQUOTE" } m := instance.NewSymbol(n) return instance.NewCons(m, instance.NewCons(cdr, instance.NewNull())), nil diff --git a/runtime/catch.go b/runtime/catch.go new file mode 100644 index 0000000..2ed3530 --- /dev/null +++ b/runtime/catch.go @@ -0,0 +1,39 @@ +package runtime + +import ( + env "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/ilos" + "github.com/ta2gch/iris/runtime/ilos/class" + "github.com/ta2gch/iris/runtime/ilos/instance" +) + +func catch(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { + // args must be a instance of Cons, not Null, and ends with nil + if !ilos.InstanceOf(args, class.Cons) || !UnsafeEndOfListIsNil(args) || UnsafeListLength(args) < 2 { // Checked at the head of test + return nil, instance.NewParseError(args, class.Cons) + } + car, err := Eval(instance.UnsafeCar(args), local, global) // Checked at the top of this function + if err != nil { + return nil, err + } + local.DefineThrowTag(car, car) + cdr := instance.UnsafeCdr(args) // Checked at the top of this function + var sucess, fail ilos.Instance + for ilos.InstanceOf(cdr, class.Cons) { + cadr := instance.UnsafeCar(cdr) // Checked at the top of this loop + cddr := instance.UnsafeCdr(cdr) // Checked at the top of this loop + sucess, fail = Eval(cadr, local, global) + if fail != nil { + if ilos.InstanceOf(fail, class.Throw) { + tag, _ := fail.GetSlotValue(instance.NewSymbol("TAG")) // Checked at the head of this condition + if car == tag { + obj, _ := fail.GetSlotValue(instance.NewSymbol("OBJECT")) // Checked at the head of this condition + return obj, nil + } + } + return nil, fail + } + cdr = cddr + } + return sucess, nil +} diff --git a/runtime/environment/environment.go b/runtime/environment/environment.go index df712b2..8cce0a0 100644 --- a/runtime/environment/environment.go +++ b/runtime/environment/environment.go @@ -4,6 +4,7 @@ import "github.com/ta2gch/iris/runtime/ilos" // Environment struct is the struct for keeping functions and variables type Environment struct { + ThrowTag []map[ilos.Instance]ilos.Instance Macro []map[ilos.Instance]ilos.Instance Function []map[ilos.Instance]ilos.Instance Variable []map[ilos.Instance]ilos.Instance @@ -13,6 +14,7 @@ type Environment struct { // New creates new environment func New() *Environment { env := new(Environment) + env.ThrowTag = []map[ilos.Instance]ilos.Instance{map[ilos.Instance]ilos.Instance{}} env.Macro = []map[ilos.Instance]ilos.Instance{map[ilos.Instance]ilos.Instance{}} env.Function = []map[ilos.Instance]ilos.Instance{map[ilos.Instance]ilos.Instance{}} env.Variable = []map[ilos.Instance]ilos.Instance{map[ilos.Instance]ilos.Instance{}} @@ -24,13 +26,41 @@ func AppendDynamicVariable(e *Environment, f *Environment) { e.DynamicVariable = append(e.DynamicVariable, f.DynamicVariable...) } +func AppendThrowTag(e *Environment, f *Environment) { + e.ThrowTag = append(e.ThrowTag, f.ThrowTag...) +} + func AppendAll(e *Environment, f *Environment) { + e.ThrowTag = append(e.ThrowTag, f.ThrowTag...) e.Variable = append(e.Variable, f.Variable...) e.Function = append(e.Function, f.Function...) e.Macro = append(e.Macro, f.Macro...) e.DynamicVariable = append(e.DynamicVariable, f.DynamicVariable...) } +func (e *Environment) GetThrowTag(key ilos.Instance) (ilos.Instance, bool) { + for _, vars := range e.ThrowTag { + if v, ok := vars[key]; ok { + return v, true + } + } + return nil, false +} + +func (e *Environment) SetThrowTag(key, value ilos.Instance) bool { + for _, vars := range e.ThrowTag { + if _, ok := vars[key]; ok { + vars[key] = value + return true + } + } + return false +} + +func (e *Environment) DefineThrowTag(key, value ilos.Instance) { + e.ThrowTag[0][key] = value +} + func (e *Environment) GetVariable(key ilos.Instance) (ilos.Instance, bool) { for _, vars := range e.Variable { if v, ok := vars[key]; ok { diff --git a/runtime/eval.go b/runtime/eval.go index 74e06e2..b1a3bd1 100644 --- a/runtime/eval.go +++ b/runtime/eval.go @@ -56,6 +56,7 @@ func evalFunction(obj ilos.Instance, local *env.Environment, global *env.Environ } e := env.New() env.AppendDynamicVariable(e, local) + env.AppendThrowTag(e, local) ret, err := fun.(instance.Function)(args, e, global) if err != nil { return nil, err @@ -97,6 +98,7 @@ func evalFunction(obj ilos.Instance, local *env.Environment, global *env.Environ } e := env.New() env.AppendDynamicVariable(e, local) + env.AppendThrowTag(e, local) ret, err := fun.(instance.Function)(args, e, global) if err != nil { return nil, err diff --git a/runtime/eval_test.go b/runtime/eval_test.go index 35ce044..7730b0d 100644 --- a/runtime/eval_test.go +++ b/runtime/eval_test.go @@ -19,8 +19,9 @@ func read(s string) ilos.Instance { } func TestEval(t *testing.T) { + Init() local := env.New() - global := env.New() + global := env.TopLevel local.DefineVariable(instance.NewSymbol("PI"), instance.NewFloat(3.14)) local.DefineFunction(instance.NewSymbol("INC"), instance.NewFunction(func(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { car := instance.UnsafeCar(args) @@ -30,7 +31,6 @@ func TestEval(t *testing.T) { ret, err := Eval(instance.NewCons(instance.NewSymbol("INC"), args), local, global) return ret, err })) - local.DefineMacro(instance.NewSymbol("LAMBDA"), instance.NewFunction(lambda)) type args struct { obj ilos.Instance local *env.Environment @@ -72,6 +72,12 @@ func TestEval(t *testing.T) { want: read("(1 2)"), wantErr: false, }, + { + name: "throw", + args: args{read("(catch 'foo 1 (throw 'foo 1))"), local, global}, + want: read("1"), + wantErr: false, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/runtime/function.go b/runtime/function.go new file mode 100644 index 0000000..9978d97 --- /dev/null +++ b/runtime/function.go @@ -0,0 +1,27 @@ +package runtime + +import ( + env "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/ilos" + "github.com/ta2gch/iris/runtime/ilos/class" + "github.com/ta2gch/iris/runtime/ilos/instance" +) + +func function(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { + // args must be a instance of Cons, not Null, and ends with nil + if !ilos.InstanceOf(args, class.Cons) || !UnsafeEndOfListIsNil(args) || UnsafeListLength(args) != 1 { // Checked at the head of test + return nil, instance.NewParseError(args, class.Cons) + } + car := instance.UnsafeCar(args) // Checked at the top of this function + // car must be a symbol + if !ilos.InstanceOf(car, class.Symbol) { + return nil, instance.NewDomainError(car, class.Symbol) + } + if f, ok := local.GetFunction(car); ok { + return f, nil + } + if f, ok := global.GetFunction(car); ok { + return f, nil + } + return nil, instance.NewUndefinedEntityError(nil, nil) +} diff --git a/runtime/ilos/class/class.go b/runtime/ilos/class/class.go index 03757b5..b8425a1 100644 --- a/runtime/ilos/class/class.go +++ b/runtime/ilos/class/class.go @@ -66,3 +66,4 @@ var EndOfStream = &builtinclass{[]ilos.Class{StreamError}, ""} var StorageExhausted = &builtinclass{[]ilos.Class{SeriousCondition}, ""} var StandardObject = &builtinclass{[]ilos.Class{Object}, ""} var Stream = &builtinclass{[]ilos.Class{Object}, ""} +var Throw = &builtinclass{[]ilos.Class{Object}, ""} diff --git a/runtime/ilos/instance/throw.go b/runtime/ilos/instance/throw.go new file mode 100644 index 0000000..ed76bfa --- /dev/null +++ b/runtime/ilos/instance/throw.go @@ -0,0 +1,15 @@ +package instance + +import ( + "github.com/ta2gch/iris/runtime/ilos" + "github.com/ta2gch/iris/runtime/ilos/class" +) + +func NewThrow(operation, operands ilos.Instance) ilos.Instance { + i := new(instance) + i.class = class.Throw + i.slots = map[ilos.Instance]ilos.Instance{} + i.slots[NewSymbol("TAG")] = operation + i.slots[NewSymbol("OBJECT")] = operands + return i +} diff --git a/runtime/quote.go b/runtime/quote.go new file mode 100644 index 0000000..de0d5a1 --- /dev/null +++ b/runtime/quote.go @@ -0,0 +1,16 @@ +package runtime + +import ( + env "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/ilos" + "github.com/ta2gch/iris/runtime/ilos/class" + "github.com/ta2gch/iris/runtime/ilos/instance" +) + +func quote(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { + // args must be a instance of Cons, not Null, and ends with nil + if !ilos.InstanceOf(args, class.Cons) || !UnsafeEndOfListIsNil(args) || UnsafeListLength(args) != 1 { // Checked at the head of test + return nil, instance.NewParseError(args, class.Cons) + } + return instance.UnsafeCar(args), nil +} diff --git a/runtime/runtime.go b/runtime/runtime.go new file mode 100644 index 0000000..745b125 --- /dev/null +++ b/runtime/runtime.go @@ -0,0 +1,13 @@ +package runtime + +import ( + e "github.com/ta2gch/iris/runtime/environment" + i "github.com/ta2gch/iris/runtime/ilos/instance" +) + +func Init() { + e.TopLevel.DefineMacro(i.NewSymbol("LAMBDA"), i.NewFunction(lambda)) + e.TopLevel.DefineMacro(i.NewSymbol("QUOTE"), i.NewFunction(quote)) + e.TopLevel.DefineFunction(i.NewSymbol("THROW"), i.NewFunction(throw)) + e.TopLevel.DefineMacro(i.NewSymbol("CATCH"), i.NewFunction(catch)) +} diff --git a/runtime/throw.go b/runtime/throw.go new file mode 100644 index 0000000..c042eec --- /dev/null +++ b/runtime/throw.go @@ -0,0 +1,21 @@ +package runtime + +import ( + env "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/ilos" + "github.com/ta2gch/iris/runtime/ilos/class" + "github.com/ta2gch/iris/runtime/ilos/instance" +) + +func throw(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { + // args must be a instance of Cons, not Null, and ends with nil + if !ilos.InstanceOf(args, class.Cons) || !UnsafeEndOfListIsNil(args) || UnsafeListLength(args) != 2 { // Checked at the head of test + return nil, instance.NewParseError(args, class.Cons) + } + car := instance.UnsafeCar(args) // Checked at the top of this function + if _, ok := local.GetThrowTag(car); !ok { + return nil, instance.NewSimpleError(instance.NewString("%v is not defined as the tag"), car) + } + cadr := instance.UnsafeCar(instance.UnsafeCdr(args)) // Checked length is 2 at the top of this function + return nil, instance.NewThrow(car, cadr) +} From a22b6098d1c8d800a0ea6b6b03c3e406577ce85b Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Fri, 4 Aug 2017 11:15:48 +0900 Subject: [PATCH 090/228] refactor environment --- runtime/catch.go | 2 +- runtime/environment/environment.go | 153 ++--------------------------- runtime/environment/stack.go | 34 +++++++ runtime/eval.go | 28 +++--- runtime/eval_test.go | 6 +- runtime/function.go | 4 +- runtime/lambda.go | 11 ++- runtime/runtime.go | 8 +- runtime/throw.go | 2 +- 9 files changed, 76 insertions(+), 172 deletions(-) create mode 100644 runtime/environment/stack.go diff --git a/runtime/catch.go b/runtime/catch.go index 2ed3530..a022a30 100644 --- a/runtime/catch.go +++ b/runtime/catch.go @@ -16,7 +16,7 @@ func catch(args ilos.Instance, local *env.Environment, global *env.Environment) if err != nil { return nil, err } - local.DefineThrowTag(car, car) + local.ThrowTag.Define(car, car) cdr := instance.UnsafeCdr(args) // Checked at the top of this function var sucess, fail ilos.Instance for ilos.InstanceOf(cdr, class.Cons) { diff --git a/runtime/environment/environment.go b/runtime/environment/environment.go index 8cce0a0..3187acf 100644 --- a/runtime/environment/environment.go +++ b/runtime/environment/environment.go @@ -1,157 +1,24 @@ package environment -import "github.com/ta2gch/iris/runtime/ilos" - // Environment struct is the struct for keeping functions and variables type Environment struct { - ThrowTag []map[ilos.Instance]ilos.Instance - Macro []map[ilos.Instance]ilos.Instance - Function []map[ilos.Instance]ilos.Instance - Variable []map[ilos.Instance]ilos.Instance - DynamicVariable []map[ilos.Instance]ilos.Instance // deep biding + ThrowTag stack + Macro stack + Function stack + Variable stack + DynamicVariable stack // deep biding } // New creates new environment func New() *Environment { env := new(Environment) - env.ThrowTag = []map[ilos.Instance]ilos.Instance{map[ilos.Instance]ilos.Instance{}} - env.Macro = []map[ilos.Instance]ilos.Instance{map[ilos.Instance]ilos.Instance{}} - env.Function = []map[ilos.Instance]ilos.Instance{map[ilos.Instance]ilos.Instance{}} - env.Variable = []map[ilos.Instance]ilos.Instance{map[ilos.Instance]ilos.Instance{}} - env.DynamicVariable = []map[ilos.Instance]ilos.Instance{map[ilos.Instance]ilos.Instance{}} + env.ThrowTag = newStack() + env.Macro = newStack() + env.Function = newStack() + env.Variable = newStack() + env.DynamicVariable = newStack() return env } -func AppendDynamicVariable(e *Environment, f *Environment) { - e.DynamicVariable = append(e.DynamicVariable, f.DynamicVariable...) -} - -func AppendThrowTag(e *Environment, f *Environment) { - e.ThrowTag = append(e.ThrowTag, f.ThrowTag...) -} - -func AppendAll(e *Environment, f *Environment) { - e.ThrowTag = append(e.ThrowTag, f.ThrowTag...) - e.Variable = append(e.Variable, f.Variable...) - e.Function = append(e.Function, f.Function...) - e.Macro = append(e.Macro, f.Macro...) - e.DynamicVariable = append(e.DynamicVariable, f.DynamicVariable...) -} - -func (e *Environment) GetThrowTag(key ilos.Instance) (ilos.Instance, bool) { - for _, vars := range e.ThrowTag { - if v, ok := vars[key]; ok { - return v, true - } - } - return nil, false -} - -func (e *Environment) SetThrowTag(key, value ilos.Instance) bool { - for _, vars := range e.ThrowTag { - if _, ok := vars[key]; ok { - vars[key] = value - return true - } - } - return false -} - -func (e *Environment) DefineThrowTag(key, value ilos.Instance) { - e.ThrowTag[0][key] = value -} - -func (e *Environment) GetVariable(key ilos.Instance) (ilos.Instance, bool) { - for _, vars := range e.Variable { - if v, ok := vars[key]; ok { - return v, true - } - } - return nil, false -} - -func (e *Environment) SetVariable(key, value ilos.Instance) bool { - for _, vars := range e.Variable { - if _, ok := vars[key]; ok { - vars[key] = value - return true - } - } - return false -} - -func (e *Environment) DefineVariable(key, value ilos.Instance) { - e.Variable[0][key] = value -} - -func (e *Environment) GetFunction(key ilos.Instance) (ilos.Instance, bool) { - for _, vars := range e.Function { - if v, ok := vars[key]; ok { - return v, true - } - } - return nil, false -} - -func (e *Environment) SetFunction(key, value ilos.Instance) bool { - for _, vars := range e.Function { - if _, ok := vars[key]; ok { - vars[key] = value - return true - } - } - return false -} - -func (e *Environment) DefineFunction(key, value ilos.Instance) { - e.Function[0][key] = value -} - -func (e *Environment) GetMacro(key ilos.Instance) (ilos.Instance, bool) { - for _, vars := range e.Macro { - if v, ok := vars[key]; ok { - return v, true - } - } - return nil, false -} - -func (e *Environment) SetMacro(key, value ilos.Instance) bool { - for _, vars := range e.Macro { - if _, ok := vars[key]; ok { - vars[key] = value - return true - } - } - return false -} - -func (e *Environment) DefineMacro(key, value ilos.Instance) { - e.Macro[0][key] = value -} - -func (e *Environment) GetDynamicVariable(key ilos.Instance) (ilos.Instance, bool) { - for _, vars := range e.DynamicVariable { - if v, ok := vars[key]; ok { - return v, true - } - } - return nil, false -} - -func (e *Environment) SetDynamicVariable(key, value ilos.Instance) bool { - for _, vars := range e.DynamicVariable { - if _, ok := vars[key]; ok { - vars[key] = value - return true - } - } - return false -} - -func (e *Environment) DefineDynamicVariable(key, value ilos.Instance) { - e.DynamicVariable[0][key] = value -} - // TopLevel is a global environment var TopLevel = New() diff --git a/runtime/environment/stack.go b/runtime/environment/stack.go new file mode 100644 index 0000000..f6b6764 --- /dev/null +++ b/runtime/environment/stack.go @@ -0,0 +1,34 @@ +package environment + +import ( + "github.com/ta2gch/iris/runtime/ilos" +) + +type stack []map[ilos.Instance]ilos.Instance + +func newStack() stack { + return []map[ilos.Instance]ilos.Instance{map[ilos.Instance]ilos.Instance{}} +} + +func (s stack) Get(key ilos.Instance) (ilos.Instance, bool) { + for i := len(s) - 1; i >= 0; i-- { + if v, ok := s[i][key]; ok { + return v, true + } + } + return nil, false +} + +func (s stack) Set(key, value ilos.Instance) bool { + for i := len(s) - 1; i >= 0; i-- { + if _, ok := s[i][key]; ok { + s[i][key] = value + return true + } + } + return false +} + +func (s stack) Define(key, value ilos.Instance) { + s[0][key] = value +} diff --git a/runtime/eval.go b/runtime/eval.go index b1a3bd1..045e2f6 100644 --- a/runtime/eval.go +++ b/runtime/eval.go @@ -54,10 +54,10 @@ func evalFunction(obj ilos.Instance, local *env.Environment, global *env.Environ if err != nil { return nil, err } - e := env.New() - env.AppendDynamicVariable(e, local) - env.AppendThrowTag(e, local) - ret, err := fun.(instance.Function)(args, e, global) + env := env.New() + env.DynamicVariable = append(local.DynamicVariable, env.DynamicVariable...) + env.ThrowTag = append(local.ThrowTag, env.ThrowTag...) + ret, err := fun.(instance.Function)(args, env, global) if err != nil { return nil, err } @@ -70,10 +70,10 @@ func evalFunction(obj ilos.Instance, local *env.Environment, global *env.Environ } // get macro instance has value of Function interface var mac ilos.Instance - if m, ok := local.GetMacro(car); ok { + if m, ok := local.Macro.Get(car); ok { mac = m } - if m, ok := global.GetMacro(car); ok { + if m, ok := global.Macro.Get(car); ok { mac = m } if mac != nil { @@ -85,10 +85,10 @@ func evalFunction(obj ilos.Instance, local *env.Environment, global *env.Environ } // get function instance has value of Function interface var fun ilos.Instance - if f, ok := local.GetFunction(car); ok { + if f, ok := local.Function.Get(car); ok { fun = f } - if f, ok := global.GetFunction(car); ok { + if f, ok := global.Function.Get(car); ok { fun = f } if fun != nil { @@ -96,10 +96,10 @@ func evalFunction(obj ilos.Instance, local *env.Environment, global *env.Environ if err != nil { return nil, err } - e := env.New() - env.AppendDynamicVariable(e, local) - env.AppendThrowTag(e, local) - ret, err := fun.(instance.Function)(args, e, global) + env := env.New() + env.DynamicVariable = append(local.DynamicVariable, env.DynamicVariable...) + env.ThrowTag = append(local.ThrowTag, env.ThrowTag...) + ret, err := fun.(instance.Function)(args, env, global) if err != nil { return nil, err } @@ -114,10 +114,10 @@ func Eval(obj ilos.Instance, local *env.Environment, global *env.Environment) (i return instance.NewNull(), nil } if ilos.InstanceOf(obj, class.Symbol) { - if val, ok := local.GetVariable(obj); ok { + if val, ok := local.Variable.Get(obj); ok { return val, nil } - if val, ok := global.GetVariable(obj); ok { + if val, ok := global.Variable.Get(obj); ok { return val, nil } return nil, instance.NewUndefinedEntityError(nil, nil) diff --git a/runtime/eval_test.go b/runtime/eval_test.go index 7730b0d..4851085 100644 --- a/runtime/eval_test.go +++ b/runtime/eval_test.go @@ -22,12 +22,12 @@ func TestEval(t *testing.T) { Init() local := env.New() global := env.TopLevel - local.DefineVariable(instance.NewSymbol("PI"), instance.NewFloat(3.14)) - local.DefineFunction(instance.NewSymbol("INC"), instance.NewFunction(func(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { + local.Variable.Define(instance.NewSymbol("PI"), instance.NewFloat(3.14)) + local.Function.Define(instance.NewSymbol("INC"), instance.NewFunction(func(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { car := instance.UnsafeCar(args) return instance.NewInteger(int(car.(instance.Integer)) + 1), nil })) - local.DefineMacro(instance.NewSymbol("MINC"), instance.NewFunction(func(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { + local.Macro.Define(instance.NewSymbol("MINC"), instance.NewFunction(func(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { ret, err := Eval(instance.NewCons(instance.NewSymbol("INC"), args), local, global) return ret, err })) diff --git a/runtime/function.go b/runtime/function.go index 9978d97..d76c128 100644 --- a/runtime/function.go +++ b/runtime/function.go @@ -17,10 +17,10 @@ func function(args ilos.Instance, local *env.Environment, global *env.Environmen if !ilos.InstanceOf(car, class.Symbol) { return nil, instance.NewDomainError(car, class.Symbol) } - if f, ok := local.GetFunction(car); ok { + if f, ok := local.Function.Get(car); ok { return f, nil } - if f, ok := global.GetFunction(car); ok { + if f, ok := global.Function.Get(car); ok { return f, nil } return nil, instance.NewUndefinedEntityError(nil, nil) diff --git a/runtime/lambda.go b/runtime/lambda.go index 71f64ea..419ae66 100644 --- a/runtime/lambda.go +++ b/runtime/lambda.go @@ -20,8 +20,11 @@ func lambda(args ilos.Instance, local *env.Environment, global *env.Environment) forms := instance.UnsafeCdr(args) // Checked at the top of this function. (EndOfListIsNil) lexical := local return instance.NewFunction(func(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { - env.AppendAll(local, lexical) - + local.ThrowTag = append(lexical.ThrowTag, local.ThrowTag...) + local.Variable = append(lexical.Variable, local.Variable...) + local.Function = append(lexical.Function, local.Function...) + local.Macro = append(lexical.Macro, local.Macro...) + local.DynamicVariable = append(lexical.DynamicVariable, local.DynamicVariable...) // args must be a instance of list and end with nil if !ilos.InstanceOf(args, class.List) || !UnsafeEndOfListIsNil(args) { // Checked at the head of test return nil, instance.NewParseError(args, class.List) @@ -61,10 +64,10 @@ func lambda(args ilos.Instance, local *env.Environment, global *env.Environment) value := instance.UnsafeCar(aargs) // Checked at the top of this loop. if key == instance.NewSymbol(":REST") || key == instance.NewSymbol("&REST") { cadr := instance.UnsafeCar(instance.UnsafeCdr(fargs)) // Checked before type checking secion - local.DefineVariable(cadr, aargs) + local.Variable.Define(cadr, aargs) break } - local.DefineVariable(key, value) + local.Variable.Define(key, value) fargs = instance.UnsafeCdr(fargs) // Checked at the top of this loop aargs = instance.UnsafeCdr(aargs) // Checked at the top of this loop } diff --git a/runtime/runtime.go b/runtime/runtime.go index 745b125..c777d55 100644 --- a/runtime/runtime.go +++ b/runtime/runtime.go @@ -6,8 +6,8 @@ import ( ) func Init() { - e.TopLevel.DefineMacro(i.NewSymbol("LAMBDA"), i.NewFunction(lambda)) - e.TopLevel.DefineMacro(i.NewSymbol("QUOTE"), i.NewFunction(quote)) - e.TopLevel.DefineFunction(i.NewSymbol("THROW"), i.NewFunction(throw)) - e.TopLevel.DefineMacro(i.NewSymbol("CATCH"), i.NewFunction(catch)) + e.TopLevel.Macro.Define(i.NewSymbol("LAMBDA"), i.NewFunction(lambda)) + e.TopLevel.Macro.Define(i.NewSymbol("QUOTE"), i.NewFunction(quote)) + e.TopLevel.Function.Define(i.NewSymbol("THROW"), i.NewFunction(throw)) + e.TopLevel.Macro.Define(i.NewSymbol("CATCH"), i.NewFunction(catch)) } diff --git a/runtime/throw.go b/runtime/throw.go index c042eec..ca56060 100644 --- a/runtime/throw.go +++ b/runtime/throw.go @@ -13,7 +13,7 @@ func throw(args ilos.Instance, local *env.Environment, global *env.Environment) return nil, instance.NewParseError(args, class.Cons) } car := instance.UnsafeCar(args) // Checked at the top of this function - if _, ok := local.GetThrowTag(car); !ok { + if _, ok := local.ThrowTag.Get(car); !ok { return nil, instance.NewSimpleError(instance.NewString("%v is not defined as the tag"), car) } cadr := instance.UnsafeCar(instance.UnsafeCdr(args)) // Checked length is 2 at the top of this function From f46083b5bbb82d6680a88b9caac63aadc5636cbb Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Fri, 4 Aug 2017 11:26:17 +0900 Subject: [PATCH 091/228] Change the order of error --- runtime/runtime.go | 2 +- runtime/throw.go | 14 +++++++++++--- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/runtime/runtime.go b/runtime/runtime.go index c777d55..a4cb1db 100644 --- a/runtime/runtime.go +++ b/runtime/runtime.go @@ -8,6 +8,6 @@ import ( func Init() { e.TopLevel.Macro.Define(i.NewSymbol("LAMBDA"), i.NewFunction(lambda)) e.TopLevel.Macro.Define(i.NewSymbol("QUOTE"), i.NewFunction(quote)) - e.TopLevel.Function.Define(i.NewSymbol("THROW"), i.NewFunction(throw)) + e.TopLevel.Macro.Define(i.NewSymbol("THROW"), i.NewFunction(throw)) e.TopLevel.Macro.Define(i.NewSymbol("CATCH"), i.NewFunction(catch)) } diff --git a/runtime/throw.go b/runtime/throw.go index ca56060..ba5b2a2 100644 --- a/runtime/throw.go +++ b/runtime/throw.go @@ -13,9 +13,17 @@ func throw(args ilos.Instance, local *env.Environment, global *env.Environment) return nil, instance.NewParseError(args, class.Cons) } car := instance.UnsafeCar(args) // Checked at the top of this function - if _, ok := local.ThrowTag.Get(car); !ok { - return nil, instance.NewSimpleError(instance.NewString("%v is not defined as the tag"), car) + tag, err := Eval(car, local, global) + if err != nil { + return nil, err } cadr := instance.UnsafeCar(instance.UnsafeCdr(args)) // Checked length is 2 at the top of this function - return nil, instance.NewThrow(car, cadr) + object, err := Eval(cadr, local, global) + if err != nil { + return nil, err + } + if _, ok := local.ThrowTag.Get(tag); !ok { + return nil, instance.NewSimpleError(instance.NewString("%v is not defined as the tag"), car) + } + return nil, instance.NewThrow(tag, object) } From 46b03ceee9d0c4a347705e05874a4f598c939944 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Fri, 4 Aug 2017 13:09:12 +0900 Subject: [PATCH 092/228] added wrong number of arguments error --- runtime/catch.go | 2 +- runtime/eval.go | 4 +-- runtime/function.go | 2 +- runtime/ilos/class/class.go | 7 ++++- runtime/ilos/instance/extension.go | 50 ++++++++++++++++++++++++++++++ runtime/ilos/instance/throw.go | 15 --------- runtime/lambda.go | 9 +++--- runtime/quote.go | 2 +- runtime/throw.go | 2 +- 9 files changed, 67 insertions(+), 26 deletions(-) create mode 100644 runtime/ilos/instance/extension.go delete mode 100644 runtime/ilos/instance/throw.go diff --git a/runtime/catch.go b/runtime/catch.go index a022a30..9472074 100644 --- a/runtime/catch.go +++ b/runtime/catch.go @@ -10,7 +10,7 @@ import ( func catch(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { // args must be a instance of Cons, not Null, and ends with nil if !ilos.InstanceOf(args, class.Cons) || !UnsafeEndOfListIsNil(args) || UnsafeListLength(args) < 2 { // Checked at the head of test - return nil, instance.NewParseError(args, class.Cons) + return nil, instance.NewWrongNumberOfArguments(instance.NewSymbol("SYMBOL"), args) } car, err := Eval(instance.UnsafeCar(args), local, global) // Checked at the top of this function if err != nil { diff --git a/runtime/eval.go b/runtime/eval.go index 045e2f6..396a18f 100644 --- a/runtime/eval.go +++ b/runtime/eval.go @@ -105,7 +105,7 @@ func evalFunction(obj ilos.Instance, local *env.Environment, global *env.Environ } return ret, nil } - return nil, instance.NewUndefinedEntityError(nil, nil) + return nil, instance.NewUndefinedFunction(car) } // Eval evaluates any classs @@ -120,7 +120,7 @@ func Eval(obj ilos.Instance, local *env.Environment, global *env.Environment) (i if val, ok := global.Variable.Get(obj); ok { return val, nil } - return nil, instance.NewUndefinedEntityError(nil, nil) + return nil, instance.NewUndefinedVariable(obj) } if ilos.InstanceOf(obj, class.Cons) { ret, err := evalFunction(obj, local, global) diff --git a/runtime/function.go b/runtime/function.go index d76c128..363e17a 100644 --- a/runtime/function.go +++ b/runtime/function.go @@ -10,7 +10,7 @@ import ( func function(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { // args must be a instance of Cons, not Null, and ends with nil if !ilos.InstanceOf(args, class.Cons) || !UnsafeEndOfListIsNil(args) || UnsafeListLength(args) != 1 { // Checked at the head of test - return nil, instance.NewParseError(args, class.Cons) + return nil, instance.NewWrongNumberOfArguments(instance.NewSymbol("FUNCTION"), args) } car := instance.UnsafeCar(args) // Checked at the top of this function // car must be a symbol diff --git a/runtime/ilos/class/class.go b/runtime/ilos/class/class.go index b8425a1..d1cdcd8 100644 --- a/runtime/ilos/class/class.go +++ b/runtime/ilos/class/class.go @@ -66,4 +66,9 @@ var EndOfStream = &builtinclass{[]ilos.Class{StreamError}, ""} var StorageExhausted = &builtinclass{[]ilos.Class{SeriousCondition}, ""} var StandardObject = &builtinclass{[]ilos.Class{Object}, ""} var Stream = &builtinclass{[]ilos.Class{Object}, ""} -var Throw = &builtinclass{[]ilos.Class{Object}, ""} + +// Implementation defined +var WrongNumberOfArguments = &builtinclass{[]ilos.Class{Error}, ""} +var Escape = &builtinclass{[]ilos.Class{Object}, ""} +var Throw = &builtinclass{[]ilos.Class{Escape}, ""} +var TagBodyTag = &builtinclass{[]ilos.Class{Escape}, ""} diff --git a/runtime/ilos/instance/extension.go b/runtime/ilos/instance/extension.go new file mode 100644 index 0000000..28c3a3b --- /dev/null +++ b/runtime/ilos/instance/extension.go @@ -0,0 +1,50 @@ +package instance + +import ( + "github.com/ta2gch/iris/runtime/ilos" + "github.com/ta2gch/iris/runtime/ilos/class" +) + +func NewThrow(tag, object ilos.Instance) ilos.Instance { + i := new(instance) + i.class = class.Throw + i.slots = map[ilos.Instance]ilos.Instance{} + i.slots[NewSymbol("TAG")] = tag + i.slots[NewSymbol("OBJECT")] = object + return i +} + +func NewTagBodyTag(tag ilos.Instance) ilos.Instance { + i := new(instance) + i.class = class.TagBodyTag + i.slots = map[ilos.Instance]ilos.Instance{} + i.slots[NewSymbol("TAG")] = tag + return i +} + +func NewWrongNumberOfArguments(function, arguments ilos.Instance) ilos.Instance { + i := new(instance) + i.class = class.WrongNumberOfArguments + i.slots = map[ilos.Instance]ilos.Instance{} + i.slots[NewSymbol("FORM")] = function + i.slots[NewSymbol("ARGUMENTS")] = arguments + return i +} + +func NewUndefinedFunction(name ilos.Instance) ilos.Instance { + i := new(instance) + i.class = class.UndefinedFunction + i.slots = map[ilos.Instance]ilos.Instance{} + i.slots[NewSymbol("NAME")] = name + i.slots[NewSymbol("NAMESPACE")] = NewSymbol("FUNCTION") + return i +} + +func NewUndefinedVariable(name ilos.Instance) ilos.Instance { + i := new(instance) + i.class = class.UndefinedVariable + i.slots = map[ilos.Instance]ilos.Instance{} + i.slots[NewSymbol("NAME")] = name + i.slots[NewSymbol("NAMESPACE")] = NewSymbol("VARIABLE") + return i +} diff --git a/runtime/ilos/instance/throw.go b/runtime/ilos/instance/throw.go deleted file mode 100644 index ed76bfa..0000000 --- a/runtime/ilos/instance/throw.go +++ /dev/null @@ -1,15 +0,0 @@ -package instance - -import ( - "github.com/ta2gch/iris/runtime/ilos" - "github.com/ta2gch/iris/runtime/ilos/class" -) - -func NewThrow(operation, operands ilos.Instance) ilos.Instance { - i := new(instance) - i.class = class.Throw - i.slots = map[ilos.Instance]ilos.Instance{} - i.slots[NewSymbol("TAG")] = operation - i.slots[NewSymbol("OBJECT")] = operands - return i -} diff --git a/runtime/lambda.go b/runtime/lambda.go index 419ae66..263fa6c 100644 --- a/runtime/lambda.go +++ b/runtime/lambda.go @@ -10,7 +10,7 @@ import ( func lambda(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { // args must be a instance of Cons, not Null, and ends with nil if !ilos.InstanceOf(args, class.Cons) || !UnsafeEndOfListIsNil(args) { // Checked at the head of test - return nil, instance.NewParseError(args, class.Cons) + return nil, instance.NewWrongNumberOfArguments(instance.NewSymbol("LAMBDA"), args) } lambdaList := instance.UnsafeCar(args) // lambda-list must be a instance of list and ends with nil @@ -20,6 +20,7 @@ func lambda(args ilos.Instance, local *env.Environment, global *env.Environment) forms := instance.UnsafeCdr(args) // Checked at the top of this function. (EndOfListIsNil) lexical := local return instance.NewFunction(func(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { + local.TagBodyTag = append(lexical.TagBodyTag, local.TagBodyTag...) local.ThrowTag = append(lexical.ThrowTag, local.ThrowTag...) local.Variable = append(lexical.Variable, local.Variable...) local.Function = append(lexical.Function, local.Function...) @@ -44,10 +45,10 @@ func lambda(args ilos.Instance, local *env.Environment, global *env.Environment) ok = true break } else { - return nil, instance.NewParseError(args, class.List) + return nil, instance.NewWrongNumberOfArguments(instance.NewSymbol("ANONYMOUS-FUNCTION"), args) } } else { - return nil, instance.NewParseError(lambdaList, class.List) + return nil, instance.NewWrongNumberOfArguments(instance.NewSymbol("LAMBDA"), lambdaList) } } } @@ -55,7 +56,7 @@ func lambda(args ilos.Instance, local *env.Environment, global *env.Environment) // aargs is a instance of list and ends nil becauseof the checking at this function. // lambda-list is a instance of list and ends nil becauseof the checking at the function, lambda. if !ok && UnsafeListLength(lambdaList) != UnsafeListLength(args) { - return nil, instance.NewParseError(args, class.List) + return nil, instance.NewWrongNumberOfArguments(instance.NewSymbol("ANONYMOUS-FUNCTION"), args) } fargs := lambdaList aargs := args diff --git a/runtime/quote.go b/runtime/quote.go index de0d5a1..2a82c9b 100644 --- a/runtime/quote.go +++ b/runtime/quote.go @@ -10,7 +10,7 @@ import ( func quote(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { // args must be a instance of Cons, not Null, and ends with nil if !ilos.InstanceOf(args, class.Cons) || !UnsafeEndOfListIsNil(args) || UnsafeListLength(args) != 1 { // Checked at the head of test - return nil, instance.NewParseError(args, class.Cons) + return nil, instance.NewWrongNumberOfArguments(instance.NewSymbol("QUOTE"), args) } return instance.UnsafeCar(args), nil } diff --git a/runtime/throw.go b/runtime/throw.go index ba5b2a2..9fabf64 100644 --- a/runtime/throw.go +++ b/runtime/throw.go @@ -10,7 +10,7 @@ import ( func throw(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { // args must be a instance of Cons, not Null, and ends with nil if !ilos.InstanceOf(args, class.Cons) || !UnsafeEndOfListIsNil(args) || UnsafeListLength(args) != 2 { // Checked at the head of test - return nil, instance.NewParseError(args, class.Cons) + return nil, instance.NewWrongNumberOfArguments(instance.NewSymbol("THROW"), args) } car := instance.UnsafeCar(args) // Checked at the top of this function tag, err := Eval(car, local, global) From 2355fb1d12217642d57976c6f4a758453cabd769 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Fri, 4 Aug 2017 14:38:27 +0900 Subject: [PATCH 093/228] Added tagbody & go --- runtime/environment/environment.go | 2 ++ runtime/eval_test.go | 8 ++++- runtime/go.go | 20 +++++++++++ runtime/runtime.go | 2 ++ runtime/tagbody.go | 53 ++++++++++++++++++++++++++++++ 5 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 runtime/go.go create mode 100644 runtime/tagbody.go diff --git a/runtime/environment/environment.go b/runtime/environment/environment.go index 3187acf..45b43e9 100644 --- a/runtime/environment/environment.go +++ b/runtime/environment/environment.go @@ -2,6 +2,7 @@ package environment // Environment struct is the struct for keeping functions and variables type Environment struct { + TagBodyTag stack ThrowTag stack Macro stack Function stack @@ -12,6 +13,7 @@ type Environment struct { // New creates new environment func New() *Environment { env := new(Environment) + env.TagBodyTag = newStack() env.ThrowTag = newStack() env.Macro = newStack() env.Function = newStack() diff --git a/runtime/eval_test.go b/runtime/eval_test.go index 4851085..fa97716 100644 --- a/runtime/eval_test.go +++ b/runtime/eval_test.go @@ -73,11 +73,17 @@ func TestEval(t *testing.T) { wantErr: false, }, { - name: "throw", + name: "catch & throw", args: args{read("(catch 'foo 1 (throw 'foo 1))"), local, global}, want: read("1"), wantErr: false, }, + { + name: "tagbody & go", + args: args{read("(catch 'foo (tagbody (go bar) (throw 'foo 1) bar))"), local, global}, + want: instance.NewNull(), + wantErr: false, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/runtime/go.go b/runtime/go.go new file mode 100644 index 0000000..1ff0f8f --- /dev/null +++ b/runtime/go.go @@ -0,0 +1,20 @@ +package runtime + +import ( + env "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/ilos" + "github.com/ta2gch/iris/runtime/ilos/class" + "github.com/ta2gch/iris/runtime/ilos/instance" +) + +func tagbodyGo(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { + // args must be a instance of Cons, not Null, and ends with nil + if !ilos.InstanceOf(args, class.Cons) || !UnsafeEndOfListIsNil(args) || UnsafeListLength(args) != 1 { // Checked at the head of test + return nil, instance.NewWrongNumberOfArguments(instance.NewSymbol("GO"), args) + } + car := instance.UnsafeCar(args) // Checked at the top of this function + if _, ok := local.TagBodyTag.Get(car); !ok { + return nil, instance.NewSimpleError(instance.NewString("%v is not defined as the tag"), car) + } + return nil, instance.NewTagBodyTag(car) +} diff --git a/runtime/runtime.go b/runtime/runtime.go index a4cb1db..181829f 100644 --- a/runtime/runtime.go +++ b/runtime/runtime.go @@ -10,4 +10,6 @@ func Init() { e.TopLevel.Macro.Define(i.NewSymbol("QUOTE"), i.NewFunction(quote)) e.TopLevel.Macro.Define(i.NewSymbol("THROW"), i.NewFunction(throw)) e.TopLevel.Macro.Define(i.NewSymbol("CATCH"), i.NewFunction(catch)) + e.TopLevel.Macro.Define(i.NewSymbol("TAGBODY"), i.NewFunction(tagbody)) + e.TopLevel.Macro.Define(i.NewSymbol("GO"), i.NewFunction(tagbodyGo)) } diff --git a/runtime/tagbody.go b/runtime/tagbody.go new file mode 100644 index 0000000..2c69b06 --- /dev/null +++ b/runtime/tagbody.go @@ -0,0 +1,53 @@ +package runtime + +import ( + env "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/ilos" + "github.com/ta2gch/iris/runtime/ilos/class" + "github.com/ta2gch/iris/runtime/ilos/instance" +) + +func tagbody(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { + // args must be a instance of Cons, not Null, and ends with nil + if !ilos.InstanceOf(args, class.Cons) || !UnsafeEndOfListIsNil(args) || UnsafeListLength(args) < 2 { // Checked at the head of test + return nil, instance.NewWrongNumberOfArguments(instance.NewSymbol("TAGBODY"), args) + } + cdr := args // Checked at the top of this function + for ilos.InstanceOf(cdr, class.Cons) { + cadr := instance.UnsafeCar(cdr) // Checked at the top of this loop + cddr := instance.UnsafeCdr(cdr) // Checked at the top of this loop + if !ilos.InstanceOf(cadr, class.Cons) { + local.TagBodyTag.Define(cadr, cddr) + } + cdr = cddr + } + cdr = args + for ilos.InstanceOf(cdr, class.Cons) { + cadr := instance.UnsafeCar(cdr) // Checked at the top of this loop + cddr := instance.UnsafeCdr(cdr) // Checked at the top of this loop + if ilos.InstanceOf(cadr, class.Cons) { + _, fail := Eval(cadr, local, global) + if fail != nil { + tag: + if ilos.InstanceOf(fail, class.TagBodyTag) { + tag, _ := fail.GetSlotValue(instance.NewSymbol("TAG")) + forms, _ := local.TagBodyTag.Get(tag) + cdddr := forms + for ilos.InstanceOf(cdddr, class.Cons) { + cadddr := instance.UnsafeCar(cdddr) // Checked at the top of this loop + cddddr := instance.UnsafeCdr(cdddr) // Checked at the top of this loop + _, fail = Eval(cadddr, local, global) + if fail != nil { + goto tag + } + cdddr = cddddr + } + break + } + return nil, fail + } + } + cdr = cddr + } + return instance.NewNull(), nil +} From cabb1b24160fdd0c627bf0323247afa46c03a135 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Fri, 4 Aug 2017 14:59:39 +0900 Subject: [PATCH 094/228] Nested tagbody --- runtime/eval_test.go | 6 ++++++ runtime/tagbody.go | 36 +++++++++++++++++++++++++----------- 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/runtime/eval_test.go b/runtime/eval_test.go index fa97716..096bf20 100644 --- a/runtime/eval_test.go +++ b/runtime/eval_test.go @@ -84,6 +84,12 @@ func TestEval(t *testing.T) { want: instance.NewNull(), wantErr: false, }, + { + name: "nested tagbody & go", + args: args{read("(catch 'foo (tagbody (tagbody (go bar) (throw 'foo 1) bar (go foobar)) foobar))"), local, global}, + want: instance.NewNull(), + wantErr: false, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/runtime/tagbody.go b/runtime/tagbody.go index 2c69b06..749abed 100644 --- a/runtime/tagbody.go +++ b/runtime/tagbody.go @@ -12,12 +12,14 @@ func tagbody(args ilos.Instance, local *env.Environment, global *env.Environment if !ilos.InstanceOf(args, class.Cons) || !UnsafeEndOfListIsNil(args) || UnsafeListLength(args) < 2 { // Checked at the head of test return nil, instance.NewWrongNumberOfArguments(instance.NewSymbol("TAGBODY"), args) } + localTags := []ilos.Instance{} cdr := args // Checked at the top of this function for ilos.InstanceOf(cdr, class.Cons) { cadr := instance.UnsafeCar(cdr) // Checked at the top of this loop cddr := instance.UnsafeCdr(cdr) // Checked at the top of this loop if !ilos.InstanceOf(cadr, class.Cons) { local.TagBodyTag.Define(cadr, cddr) + localTags = append(localTags, cadr) } cdr = cddr } @@ -30,19 +32,31 @@ func tagbody(args ilos.Instance, local *env.Environment, global *env.Environment if fail != nil { tag: if ilos.InstanceOf(fail, class.TagBodyTag) { - tag, _ := fail.GetSlotValue(instance.NewSymbol("TAG")) - forms, _ := local.TagBodyTag.Get(tag) - cdddr := forms - for ilos.InstanceOf(cdddr, class.Cons) { - cadddr := instance.UnsafeCar(cdddr) // Checked at the top of this loop - cddddr := instance.UnsafeCdr(cdddr) // Checked at the top of this loop - _, fail = Eval(cadddr, local, global) - if fail != nil { - goto tag + tag, _ := fail.GetSlotValue(instance.NewSymbol("TAG")) // Checked at the top of this loop + found := false + for _, localTag := range localTags { + if tag == localTag { + found = true + break } - cdddr = cddddr } - break + if found { + forms, _ := local.TagBodyTag.Get(tag) // Checked in the function, tagbodyGo + cdddr := forms + for ilos.InstanceOf(cdddr, class.Cons) { + cadddr := instance.UnsafeCar(cdddr) // Checked at the top of this loop + cddddr := instance.UnsafeCdr(cdddr) // Checked at the top of this loop + if ilos.InstanceOf(cadddr, class.Cons) { + _, fail = Eval(cadddr, local, global) + if fail != nil { + goto tag + } + } + cdddr = cddddr + } + break + } + } return nil, fail } From ec0df82f0d3f51462dc0596dc96b9a36c0380453 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Fri, 4 Aug 2017 15:10:01 +0900 Subject: [PATCH 095/228] Added function --- runtime/eval_test.go | 7 ++++--- runtime/function.go | 2 +- runtime/runtime.go | 1 + 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/runtime/eval_test.go b/runtime/eval_test.go index 096bf20..4ff2ac5 100644 --- a/runtime/eval_test.go +++ b/runtime/eval_test.go @@ -22,11 +22,12 @@ func TestEval(t *testing.T) { Init() local := env.New() global := env.TopLevel - local.Variable.Define(instance.NewSymbol("PI"), instance.NewFloat(3.14)) - local.Function.Define(instance.NewSymbol("INC"), instance.NewFunction(func(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { + inc := func(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { car := instance.UnsafeCar(args) return instance.NewInteger(int(car.(instance.Integer)) + 1), nil - })) + } + local.Variable.Define(instance.NewSymbol("PI"), instance.NewFloat(3.14)) + local.Function.Define(instance.NewSymbol("INC"), instance.NewFunction(inc)) local.Macro.Define(instance.NewSymbol("MINC"), instance.NewFunction(func(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { ret, err := Eval(instance.NewCons(instance.NewSymbol("INC"), args), local, global) return ret, err diff --git a/runtime/function.go b/runtime/function.go index 363e17a..3f20f60 100644 --- a/runtime/function.go +++ b/runtime/function.go @@ -23,5 +23,5 @@ func function(args ilos.Instance, local *env.Environment, global *env.Environmen if f, ok := global.Function.Get(car); ok { return f, nil } - return nil, instance.NewUndefinedEntityError(nil, nil) + return nil, instance.NewUndefinedFunction(car) } diff --git a/runtime/runtime.go b/runtime/runtime.go index 181829f..a150b71 100644 --- a/runtime/runtime.go +++ b/runtime/runtime.go @@ -12,4 +12,5 @@ func Init() { e.TopLevel.Macro.Define(i.NewSymbol("CATCH"), i.NewFunction(catch)) e.TopLevel.Macro.Define(i.NewSymbol("TAGBODY"), i.NewFunction(tagbody)) e.TopLevel.Macro.Define(i.NewSymbol("GO"), i.NewFunction(tagbodyGo)) + e.TopLevel.Macro.Define(i.NewSymbol("FUNCTION"), i.NewFunction(function)) } From b1544933e242cea7845209491d2eb5c8190e2a59 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Fri, 4 Aug 2017 15:11:35 +0900 Subject: [PATCH 096/228] Added reader macro for function --- reader/parser/parser.go | 4 +++- reader/tokenizer/tokenizer.go | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/reader/parser/parser.go b/reader/parser/parser.go index 21b898b..76f68a9 100644 --- a/reader/parser/parser.go +++ b/reader/parser/parser.go @@ -108,6 +108,8 @@ func parseMacro(tok string, t *tokenizer.Tokenizer) (ilos.Instance, ilos.Instanc return instance.NewCons(s, instance.NewCons(d, instance.NewCons(cdr, instance.NewNull()))), nil } switch tok { + case "#'": + n = "FUNCTION" case ",@": n = "commaat" case ",": @@ -164,7 +166,7 @@ func Parse(t *tokenizer.Tokenizer) (ilos.Instance, ilos.Instance) { if tok == "." { return nil, bod } - if mat, _ := regexp.MatchString("^(?:,@?|'|`|#[[:digit:]]*[aA])$", tok); mat { + if mat, _ := regexp.MatchString("^(?:#'|,@?|'|`|#[[:digit:]]*[aA])$", tok); mat { m, err := parseMacro(tok, t) if err != nil { return nil, err diff --git a/reader/tokenizer/tokenizer.go b/reader/tokenizer/tokenizer.go index 1c2c3f3..912e606 100644 --- a/reader/tokenizer/tokenizer.go +++ b/reader/tokenizer/tokenizer.go @@ -34,7 +34,7 @@ func New(r io.Reader) *Tokenizer { str += "\\|.*\\||" str += "[<>/*=?_!$%[\\]^{}~a-zA-Z][<>/*=?_!$%[\\]^{}~0-9a-zA-Z]*|" str += "[.()]|" - str += ",@?|'|`|#[[:digit:]]*[aA]" + str += "#'|,@?|'|`|#[[:digit:]]*[aA]" re = regexp.MustCompile(str) sc := bufio.NewScanner(r) sc.Split(splitter) From e8707528e4d7fac13a3efbfadfe4f668d338b2e7 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Fri, 4 Aug 2017 15:53:38 +0900 Subject: [PATCH 097/228] domain-error for thor & catch --- runtime/catch.go | 3 +++ runtime/throw.go | 3 +++ 2 files changed, 6 insertions(+) diff --git a/runtime/catch.go b/runtime/catch.go index 9472074..e75e952 100644 --- a/runtime/catch.go +++ b/runtime/catch.go @@ -16,6 +16,9 @@ func catch(args ilos.Instance, local *env.Environment, global *env.Environment) if err != nil { return nil, err } + if ilos.InstanceOf(car, class.Number) || ilos.InstanceOf(car, class.Character) { + return nil, instance.NewDomainError(car, class.Object) + } local.ThrowTag.Define(car, car) cdr := instance.UnsafeCdr(args) // Checked at the top of this function var sucess, fail ilos.Instance diff --git a/runtime/throw.go b/runtime/throw.go index 9fabf64..b0f4a23 100644 --- a/runtime/throw.go +++ b/runtime/throw.go @@ -17,6 +17,9 @@ func throw(args ilos.Instance, local *env.Environment, global *env.Environment) if err != nil { return nil, err } + if ilos.InstanceOf(tag, class.Number) || ilos.InstanceOf(tag, class.Character) { + return nil, instance.NewDomainError(tag, class.Object) + } cadr := instance.UnsafeCar(instance.UnsafeCdr(args)) // Checked length is 2 at the top of this function object, err := Eval(cadr, local, global) if err != nil { From b7d9c7ae1b8bebb09c2d3c46352840c95b16aa22 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Fri, 4 Aug 2017 16:03:26 +0900 Subject: [PATCH 098/228] Change LICENSE --- LICENSE | 1047 ++++++++++++++++++++----------------------------------- 1 file changed, 373 insertions(+), 674 deletions(-) diff --git a/LICENSE b/LICENSE index 9cecc1d..fa0086a 100644 --- a/LICENSE +++ b/LICENSE @@ -1,674 +1,373 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - {one line to give the program's name and a brief idea of what it does.} - Copyright (C) {year} {name of author} - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - {project} Copyright (C) {year} {fullname} - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. \ No newline at end of file From 9349d801f3cd7847734efb25526610bb551176c3 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Fri, 4 Aug 2017 16:20:13 +0900 Subject: [PATCH 099/228] Added README --- README.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/README.md b/README.md index 9b2ebd2..4183997 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,29 @@ # iris +Iris is a interpreter of ISLisp implemented golang + +[![Build Status](https://travis-ci.org/ta2gch/iris.svg?branch=master)](https://travis-ci.org/ta2gch/iris) + + +## Introduction + +ISLisp is a member of LISP family and standardized by ISO in 2007. +As you know, Common Lisp is standardized by ANSI in 1994. +Iris is a interpreter of ISLisp implemented with golang. + +## Development + +### Test + +Iris is tested on TravisCI with this command. + +``` +$ go test ./... +``` + +## License +This software is licensed under the Mozilla Public License v2.0 + +## Copyright +Copyright (c) 2017 TANIGUCHI Masaya \ No newline at end of file From eb6331a3b0081f02cc64c095d128de7007e8488d Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Fri, 4 Aug 2017 16:30:05 +0900 Subject: [PATCH 100/228] Updated README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4183997..189cef5 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # iris -Iris is a interpreter of ISLisp implemented golang +Iris is a interpreter of ISLisp implemented with golang [![Build Status](https://travis-ci.org/ta2gch/iris.svg?branch=master)](https://travis-ci.org/ta2gch/iris) From 5622d178571e086a876f9f176922078307e7bbdc Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Fri, 4 Aug 2017 21:50:27 +0900 Subject: [PATCH 101/228] Added block & return-from --- reader/parser/parser.go | 2 +- reader/tokenizer/tokenizer.go | 2 +- runtime/block.go | 42 ++++++++++++++++++++++++++++++ runtime/environment/environment.go | 2 ++ runtime/eval_test.go | 6 +++++ runtime/ilos/class/class.go | 1 + runtime/ilos/instance/extension.go | 9 +++++++ runtime/lambda.go | 1 + runtime/return-from.go | 32 +++++++++++++++++++++++ runtime/runtime.go | 2 ++ 10 files changed, 97 insertions(+), 2 deletions(-) create mode 100644 runtime/block.go create mode 100644 runtime/return-from.go diff --git a/reader/parser/parser.go b/reader/parser/parser.go index 76f68a9..c48a9b4 100644 --- a/reader/parser/parser.go +++ b/reader/parser/parser.go @@ -81,7 +81,7 @@ func parseAtom(tok string) (ilos.Instance, ilos.Instance) { if m, _ := regexp.MatchString("^\\|.*\\|$", tok); m { return instance.NewSymbol(tok), nil } - if m, _ := regexp.MatchString("^[<>/*=?_!$%[\\]^{}~a-zA-Z][<>/*=?_!$%[\\]^{}~0-9a-zA-Z]*$", tok); m { + if m, _ := regexp.MatchString("^[<>/*=?_!$%[\\]^{}~a-zA-Z-][<>/*=?_!$%[\\]^{}~0-9a-zA-Z-]*$", tok); m { return instance.NewSymbol(strings.ToUpper(tok)), nil } return nil, instance.NewParseError(instance.NewString(tok), class.Object) diff --git a/reader/tokenizer/tokenizer.go b/reader/tokenizer/tokenizer.go index 912e606..a2f80b3 100644 --- a/reader/tokenizer/tokenizer.go +++ b/reader/tokenizer/tokenizer.go @@ -32,7 +32,7 @@ func New(r io.Reader) *Tokenizer { str += "\".*\"|" str += ":[<>/*=?_!$%[\\]^{}~0-9a-zA-Z]+|" str += "\\|.*\\||" - str += "[<>/*=?_!$%[\\]^{}~a-zA-Z][<>/*=?_!$%[\\]^{}~0-9a-zA-Z]*|" + str += "[<>/*=?_!$%[\\]^{}~a-zA-Z-][<>/*=?_!$%[\\]^{}~0-9a-zA-Z-]*|" str += "[.()]|" str += "#'|,@?|'|`|#[[:digit:]]*[aA]" re = regexp.MustCompile(str) diff --git a/runtime/block.go b/runtime/block.go new file mode 100644 index 0000000..6ce2a8b --- /dev/null +++ b/runtime/block.go @@ -0,0 +1,42 @@ +package runtime + +import ( + env "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/ilos" + "github.com/ta2gch/iris/runtime/ilos/class" + "github.com/ta2gch/iris/runtime/ilos/instance" +) + +func block(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { + // args must be a instance of Cons, not Null, and ends with nil + if !ilos.InstanceOf(args, class.Cons) || !UnsafeEndOfListIsNil(args) || UnsafeListLength(args) < 2 { // Checked at the head of test + return nil, instance.NewWrongNumberOfArguments(instance.NewSymbol("BLOCK"), args) + } + car, err := Eval(instance.UnsafeCar(args), local, global) // Checked at the top of this function + if err != nil { + return nil, err + } + if ilos.InstanceOf(car, class.Number) || ilos.InstanceOf(car, class.Character) { + return nil, instance.NewDomainError(car, class.Object) + } + local.BlockTag.Define(car, car) + cdr := instance.UnsafeCdr(args) // Checked at the top of this function + var sucess, fail ilos.Instance + for ilos.InstanceOf(cdr, class.Cons) { + cadr := instance.UnsafeCar(cdr) // Checked at the top of this loop + cddr := instance.UnsafeCdr(cdr) // Checked at the top of this loop + sucess, fail = Eval(cadr, local, global) + if fail != nil { + if ilos.InstanceOf(fail, class.BlockTag) { + tag, _ := fail.GetSlotValue(instance.NewSymbol("TAG")) // Checked at the head of this condition + if car == tag { + obj, _ := fail.GetSlotValue(instance.NewSymbol("OBJECT")) // Checked at the head of this condition + return obj, nil + } + } + return nil, fail + } + cdr = cddr + } + return sucess, nil +} diff --git a/runtime/environment/environment.go b/runtime/environment/environment.go index 45b43e9..b347582 100644 --- a/runtime/environment/environment.go +++ b/runtime/environment/environment.go @@ -2,6 +2,7 @@ package environment // Environment struct is the struct for keeping functions and variables type Environment struct { + BlockTag stack TagBodyTag stack ThrowTag stack Macro stack @@ -13,6 +14,7 @@ type Environment struct { // New creates new environment func New() *Environment { env := new(Environment) + env.BlockTag = newStack() env.TagBodyTag = newStack() env.ThrowTag = newStack() env.Macro = newStack() diff --git a/runtime/eval_test.go b/runtime/eval_test.go index 4ff2ac5..4a7f632 100644 --- a/runtime/eval_test.go +++ b/runtime/eval_test.go @@ -79,6 +79,12 @@ func TestEval(t *testing.T) { want: read("1"), wantErr: false, }, + { + name: "block & return-from", + args: args{read("(block 'foo 1 (return-from'foo 1))"), local, global}, + want: read("1"), + wantErr: false, + }, { name: "tagbody & go", args: args{read("(catch 'foo (tagbody (go bar) (throw 'foo 1) bar))"), local, global}, diff --git a/runtime/ilos/class/class.go b/runtime/ilos/class/class.go index d1cdcd8..2c6f476 100644 --- a/runtime/ilos/class/class.go +++ b/runtime/ilos/class/class.go @@ -72,3 +72,4 @@ var WrongNumberOfArguments = &builtinclass{[]ilos.Class{Error}, ""} var Throw = &builtinclass{[]ilos.Class{Escape}, ""} var TagBodyTag = &builtinclass{[]ilos.Class{Escape}, ""} +var BlockTag = &builtinclass{[]ilos.Class{Escape}, ""} diff --git a/runtime/ilos/instance/extension.go b/runtime/ilos/instance/extension.go index 28c3a3b..b43f172 100644 --- a/runtime/ilos/instance/extension.go +++ b/runtime/ilos/instance/extension.go @@ -14,6 +14,15 @@ func NewThrow(tag, object ilos.Instance) ilos.Instance { return i } +func NewBlockTag(tag, object ilos.Instance) ilos.Instance { + i := new(instance) + i.class = class.BlockTag + i.slots = map[ilos.Instance]ilos.Instance{} + i.slots[NewSymbol("TAG")] = tag + i.slots[NewSymbol("OBJECT")] = object + return i +} + func NewTagBodyTag(tag ilos.Instance) ilos.Instance { i := new(instance) i.class = class.TagBodyTag diff --git a/runtime/lambda.go b/runtime/lambda.go index 263fa6c..26a8571 100644 --- a/runtime/lambda.go +++ b/runtime/lambda.go @@ -20,6 +20,7 @@ func lambda(args ilos.Instance, local *env.Environment, global *env.Environment) forms := instance.UnsafeCdr(args) // Checked at the top of this function. (EndOfListIsNil) lexical := local return instance.NewFunction(func(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { + local.BlockTag = append(lexical.BlockTag, local.BlockTag...) local.TagBodyTag = append(lexical.TagBodyTag, local.TagBodyTag...) local.ThrowTag = append(lexical.ThrowTag, local.ThrowTag...) local.Variable = append(lexical.Variable, local.Variable...) diff --git a/runtime/return-from.go b/runtime/return-from.go new file mode 100644 index 0000000..5d1afa3 --- /dev/null +++ b/runtime/return-from.go @@ -0,0 +1,32 @@ +package runtime + +import ( + env "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/ilos" + "github.com/ta2gch/iris/runtime/ilos/class" + "github.com/ta2gch/iris/runtime/ilos/instance" +) + +func returnFrom(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { + // args must be a instance of Cons, not Null, and ends with nil + if !ilos.InstanceOf(args, class.Cons) || !UnsafeEndOfListIsNil(args) || UnsafeListLength(args) != 2 { // Checked at the head of test + return nil, instance.NewWrongNumberOfArguments(instance.NewSymbol("RETURN-FROM"), args) + } + car := instance.UnsafeCar(args) // Checked at the top of this function + tag, err := Eval(car, local, global) + if err != nil { + return nil, err + } + if ilos.InstanceOf(tag, class.Number) || ilos.InstanceOf(tag, class.Character) { + return nil, instance.NewDomainError(tag, class.Object) + } + cadr := instance.UnsafeCar(instance.UnsafeCdr(args)) // Checked length is 2 at the top of this function + object, err := Eval(cadr, local, global) + if err != nil { + return nil, err + } + if _, ok := local.BlockTag.Get(tag); !ok { + return nil, instance.NewSimpleError(instance.NewString("%v is not defined as the tag"), car) + } + return nil, instance.NewBlockTag(tag, object) +} diff --git a/runtime/runtime.go b/runtime/runtime.go index a150b71..dbfa629 100644 --- a/runtime/runtime.go +++ b/runtime/runtime.go @@ -10,6 +10,8 @@ func Init() { e.TopLevel.Macro.Define(i.NewSymbol("QUOTE"), i.NewFunction(quote)) e.TopLevel.Macro.Define(i.NewSymbol("THROW"), i.NewFunction(throw)) e.TopLevel.Macro.Define(i.NewSymbol("CATCH"), i.NewFunction(catch)) + e.TopLevel.Macro.Define(i.NewSymbol("BLOCK"), i.NewFunction(block)) + e.TopLevel.Macro.Define(i.NewSymbol("RETURN-FROM"), i.NewFunction(returnFrom)) e.TopLevel.Macro.Define(i.NewSymbol("TAGBODY"), i.NewFunction(tagbody)) e.TopLevel.Macro.Define(i.NewSymbol("GO"), i.NewFunction(tagbodyGo)) e.TopLevel.Macro.Define(i.NewSymbol("FUNCTION"), i.NewFunction(function)) From 7554b1e521f1395b9e0fe6b91073a9d641ce7c4b Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Fri, 4 Aug 2017 21:50:54 +0900 Subject: [PATCH 102/228] Changed error message --- runtime/catch.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/catch.go b/runtime/catch.go index e75e952..9f45203 100644 --- a/runtime/catch.go +++ b/runtime/catch.go @@ -10,7 +10,7 @@ import ( func catch(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { // args must be a instance of Cons, not Null, and ends with nil if !ilos.InstanceOf(args, class.Cons) || !UnsafeEndOfListIsNil(args) || UnsafeListLength(args) < 2 { // Checked at the head of test - return nil, instance.NewWrongNumberOfArguments(instance.NewSymbol("SYMBOL"), args) + return nil, instance.NewWrongNumberOfArguments(instance.NewSymbol("CATCH"), args) } car, err := Eval(instance.UnsafeCar(args), local, global) // Checked at the top of this function if err != nil { From 54ad77f39075b10554f1afa1ff7f63a56caec4c2 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Sun, 6 Aug 2017 19:19:09 +0900 Subject: [PATCH 103/228] Added documentation --- runtime/block.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/runtime/block.go b/runtime/block.go index 6ce2a8b..cde57e2 100644 --- a/runtime/block.go +++ b/runtime/block.go @@ -7,6 +7,14 @@ import ( "github.com/ta2gch/iris/runtime/ilos/instance" ) +// DEFINISION: +// The block special form executes each form sequentially from left to right. +// If the last form exits normally, whatever it returns is returned by the block form. +// The name in a block form is not evaluated; it must be an identifier. The scope of name +// is the body form only a return-from textually contained in some form can exit the block. +// The extend of name is dynamic. (islisp-v23.pdf, 43-44) +// NOTE: +// According to this, the scope of name is dynamic. I guess it should be a static. func block(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { // args must be a instance of Cons, not Null, and ends with nil if !ilos.InstanceOf(args, class.Cons) || !UnsafeEndOfListIsNil(args) || UnsafeListLength(args) < 2 { // Checked at the head of test From f3383bf2369ae2350b0416f488a7db8436eafa10 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Sun, 6 Aug 2017 21:45:01 +0900 Subject: [PATCH 104/228] Changed symbol name --- runtime/ilos/instance/serious-error.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/ilos/instance/serious-error.go b/runtime/ilos/instance/serious-error.go index 7182d7c..abcb247 100644 --- a/runtime/ilos/instance/serious-error.go +++ b/runtime/ilos/instance/serious-error.go @@ -49,7 +49,7 @@ func NewStreamError(stream ilos.Instance) ilos.Instance { i := new(instance) i.class = class.StreamError i.slots = map[ilos.Instance]ilos.Instance{} - i.slots[NewSymbol("stream")] = stream + i.slots[NewSymbol("STREAM")] = stream return i } From d482595ddff9b961897c9eb39eb2a498db8eb805 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Sun, 6 Aug 2017 21:45:28 +0900 Subject: [PATCH 105/228] Added slots of super classes --- runtime/ilos/instance/instance.go | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/runtime/ilos/instance/instance.go b/runtime/ilos/instance/instance.go index a5d5be7..a7f75bb 100644 --- a/runtime/ilos/instance/instance.go +++ b/runtime/ilos/instance/instance.go @@ -11,8 +11,9 @@ import ( // type instance struct { - class ilos.Class - slots map[ilos.Instance]ilos.Instance + class ilos.Class + supers []ilos.Instance + slots map[ilos.Instance]ilos.Instance } func (i *instance) Class() ilos.Class { @@ -20,8 +21,15 @@ func (i *instance) Class() ilos.Class { } func (i *instance) GetSlotValue(key ilos.Instance) (ilos.Instance, bool) { - v, ok := i.slots[key] - return v, ok + if v, ok := i.slots[key]; ok { + return v, ok + } + for _, s := range i.supers { + if v, ok := s.GetSlotValue(key); ok { + return v, ok + } + } + return nil, false } func (i *instance) SetSlotValue(key ilos.Instance, value ilos.Instance) bool { @@ -29,6 +37,11 @@ func (i *instance) SetSlotValue(key ilos.Instance, value ilos.Instance) bool { i.slots[key] = value return true } + for _, s := range i.supers { + if ok := s.SetSlotValue(key, value); ok { + return ok + } + } return false } From db82706353cd6651ce7eb1937962656cb40d8755 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Wed, 9 Aug 2017 17:15:23 +0900 Subject: [PATCH 106/228] get slotvalue by class --- runtime/block.go | 4 +- runtime/catch.go | 4 +- runtime/ilos/class/class.go | 4 +- runtime/ilos/ilos.go | 8 +-- runtime/ilos/instance/basic-array.go | 12 ++--- runtime/ilos/instance/character.go | 4 +- runtime/ilos/instance/function.go | 76 +--------------------------- runtime/ilos/instance/instance.go | 12 ++--- runtime/ilos/instance/list.go | 8 +-- runtime/ilos/instance/number.go | 8 +-- runtime/ilos/instance/symbol.go | 4 +- runtime/tagbody.go | 2 +- 12 files changed, 37 insertions(+), 109 deletions(-) diff --git a/runtime/block.go b/runtime/block.go index cde57e2..71acc4e 100644 --- a/runtime/block.go +++ b/runtime/block.go @@ -36,9 +36,9 @@ func block(args ilos.Instance, local *env.Environment, global *env.Environment) sucess, fail = Eval(cadr, local, global) if fail != nil { if ilos.InstanceOf(fail, class.BlockTag) { - tag, _ := fail.GetSlotValue(instance.NewSymbol("TAG")) // Checked at the head of this condition + tag, _ := fail.GetSlotValue(instance.NewSymbol("TAG"), class.BlockTag) // Checked at the head of this condition if car == tag { - obj, _ := fail.GetSlotValue(instance.NewSymbol("OBJECT")) // Checked at the head of this condition + obj, _ := fail.GetSlotValue(instance.NewSymbol("OBJECT"), class.BlockTag) // Checked at the head of this condition return obj, nil } } diff --git a/runtime/catch.go b/runtime/catch.go index 9f45203..f6d62f5 100644 --- a/runtime/catch.go +++ b/runtime/catch.go @@ -28,9 +28,9 @@ func catch(args ilos.Instance, local *env.Environment, global *env.Environment) sucess, fail = Eval(cadr, local, global) if fail != nil { if ilos.InstanceOf(fail, class.Throw) { - tag, _ := fail.GetSlotValue(instance.NewSymbol("TAG")) // Checked at the head of this condition + tag, _ := fail.GetSlotValue(instance.NewSymbol("TAG"), class.Throw) // Checked at the head of this condition if car == tag { - obj, _ := fail.GetSlotValue(instance.NewSymbol("OBJECT")) // Checked at the head of this condition + obj, _ := fail.GetSlotValue(instance.NewSymbol("OBJECT"), class.Throw) // Checked at the head of this condition return obj, nil } } diff --git a/runtime/ilos/class/class.go b/runtime/ilos/class/class.go index 2c6f476..fee8c35 100644 --- a/runtime/ilos/class/class.go +++ b/runtime/ilos/class/class.go @@ -15,11 +15,11 @@ func (p *builtinclass) Parents() []ilos.Class { return p.parents } -func (i *builtinclass) GetSlotValue(key ilos.Instance) (ilos.Instance, bool) { +func (i *builtinclass) GetSlotValue(key ilos.Instance, _ ilos.Class) (ilos.Instance, bool) { return nil, false } -func (i *builtinclass) SetSlotValue(key ilos.Instance, value ilos.Instance) bool { +func (i *builtinclass) SetSlotValue(key ilos.Instance, value ilos.Instance, _ ilos.Class) bool { return false } diff --git a/runtime/ilos/ilos.go b/runtime/ilos/ilos.go index e3d77e4..926fa4c 100644 --- a/runtime/ilos/ilos.go +++ b/runtime/ilos/ilos.go @@ -3,15 +3,15 @@ package ilos type Class interface { Class() Class Parents() []Class - GetSlotValue(Instance) (Instance, bool) - SetSlotValue(Instance, Instance) bool + GetSlotValue(Instance, Class) (Instance, bool) + SetSlotValue(Instance, Instance, Class) bool String() string } type Instance interface { Class() Class - GetSlotValue(Instance) (Instance, bool) - SetSlotValue(Instance, Instance) bool + GetSlotValue(Instance, Class) (Instance, bool) + SetSlotValue(Instance, Instance, Class) bool String() string } diff --git a/runtime/ilos/instance/basic-array.go b/runtime/ilos/instance/basic-array.go index 2e0d99b..c6e3f42 100644 --- a/runtime/ilos/instance/basic-array.go +++ b/runtime/ilos/instance/basic-array.go @@ -23,7 +23,7 @@ func (*GeneralArrayStar) Class() ilos.Class { return class.GeneralArrayStar } -func (a *GeneralArrayStar) GetSlotValue(key ilos.Instance) (ilos.Instance, bool) { +func (a *GeneralArrayStar) GetSlotValue(key ilos.Instance, _ ilos.Class) (ilos.Instance, bool) { if symbol, ok := key.(Symbol); ok && symbol == "LENGTH" { cons := NewNull() for i := 128; i > 0; i-- { @@ -52,7 +52,7 @@ func (a *GeneralArrayStar) GetSlotValue(key ilos.Instance) (ilos.Instance, bool) return nil, false } -func (a *GeneralArrayStar) SetSlotValue(key ilos.Instance, value ilos.Instance) bool { +func (a *GeneralArrayStar) SetSlotValue(key ilos.Instance, value ilos.Instance, _ ilos.Class) bool { if ilos.InstanceOf(key, class.List) { dim := [128]int{} idx := 0 @@ -91,7 +91,7 @@ func (GeneralVector) Class() ilos.Class { return class.GeneraVector } -func (i GeneralVector) GetSlotValue(key ilos.Instance) (ilos.Instance, bool) { +func (i GeneralVector) GetSlotValue(key ilos.Instance, _ ilos.Class) (ilos.Instance, bool) { if symbol, ok := key.(Symbol); ok && symbol == "LENGTH" { return NewInteger(len(i)), true } @@ -101,7 +101,7 @@ func (i GeneralVector) GetSlotValue(key ilos.Instance) (ilos.Instance, bool) { return nil, false } -func (i GeneralVector) SetSlotValue(key ilos.Instance, value ilos.Instance) bool { +func (i GeneralVector) SetSlotValue(key ilos.Instance, value ilos.Instance, _ ilos.Class) bool { if index, ok := key.(Integer); ok && int(index) < len(i) { i[int(index)] = value return true @@ -127,7 +127,7 @@ func (String) Class() ilos.Class { return class.String } -func (i String) GetSlotValue(key ilos.Instance) (ilos.Instance, bool) { +func (i String) GetSlotValue(key ilos.Instance, _ ilos.Class) (ilos.Instance, bool) { if symbol, ok := key.(Symbol); ok && symbol == "LENGTH" { return NewInteger(len(i)), true } @@ -137,7 +137,7 @@ func (i String) GetSlotValue(key ilos.Instance) (ilos.Instance, bool) { return nil, false } -func (i String) SetSlotValue(key ilos.Instance, value ilos.Instance) bool { +func (i String) SetSlotValue(key ilos.Instance, value ilos.Instance, _ ilos.Class) bool { if index, ok := key.(Integer); ok && int(index) < len(i) { if character, ok := value.(Character); ok { i[index] = rune(character) diff --git a/runtime/ilos/instance/character.go b/runtime/ilos/instance/character.go index e04ebcc..2012e18 100644 --- a/runtime/ilos/instance/character.go +++ b/runtime/ilos/instance/character.go @@ -19,11 +19,11 @@ func (Character) Class() ilos.Class { return class.Character } -func (i Character) GetSlotValue(key ilos.Instance) (ilos.Instance, bool) { +func (i Character) GetSlotValue(key ilos.Instance, _ ilos.Class) (ilos.Instance, bool) { return nil, false } -func (i Character) SetSlotValue(key ilos.Instance, value ilos.Instance) bool { +func (i Character) SetSlotValue(key ilos.Instance, value ilos.Instance, _ ilos.Class) bool { return false } diff --git a/runtime/ilos/instance/function.go b/runtime/ilos/instance/function.go index 28b7857..320a555 100644 --- a/runtime/ilos/instance/function.go +++ b/runtime/ilos/instance/function.go @@ -18,86 +18,14 @@ func (Function) Class() ilos.Class { return class.Function } -func (f Function) GetSlotValue(key ilos.Instance) (ilos.Instance, bool) { +func (f Function) GetSlotValue(key ilos.Instance, _ ilos.Class) (ilos.Instance, bool) { return nil, false } -func (Function) SetSlotValue(key ilos.Instance, value ilos.Instance) bool { +func (Function) SetSlotValue(key ilos.Instance, value ilos.Instance, _ ilos.Class) bool { return false } func (f Function) String() string { return fmt.Sprintf("#%v", f.Class()) } - -type GenericFunction map[[128]ilos.Class]Function - -func (GenericFunction) Class() ilos.Class { - return class.GenericFunction -} - -func (f GenericFunction) GetSlotValue(key ilos.Instance) (ilos.Instance, bool) { - types := [128]ilos.Class{} - cdr := key - idx := 0 - for ilos.InstanceOf(cdr, class.Cons) { - types[idx] = cdr.Class() - idx++ - } - if v, ok := f[types]; ok { - return v, true - } - return nil, false -} - -func (f GenericFunction) SetSlotValue(key ilos.Instance, value ilos.Instance) bool { - types := [128]ilos.Class{} - cdr := key - idx := 0 - for ilos.InstanceOf(cdr, class.Cons) { - types[idx] = cdr.Class() - idx++ - } - f[types] = value.(Function) - return true -} - -func (f GenericFunction) String() string { - return fmt.Sprintf("#%v", f.Class()) -} - -type StandardGenericFunction map[[128]ilos.Class]Function - -func (StandardGenericFunction) Class() ilos.Class { - return class.StandardGenericFunction -} - -func (f StandardGenericFunction) GetSlotValue(key ilos.Instance) (ilos.Instance, bool) { - types := [128]ilos.Class{} - cdr := key - idx := 0 - for ilos.InstanceOf(cdr, class.Cons) { - types[idx] = cdr.Class() - idx++ - } - if v, ok := f[types]; ok { - return v, true - } - return nil, false -} - -func (f StandardGenericFunction) SetSlotValue(key ilos.Instance, value ilos.Instance) bool { - types := [128]ilos.Class{} - cdr := key - idx := 0 - for ilos.InstanceOf(cdr, class.Cons) { - types[idx] = cdr.Class() - idx++ - } - f[types] = value.(Function) - return true -} - -func (f StandardGenericFunction) String() string { - return fmt.Sprintf("#%v", f.Class()) -} diff --git a/runtime/ilos/instance/instance.go b/runtime/ilos/instance/instance.go index a7f75bb..74bbfea 100644 --- a/runtime/ilos/instance/instance.go +++ b/runtime/ilos/instance/instance.go @@ -20,25 +20,25 @@ func (i *instance) Class() ilos.Class { return i.class } -func (i *instance) GetSlotValue(key ilos.Instance) (ilos.Instance, bool) { - if v, ok := i.slots[key]; ok { +func (i *instance) GetSlotValue(key ilos.Instance, class ilos.Class) (ilos.Instance, bool) { + if v, ok := i.slots[key]; ok && i.class == class { return v, ok } for _, s := range i.supers { - if v, ok := s.GetSlotValue(key); ok { + if v, ok := s.GetSlotValue(key, class); ok { return v, ok } } return nil, false } -func (i *instance) SetSlotValue(key ilos.Instance, value ilos.Instance) bool { - if _, ok := i.slots[key]; ok { +func (i *instance) SetSlotValue(key ilos.Instance, value ilos.Instance, class ilos.Class) bool { + if _, ok := i.slots[key]; ok && i.class == class { i.slots[key] = value return true } for _, s := range i.supers { - if ok := s.SetSlotValue(key, value); ok { + if ok := s.SetSlotValue(key, value, class); ok { return ok } } diff --git a/runtime/ilos/instance/list.go b/runtime/ilos/instance/list.go index b5f09d3..dff2961 100644 --- a/runtime/ilos/instance/list.go +++ b/runtime/ilos/instance/list.go @@ -24,7 +24,7 @@ func (*Cons) Class() ilos.Class { return class.Cons } -func (i *Cons) GetSlotValue(key ilos.Instance) (ilos.Instance, bool) { +func (i *Cons) GetSlotValue(key ilos.Instance, _ ilos.Class) (ilos.Instance, bool) { if symbol, ok := key.(Symbol); ok { switch symbol { case "CAR": @@ -36,7 +36,7 @@ func (i *Cons) GetSlotValue(key ilos.Instance) (ilos.Instance, bool) { return nil, false } -func (i *Cons) SetSlotValue(key ilos.Instance, value ilos.Instance) bool { +func (i *Cons) SetSlotValue(key ilos.Instance, value ilos.Instance, _ ilos.Class) bool { if symbol, ok := key.(Symbol); ok { switch symbol { case "CAR": @@ -87,11 +87,11 @@ func (Null) Class() ilos.Class { return class.Null } -func (i Null) GetSlotValue(key ilos.Instance) (ilos.Instance, bool) { +func (i Null) GetSlotValue(key ilos.Instance, _ ilos.Class) (ilos.Instance, bool) { return nil, false } -func (i Null) SetSlotValue(key ilos.Instance, value ilos.Instance) bool { +func (i Null) SetSlotValue(key ilos.Instance, value ilos.Instance, _ ilos.Class) bool { return false } diff --git a/runtime/ilos/instance/number.go b/runtime/ilos/instance/number.go index fc1acbf..a524b5c 100644 --- a/runtime/ilos/instance/number.go +++ b/runtime/ilos/instance/number.go @@ -21,11 +21,11 @@ func (Integer) Class() ilos.Class { return class.Integer } -func (i Integer) GetSlotValue(key ilos.Instance) (ilos.Instance, bool) { +func (i Integer) GetSlotValue(key ilos.Instance, _ ilos.Class) (ilos.Instance, bool) { return nil, false } -func (i Integer) SetSlotValue(key ilos.Instance, value ilos.Instance) bool { +func (i Integer) SetSlotValue(key ilos.Instance, value ilos.Instance, _ ilos.Class) bool { return false } @@ -47,11 +47,11 @@ func (Float) Class() ilos.Class { return class.Float } -func (i Float) GetSlotValue(key ilos.Instance) (ilos.Instance, bool) { +func (i Float) GetSlotValue(key ilos.Instance, _ ilos.Class) (ilos.Instance, bool) { return nil, false } -func (i Float) SetSlotValue(key ilos.Instance, value ilos.Instance) bool { +func (i Float) SetSlotValue(key ilos.Instance, value ilos.Instance, _ ilos.Class) bool { return false } diff --git a/runtime/ilos/instance/symbol.go b/runtime/ilos/instance/symbol.go index cb895ed..5c5b8b8 100644 --- a/runtime/ilos/instance/symbol.go +++ b/runtime/ilos/instance/symbol.go @@ -19,11 +19,11 @@ func (Symbol) Class() ilos.Class { return class.Symbol } -func (i Symbol) GetSlotValue(key ilos.Instance) (ilos.Instance, bool) { +func (i Symbol) GetSlotValue(key ilos.Instance, _ ilos.Class) (ilos.Instance, bool) { return nil, false } -func (i Symbol) SetSlotValue(key ilos.Instance, value ilos.Instance) bool { +func (i Symbol) SetSlotValue(key ilos.Instance, value ilos.Instance, _ ilos.Class) bool { return false } diff --git a/runtime/tagbody.go b/runtime/tagbody.go index 749abed..fa4c427 100644 --- a/runtime/tagbody.go +++ b/runtime/tagbody.go @@ -32,7 +32,7 @@ func tagbody(args ilos.Instance, local *env.Environment, global *env.Environment if fail != nil { tag: if ilos.InstanceOf(fail, class.TagBodyTag) { - tag, _ := fail.GetSlotValue(instance.NewSymbol("TAG")) // Checked at the top of this loop + tag, _ := fail.GetSlotValue(instance.NewSymbol("TAG"), class.TagBodyTag) // Checked at the top of this loop found := false for _, localTag := range localTags { if tag == localTag { From 74c0f64f480d4d6a293ba683b45c858430e71479 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Wed, 9 Aug 2017 17:25:56 +0900 Subject: [PATCH 107/228] Rename Special Object's names --- runtime/block.go | 6 +++--- runtime/go.go | 2 +- runtime/ilos/class/class.go | 4 ++-- runtime/ilos/instance/extension.go | 8 ++++---- runtime/return-from.go | 2 +- runtime/tagbody.go | 4 ++-- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/runtime/block.go b/runtime/block.go index 71acc4e..645fdef 100644 --- a/runtime/block.go +++ b/runtime/block.go @@ -35,10 +35,10 @@ func block(args ilos.Instance, local *env.Environment, global *env.Environment) cddr := instance.UnsafeCdr(cdr) // Checked at the top of this loop sucess, fail = Eval(cadr, local, global) if fail != nil { - if ilos.InstanceOf(fail, class.BlockTag) { - tag, _ := fail.GetSlotValue(instance.NewSymbol("TAG"), class.BlockTag) // Checked at the head of this condition + if ilos.InstanceOf(fail, class.ReturnFrom) { + tag, _ := fail.GetSlotValue(instance.NewSymbol("TAG"), class.ReturnFrom) // Checked at the head of this condition if car == tag { - obj, _ := fail.GetSlotValue(instance.NewSymbol("OBJECT"), class.BlockTag) // Checked at the head of this condition + obj, _ := fail.GetSlotValue(instance.NewSymbol("OBJECT"), class.ReturnFrom) // Checked at the head of this condition return obj, nil } } diff --git a/runtime/go.go b/runtime/go.go index 1ff0f8f..18c2c20 100644 --- a/runtime/go.go +++ b/runtime/go.go @@ -16,5 +16,5 @@ func tagbodyGo(args ilos.Instance, local *env.Environment, global *env.Environme if _, ok := local.TagBodyTag.Get(car); !ok { return nil, instance.NewSimpleError(instance.NewString("%v is not defined as the tag"), car) } - return nil, instance.NewTagBodyTag(car) + return nil, instance.NewGo(car) } diff --git a/runtime/ilos/class/class.go b/runtime/ilos/class/class.go index fee8c35..cf7b2c3 100644 --- a/runtime/ilos/class/class.go +++ b/runtime/ilos/class/class.go @@ -71,5 +71,5 @@ var Stream = &builtinclass{[]ilos.Class{Object}, ""} var WrongNumberOfArguments = &builtinclass{[]ilos.Class{Error}, ""} var Escape = &builtinclass{[]ilos.Class{Object}, ""} var Throw = &builtinclass{[]ilos.Class{Escape}, ""} -var TagBodyTag = &builtinclass{[]ilos.Class{Escape}, ""} -var BlockTag = &builtinclass{[]ilos.Class{Escape}, ""} +var Go = &builtinclass{[]ilos.Class{Escape}, ""} +var ReturnFrom = &builtinclass{[]ilos.Class{Escape}, ""} diff --git a/runtime/ilos/instance/extension.go b/runtime/ilos/instance/extension.go index b43f172..a138646 100644 --- a/runtime/ilos/instance/extension.go +++ b/runtime/ilos/instance/extension.go @@ -14,18 +14,18 @@ func NewThrow(tag, object ilos.Instance) ilos.Instance { return i } -func NewBlockTag(tag, object ilos.Instance) ilos.Instance { +func NewReturnFrom(tag, object ilos.Instance) ilos.Instance { i := new(instance) - i.class = class.BlockTag + i.class = class.ReturnFrom i.slots = map[ilos.Instance]ilos.Instance{} i.slots[NewSymbol("TAG")] = tag i.slots[NewSymbol("OBJECT")] = object return i } -func NewTagBodyTag(tag ilos.Instance) ilos.Instance { +func NewGo(tag ilos.Instance) ilos.Instance { i := new(instance) - i.class = class.TagBodyTag + i.class = class.Go i.slots = map[ilos.Instance]ilos.Instance{} i.slots[NewSymbol("TAG")] = tag return i diff --git a/runtime/return-from.go b/runtime/return-from.go index 5d1afa3..8a6628f 100644 --- a/runtime/return-from.go +++ b/runtime/return-from.go @@ -28,5 +28,5 @@ func returnFrom(args ilos.Instance, local *env.Environment, global *env.Environm if _, ok := local.BlockTag.Get(tag); !ok { return nil, instance.NewSimpleError(instance.NewString("%v is not defined as the tag"), car) } - return nil, instance.NewBlockTag(tag, object) + return nil, instance.NewReturnFrom(tag, object) } diff --git a/runtime/tagbody.go b/runtime/tagbody.go index fa4c427..aeb7a19 100644 --- a/runtime/tagbody.go +++ b/runtime/tagbody.go @@ -31,8 +31,8 @@ func tagbody(args ilos.Instance, local *env.Environment, global *env.Environment _, fail := Eval(cadr, local, global) if fail != nil { tag: - if ilos.InstanceOf(fail, class.TagBodyTag) { - tag, _ := fail.GetSlotValue(instance.NewSymbol("TAG"), class.TagBodyTag) // Checked at the top of this loop + if ilos.InstanceOf(fail, class.Go) { + tag, _ := fail.GetSlotValue(instance.NewSymbol("TAG"), class.Go) // Checked at the top of this loop found := false for _, localTag := range localTags { if tag == localTag { From 209c7b9d7ef2abc8333ed944f8daef56da49f400 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Wed, 9 Aug 2017 22:10:18 +0900 Subject: [PATCH 108/228] added instance.New --- reader/parser/parser.go | 59 ++++++++++---------- reader/parser/parser_test.go | 33 ++++++------ reader/tokenizer/tokenizer.go | 2 +- runtime/block.go | 11 ++-- runtime/catch.go | 11 ++-- runtime/eval.go | 33 ++++++++---- runtime/eval_test.go | 25 ++++----- runtime/function.go | 15 ++++-- runtime/go.go | 12 +++-- runtime/ilos/class/builtinclass.go | 60 +++++++++++++++++++++ runtime/ilos/class/class.go | 75 -------------------------- runtime/ilos/class/primitiveclass.go | 53 ++++++++++++++++++ runtime/ilos/ilos.go | 1 + runtime/ilos/instance/extension.go | 59 -------------------- runtime/ilos/instance/instance.go | 41 ++++++++++++-- runtime/ilos/instance/serious-error.go | 63 ---------------------- runtime/lambda.go | 35 ++++++++---- runtime/quote.go | 5 +- runtime/return-from.go | 20 +++++-- runtime/tagbody.go | 9 ++-- runtime/throw.go | 20 +++++-- 21 files changed, 339 insertions(+), 303 deletions(-) create mode 100644 runtime/ilos/class/builtinclass.go delete mode 100644 runtime/ilos/class/class.go create mode 100644 runtime/ilos/class/primitiveclass.go delete mode 100644 runtime/ilos/instance/extension.go delete mode 100644 runtime/ilos/instance/serious-error.go diff --git a/reader/parser/parser.go b/reader/parser/parser.go index c48a9b4..a7fa4ad 100644 --- a/reader/parser/parser.go +++ b/reader/parser/parser.go @@ -13,8 +13,8 @@ import ( "github.com/ta2gch/iris/runtime/ilos/class" ) -var eop = instance.NewSymbol("End Of Parentheses") -var bod = instance.NewSymbol("Begin Of Dot") +var eop = instance.New(class.Symbol, "End Of Parentheses") +var bod = instance.New(class.Symbol, "Begin Of Dot") func parseAtom(tok string) (ilos.Instance, ilos.Instance) { // @@ -22,69 +22,72 @@ func parseAtom(tok string) (ilos.Instance, ilos.Instance) { // if m, _ := regexp.MatchString("^[-+]?[[:digit:]]+$", tok); m { n, _ := strconv.ParseInt(tok, 10, 64) - return instance.NewInteger(int(n)), nil + return instance.New(class.Integer, int(n)), nil } if r := regexp.MustCompile("^#[bB]([-+]?[01]+)$").FindStringSubmatch(tok); len(r) >= 2 { n, _ := strconv.ParseInt(r[1], 2, 64) - return instance.NewInteger(int(n)), nil + return instance.New(class.Integer, int(n)), nil } if r := regexp.MustCompile("^#[oO]([-+]?[0-7]+)$").FindStringSubmatch(tok); len(r) >= 2 { n, _ := strconv.ParseInt(r[1], 8, 64) - return instance.NewInteger(int(n)), nil + return instance.New(class.Integer, int(n)), nil } if r := regexp.MustCompile("^#[xX]([-+]?[[:xdigit:]]+)$").FindStringSubmatch(tok); len(r) >= 2 { n, _ := strconv.ParseInt(r[1], 16, 64) - return instance.NewInteger(int(n)), nil + return instance.New(class.Integer, int(n)), nil } // // float // if m, _ := regexp.MatchString("^[-+]?[[:digit:]]+\\.[[:digit:]]+$", tok); m { n, _ := strconv.ParseFloat(tok, 64) - return instance.NewFloat(n), nil + return instance.New(class.Float, n), nil } if r := regexp.MustCompile("^([-+]?[[:digit:]]+(?:\\.[[:digit:]]+)?)[eE]([-+]?[[:digit:]]+)$").FindStringSubmatch(tok); len(r) >= 3 { n, _ := strconv.ParseFloat(r[1], 64) e, _ := strconv.ParseInt(r[2], 10, 64) - return instance.NewFloat(n * math.Pow10(int(e))), nil + return instance.New(class.Float, n*math.Pow10(int(e))), nil } // // character // if m, _ := regexp.MatchString("^#\\\\newline$", tok); m { - return instance.NewCharacter('\n'), nil + return instance.New(class.Character, '\n'), nil } if m, _ := regexp.MatchString("^#\\\\space$", tok); m { - return instance.NewCharacter(' '), nil + return instance.New(class.Character, ' '), nil } if r := regexp.MustCompile("^#\\\\([[:graph:]])$").FindStringSubmatch(tok); len(r) >= 2 { - return instance.NewCharacter(rune(r[1][0])), nil + return instance.New(class.Character, rune(r[1][0])), nil } // // string // if m, _ := regexp.MatchString("^\".*\"$", tok); m { - return instance.NewString(tok), nil + return instance.New(class.String, tok), nil } // // symbol // if "nil" == tok { - return instance.NewNull(), nil + return instance.New(class.Null), nil } if r := regexp.MustCompile("^:([<>/*=?_!$%[\\]^{}~0-9a-zA-Z]+)$").FindStringSubmatch(tok); len(r) >= 2 { - return instance.NewSymbol(strings.ToUpper(r[0])), nil + return instance.New(class.Symbol, strings.ToUpper(r[0])), nil } if r := regexp.MustCompile("^&([<>/*=?_!$%[\\]^{}~0-9a-zA-Z]+)$").FindStringSubmatch(tok); len(r) >= 2 { - return instance.NewSymbol(strings.ToUpper(r[0])), nil + return instance.New(class.Symbol, strings.ToUpper(r[0])), nil } if m, _ := regexp.MatchString("^\\|.*\\|$", tok); m { - return instance.NewSymbol(tok), nil + return instance.New(class.Symbol, tok), nil } if m, _ := regexp.MatchString("^[<>/*=?_!$%[\\]^{}~a-zA-Z-][<>/*=?_!$%[\\]^{}~0-9a-zA-Z-]*$", tok); m { - return instance.NewSymbol(strings.ToUpper(tok)), nil + return instance.New(class.Symbol, strings.ToUpper(tok)), nil } - return nil, instance.NewParseError(instance.NewString(tok), class.Object) + return nil, instance.New(class.ParseError, map[string]ilos.Instance{ + "STRING": instance.New(class.String, tok), + "EXPECTED-CLASS": class.Object, + }) } func parseMacro(tok string, t *tokenizer.Tokenizer) (ilos.Instance, ilos.Instance) { @@ -94,18 +97,18 @@ func parseMacro(tok string, t *tokenizer.Tokenizer) (ilos.Instance, ilos.Instanc } n := tok if m, _ := regexp.MatchString("#[[:digit:]]*[aA]", tok); m { - s := instance.NewSymbol("array") + s := instance.New(class.Symbol, "array") i := strings.IndexRune(strings.ToLower(tok), 'a') if i == 1 { - d := instance.NewInteger(1) - return instance.NewCons(s, instance.NewCons(d, instance.NewCons(cdr, instance.NewNull()))), nil + d := instance.New(class.Integer, 1) + return instance.New(class.Cons, s, instance.New(class.Cons, d, instance.New(class.Cons, cdr, instance.New(class.Null)))), nil } v, err := strconv.ParseInt(tok[1:i], 10, 32) if err != nil { - return nil, instance.NewParseError(instance.NewString(tok), class.Integer) + return nil, instance.New(class.ParseError, instance.New(class.String, tok), class.Integer) } - d := instance.NewInteger(int(v)) - return instance.NewCons(s, instance.NewCons(d, instance.NewCons(cdr, instance.NewNull()))), nil + d := instance.New(class.Integer, int(v)) + return instance.New(class.Cons, s, instance.New(class.Cons, d, instance.New(class.Cons, cdr, instance.New(class.Null)))), nil } switch tok { case "#'": @@ -119,13 +122,13 @@ func parseMacro(tok string, t *tokenizer.Tokenizer) (ilos.Instance, ilos.Instanc case "`": n = "BACKQUOTE" } - m := instance.NewSymbol(n) - return instance.NewCons(m, instance.NewCons(cdr, instance.NewNull())), nil + m := instance.New(class.Symbol, n) + return instance.New(class.Cons, m, instance.New(class.Cons, cdr, instance.New(class.Null))), nil } func parseCons(t *tokenizer.Tokenizer) (ilos.Instance, ilos.Instance) { car, err := Parse(t) if err == eop { - return instance.NewNull(), nil + return instance.New(class.Null), nil } if err == bod { cdr, err := Parse(t) @@ -144,7 +147,7 @@ func parseCons(t *tokenizer.Tokenizer) (ilos.Instance, ilos.Instance) { if err != nil { return nil, err } - return instance.NewCons(car, cdr), nil + return instance.New(class.Cons, car, cdr), nil } // Parse builds a internal expression from tokens diff --git a/reader/parser/parser_test.go b/reader/parser/parser_test.go index 04f1653..6138e9e 100644 --- a/reader/parser/parser_test.go +++ b/reader/parser/parser_test.go @@ -5,6 +5,7 @@ import ( "testing" "github.com/ta2gch/iris/runtime/ilos" + "github.com/ta2gch/iris/runtime/ilos/class" "github.com/ta2gch/iris/runtime/ilos/instance" ) @@ -24,31 +25,31 @@ func Test_parseAtom(t *testing.T) { { name: "default", args: args{"3.14"}, - want: instance.NewFloat(3.14), + want: instance.New(class.Float, 3.14), wantErr: false, }, { name: "signed", args: args{"-5.0"}, - want: instance.NewFloat(-5.0), + want: instance.New(class.Float, -5.0), wantErr: false, }, { name: "exponential", args: args{"-5.0E3"}, - want: instance.NewFloat(-5.0 * 1000), + want: instance.New(class.Float, -5.0*1000), wantErr: false, }, { name: "signed exponential", args: args{"5.0E-3"}, - want: instance.NewFloat(5.0 * 1.0 / 1000.0), + want: instance.New(class.Float, 5.0*1.0/1000.0), wantErr: false, }, { name: "without point", args: args{"5E-3"}, - want: instance.NewFloat(5.0 * 1.0 / 1000.0), + want: instance.New(class.Float, 5.0*1.0/1000.0), wantErr: false, }, { @@ -69,49 +70,49 @@ func Test_parseAtom(t *testing.T) { { name: "default", args: args{"5"}, - want: instance.NewInteger(5), + want: instance.New(class.Integer, 5), wantErr: false, }, { name: "signed", args: args{"-5"}, - want: instance.NewInteger(-5), + want: instance.New(class.Integer, -5), wantErr: false, }, { name: "binary", args: args{"#B00101"}, - want: instance.NewInteger(5), + want: instance.New(class.Integer, 5), wantErr: false, }, { name: "signed binary", args: args{"#b+00101"}, - want: instance.NewInteger(5), + want: instance.New(class.Integer, 5), wantErr: false, }, { name: "octal", args: args{"#o00101"}, - want: instance.NewInteger(65), + want: instance.New(class.Integer, 65), wantErr: false, }, { name: "signed octal", args: args{"#O-00101"}, - want: instance.NewInteger(-65), + want: instance.New(class.Integer, -65), wantErr: false, }, { name: "hexadecimal", args: args{"#X00101"}, - want: instance.NewInteger(257), + want: instance.New(class.Integer, 257), wantErr: false, }, { name: "signed hexadecimal", args: args{"#x-00101"}, - want: instance.NewInteger(-257), + want: instance.New(class.Integer, -257), wantErr: false, }, { @@ -126,19 +127,19 @@ func Test_parseAtom(t *testing.T) { { name: "default", args: args{"#\\a"}, - want: instance.NewCharacter('a'), + want: instance.New(class.Character, 'a'), wantErr: false, }, { name: "newline", args: args{"#\\newline"}, - want: instance.NewCharacter('\n'), + want: instance.New(class.Character, '\n'), wantErr: false, }, { name: "space", args: args{"#\\space"}, - want: instance.NewCharacter(' '), + want: instance.New(class.Character, ' '), wantErr: false, }, { diff --git a/reader/tokenizer/tokenizer.go b/reader/tokenizer/tokenizer.go index a2f80b3..6fbe295 100644 --- a/reader/tokenizer/tokenizer.go +++ b/reader/tokenizer/tokenizer.go @@ -45,7 +45,7 @@ func (t *Tokenizer) Next() (string, ilos.Instance) { if t.sc.Scan() { return t.sc.Text(), nil } - return "", instance.NewParseError(instance.NewString(t.sc.Text()), class.Object) + return "", instance.New(class.ParseError,instance.New(class.String,t.sc.Text()), class.Object) } func splitter(data []byte, atEOF bool) (advance int, token []byte, err error) { diff --git a/runtime/block.go b/runtime/block.go index 645fdef..99b3eea 100644 --- a/runtime/block.go +++ b/runtime/block.go @@ -18,14 +18,17 @@ import ( func block(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { // args must be a instance of Cons, not Null, and ends with nil if !ilos.InstanceOf(args, class.Cons) || !UnsafeEndOfListIsNil(args) || UnsafeListLength(args) < 2 { // Checked at the head of test - return nil, instance.NewWrongNumberOfArguments(instance.NewSymbol("BLOCK"), args) + return nil, instance.New(class.WrongNumberOfArguments, map[string]ilos.Instance{ + "FORM": instance.New(class.Symbol, "BLOCK"), + "ARGUMENTS": args, + }) } car, err := Eval(instance.UnsafeCar(args), local, global) // Checked at the top of this function if err != nil { return nil, err } if ilos.InstanceOf(car, class.Number) || ilos.InstanceOf(car, class.Character) { - return nil, instance.NewDomainError(car, class.Object) + return nil, instance.New(class.DomainError, car, class.Object) } local.BlockTag.Define(car, car) cdr := instance.UnsafeCdr(args) // Checked at the top of this function @@ -36,9 +39,9 @@ func block(args ilos.Instance, local *env.Environment, global *env.Environment) sucess, fail = Eval(cadr, local, global) if fail != nil { if ilos.InstanceOf(fail, class.ReturnFrom) { - tag, _ := fail.GetSlotValue(instance.NewSymbol("TAG"), class.ReturnFrom) // Checked at the head of this condition + tag, _ := fail.GetSlotValue(instance.New(class.Symbol, "TAG"), class.Escape) // Checked at the head of this condition if car == tag { - obj, _ := fail.GetSlotValue(instance.NewSymbol("OBJECT"), class.ReturnFrom) // Checked at the head of this condition + obj, _ := fail.GetSlotValue(instance.New(class.Symbol, "OBJECT"), class.ReturnFrom) // Checked at the head of this condition return obj, nil } } diff --git a/runtime/catch.go b/runtime/catch.go index f6d62f5..35707cd 100644 --- a/runtime/catch.go +++ b/runtime/catch.go @@ -10,14 +10,17 @@ import ( func catch(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { // args must be a instance of Cons, not Null, and ends with nil if !ilos.InstanceOf(args, class.Cons) || !UnsafeEndOfListIsNil(args) || UnsafeListLength(args) < 2 { // Checked at the head of test - return nil, instance.NewWrongNumberOfArguments(instance.NewSymbol("CATCH"), args) + return nil, instance.New(class.WrongNumberOfArguments, map[string]ilos.Instance{ + "FORM": instance.New(class.Symbol, "CATCH"), + "ARGUMENTS": args, + }) } car, err := Eval(instance.UnsafeCar(args), local, global) // Checked at the top of this function if err != nil { return nil, err } if ilos.InstanceOf(car, class.Number) || ilos.InstanceOf(car, class.Character) { - return nil, instance.NewDomainError(car, class.Object) + return nil, instance.New(class.DomainError, car, class.Object) } local.ThrowTag.Define(car, car) cdr := instance.UnsafeCdr(args) // Checked at the top of this function @@ -28,9 +31,9 @@ func catch(args ilos.Instance, local *env.Environment, global *env.Environment) sucess, fail = Eval(cadr, local, global) if fail != nil { if ilos.InstanceOf(fail, class.Throw) { - tag, _ := fail.GetSlotValue(instance.NewSymbol("TAG"), class.Throw) // Checked at the head of this condition + tag, _ := fail.GetSlotValue(instance.New(class.Symbol, "TAG"), class.Escape) // Checked at the head of this condition if car == tag { - obj, _ := fail.GetSlotValue(instance.NewSymbol("OBJECT"), class.Throw) // Checked at the head of this condition + obj, _ := fail.GetSlotValue(instance.New(class.Symbol, "OBJECT"), class.Throw) // Checked at the head of this condition return obj, nil } } diff --git a/runtime/eval.go b/runtime/eval.go index 396a18f..fbfdc8e 100644 --- a/runtime/eval.go +++ b/runtime/eval.go @@ -10,11 +10,14 @@ import ( func evalArguments(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { // if args ends here if ilos.InstanceOf(args, class.Null) { - return instance.NewNull(), nil + return instance.New(class.Null), nil } // args must be a instance of list and ends with nil if !ilos.InstanceOf(args, class.List) || !UnsafeEndOfListIsNil(args) { - return nil, instance.NewParseError(args, class.List) + return nil, instance.New(class.ParseError, map[string]ilos.Instance{ + "STRING": args, + "EXPECTED-CLASS": class.List, + }) } car := instance.UnsafeCar(args) // Checked there cdr := instance.UnsafeCdr(args) // Checked there @@ -26,14 +29,17 @@ func evalArguments(args ilos.Instance, local *env.Environment, global *env.Envir if err != nil { return nil, err } - return instance.NewCons(a, b), nil + return instance.New(class.Cons, a, b), nil } func evalFunction(obj ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { // obj, function call form, must be a instance of Cons, NOT Null, and ends with nil if !ilos.InstanceOf(obj, class.Cons) || !UnsafeEndOfListIsNil(obj) { - return nil, instance.NewParseError(obj, class.Cons) + return nil, instance.New(class.ParseError, map[string]ilos.Instance{ + "STRING": obj, + "EXPECTED-CLASS": class.Cons, + }) } // get function symbol car := instance.UnsafeCar(obj) // Checked at the top of this function @@ -44,7 +50,7 @@ func evalFunction(obj ilos.Instance, local *env.Environment, global *env.Environ // eval if lambda form if ilos.InstanceOf(car, class.Cons) { caar := instance.UnsafeCar(car) // Checked at the top of this sentence - if caar == instance.NewSymbol("LAMBDA") { + if caar == instance.New(class.Symbol, "LAMBDA") { fun, err := Eval(car, local, global) if err != nil { return nil, err @@ -66,7 +72,10 @@ func evalFunction(obj ilos.Instance, local *env.Environment, global *env.Environ } // if function is not a lambda special form, first element must be a symbol if !ilos.InstanceOf(car, class.Symbol) { - return nil, instance.NewDomainError(car, class.Symbol) + return nil, instance.New(class.DomainError, map[string]ilos.Instance{ + "OBJECT": car, + "EXPECTED-CLASS": class.Symbol, + }) } // get macro instance has value of Function interface var mac ilos.Instance @@ -105,13 +114,16 @@ func evalFunction(obj ilos.Instance, local *env.Environment, global *env.Environ } return ret, nil } - return nil, instance.NewUndefinedFunction(car) + return nil, instance.New(class.UndefinedFunction, map[string]ilos.Instance{ + "NAME": car, + "NAMESPACE": instance.New(class.Symbol, "FUNCTION"), + }) } // Eval evaluates any classs func Eval(obj ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { if ilos.InstanceOf(obj, class.Null) { - return instance.NewNull(), nil + return instance.New(class.Null), nil } if ilos.InstanceOf(obj, class.Symbol) { if val, ok := local.Variable.Get(obj); ok { @@ -120,7 +132,10 @@ func Eval(obj ilos.Instance, local *env.Environment, global *env.Environment) (i if val, ok := global.Variable.Get(obj); ok { return val, nil } - return nil, instance.NewUndefinedVariable(obj) + return nil, instance.New(class.UndefinedVariable, map[string]ilos.Instance{ + "NAME": obj, + "NAMESPACE": instance.New(class.Symbol, "VARIABLE"), + }) } if ilos.InstanceOf(obj, class.Cons) { ret, err := evalFunction(obj, local, global) diff --git a/runtime/eval_test.go b/runtime/eval_test.go index 4a7f632..088fc5f 100644 --- a/runtime/eval_test.go +++ b/runtime/eval_test.go @@ -10,6 +10,7 @@ import ( env "github.com/ta2gch/iris/runtime/environment" "github.com/ta2gch/iris/runtime/ilos" + "github.com/ta2gch/iris/runtime/ilos/class" "github.com/ta2gch/iris/runtime/ilos/instance" ) @@ -24,12 +25,12 @@ func TestEval(t *testing.T) { global := env.TopLevel inc := func(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { car := instance.UnsafeCar(args) - return instance.NewInteger(int(car.(instance.Integer)) + 1), nil + return instance.New(class.Integer, int(car.(instance.Integer))+1), nil } - local.Variable.Define(instance.NewSymbol("PI"), instance.NewFloat(3.14)) - local.Function.Define(instance.NewSymbol("INC"), instance.NewFunction(inc)) - local.Macro.Define(instance.NewSymbol("MINC"), instance.NewFunction(func(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { - ret, err := Eval(instance.NewCons(instance.NewSymbol("INC"), args), local, global) + local.Variable.Define(instance.New(class.Symbol, "PI"), instance.New(class.Float, 3.14)) + local.Function.Define(instance.New(class.Symbol, "INC"), instance.New(class.Function, inc)) + local.Macro.Define(instance.New(class.Symbol, "MINC"), instance.New(class.Function, func(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { + ret, err := Eval(instance.New(class.Cons, instance.New(class.Symbol, "INC"), args), local, global) return ret, err })) type args struct { @@ -45,26 +46,26 @@ func TestEval(t *testing.T) { }{ { name: "local variable", - args: args{instance.NewSymbol("PI"), local, global}, - want: instance.NewFloat(3.14), + args: args{instance.New(class.Symbol, "PI"), local, global}, + want: instance.New(class.Float, 3.14), wantErr: false, }, { name: "local function", args: args{read("(inc (inc 1))"), local, global}, - want: instance.NewInteger(3), + want: instance.New(class.Integer, 3), wantErr: false, }, { name: "local macro", args: args{read("(minc (minc 1))"), local, global}, - want: instance.NewInteger(3), + want: instance.New(class.Integer, 3), wantErr: false, }, { name: "lambda form", args: args{read("((lambda (x)) 1)"), local, global}, - want: instance.NewNull(), + want: instance.New(class.Null), wantErr: false, }, { @@ -88,13 +89,13 @@ func TestEval(t *testing.T) { { name: "tagbody & go", args: args{read("(catch 'foo (tagbody (go bar) (throw 'foo 1) bar))"), local, global}, - want: instance.NewNull(), + want: instance.New(class.Null), wantErr: false, }, { name: "nested tagbody & go", args: args{read("(catch 'foo (tagbody (tagbody (go bar) (throw 'foo 1) bar (go foobar)) foobar))"), local, global}, - want: instance.NewNull(), + want: instance.New(class.Null), wantErr: false, }, } diff --git a/runtime/function.go b/runtime/function.go index 3f20f60..e755838 100644 --- a/runtime/function.go +++ b/runtime/function.go @@ -10,12 +10,18 @@ import ( func function(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { // args must be a instance of Cons, not Null, and ends with nil if !ilos.InstanceOf(args, class.Cons) || !UnsafeEndOfListIsNil(args) || UnsafeListLength(args) != 1 { // Checked at the head of test - return nil, instance.NewWrongNumberOfArguments(instance.NewSymbol("FUNCTION"), args) + return nil, instance.New(class.WrongNumberOfArguments, map[string]ilos.Instance{ + "FORM": instance.New(class.Symbol, "FUNCTION"), + "ARGUMENTS": args, + }) } car := instance.UnsafeCar(args) // Checked at the top of this function // car must be a symbol if !ilos.InstanceOf(car, class.Symbol) { - return nil, instance.NewDomainError(car, class.Symbol) + return nil, instance.New(class.DomainError, map[string]ilos.Instance{ + "OBJECT": car, + "EXPECTED-CLASS": class.Symbol, + }) } if f, ok := local.Function.Get(car); ok { return f, nil @@ -23,5 +29,8 @@ func function(args ilos.Instance, local *env.Environment, global *env.Environmen if f, ok := global.Function.Get(car); ok { return f, nil } - return nil, instance.NewUndefinedFunction(car) + return nil, instance.New(class.UndefinedFunction, map[string]ilos.Instance{ + "NAME": car, + "NAMESPACE": instance.New(class.Symbol, "FUNCTION"), + }) } diff --git a/runtime/go.go b/runtime/go.go index 18c2c20..b585a69 100644 --- a/runtime/go.go +++ b/runtime/go.go @@ -10,11 +10,17 @@ import ( func tagbodyGo(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { // args must be a instance of Cons, not Null, and ends with nil if !ilos.InstanceOf(args, class.Cons) || !UnsafeEndOfListIsNil(args) || UnsafeListLength(args) != 1 { // Checked at the head of test - return nil, instance.NewWrongNumberOfArguments(instance.NewSymbol("GO"), args) + return nil, instance.New(class.WrongNumberOfArguments, map[string]ilos.Instance{ + "FORM": instance.New(class.Symbol, "GO"), + "ARGUMENTS": args, + }) } car := instance.UnsafeCar(args) // Checked at the top of this function if _, ok := local.TagBodyTag.Get(car); !ok { - return nil, instance.NewSimpleError(instance.NewString("%v is not defined as the tag"), car) + return nil, instance.New(class.SimpleError, map[string]ilos.Instance{ + "FORMAT-STRING": instance.New(class.String, "%v is not defined as the tag"), + "FORMAT-ARGUMENTS": car, + }) } - return nil, instance.NewGo(car) + return nil, instance.New(class.Go, map[string]ilos.Instance{"TAG": car}) } diff --git a/runtime/ilos/class/builtinclass.go b/runtime/ilos/class/builtinclass.go new file mode 100644 index 0000000..9d26915 --- /dev/null +++ b/runtime/ilos/class/builtinclass.go @@ -0,0 +1,60 @@ +package class + +import "github.com/ta2gch/iris/runtime/ilos" + +type builtinclass struct { + parents []ilos.Class + slots []string + name string +} + +func (*builtinclass) Class() ilos.Class { + return BuiltInClass +} + +func (p *builtinclass) Parents() []ilos.Class { + return p.parents +} + +func (p *builtinclass) Slots() []string { + return p.slots +} + +func (i *builtinclass) GetSlotValue(key ilos.Instance, _ ilos.Class) (ilos.Instance, bool) { + return nil, false +} + +func (i *builtinclass) SetSlotValue(key ilos.Instance, value ilos.Instance, _ ilos.Class) bool { + return false +} + +func (p *builtinclass) String() string { + return p.name +} + +var SeriousCondition = &builtinclass{[]ilos.Class{Object}, []string{}, ""} +var Error = &builtinclass{[]ilos.Class{SeriousCondition}, []string{}, ""} +var ArithmeticError = &builtinclass{[]ilos.Class{Error}, []string{"OPERATION", "OPERANDS"}, ""} +var DivisionByZero = &builtinclass{[]ilos.Class{ArithmeticError}, []string{}, ""} +var FloatingPointOnderflow = &builtinclass{[]ilos.Class{ArithmeticError}, []string{}, ""} +var FloatingPointUnderflow = &builtinclass{[]ilos.Class{ArithmeticError}, []string{}, ""} +var ControlError = &builtinclass{[]ilos.Class{Error}, []string{}, ""} +var ParseError = &builtinclass{[]ilos.Class{Error}, []string{"STRING", "EXPECTED-CLASS"}, ""} +var ProgramError = &builtinclass{[]ilos.Class{Error}, []string{}, ""} +var DomainError = &builtinclass{[]ilos.Class{ProgramError}, []string{"OBJECT", "EXPECTED-CLASS"}, ""} +var UndefinedEntity = &builtinclass{[]ilos.Class{ProgramError}, []string{"NAME", "NAMESPACE"}, ""} +var UndefinedVariable = &builtinclass{[]ilos.Class{UndefinedEntity}, []string{}, ""} +var UndefinedFunction = &builtinclass{[]ilos.Class{UndefinedEntity}, []string{}, ""} +var SimpleError = &builtinclass{[]ilos.Class{Error}, []string{"FORMAT-STRING", "FORMAT-ARGUMENTS"}, ""} +var StreamError = &builtinclass{[]ilos.Class{Error}, []string{}, ""} +var EndOfStream = &builtinclass{[]ilos.Class{StreamError}, []string{}, ""} +var StorageExhausted = &builtinclass{[]ilos.Class{SeriousCondition}, []string{}, ""} +var StandardObject = &builtinclass{[]ilos.Class{Object}, []string{}, ""} +var Stream = &builtinclass{[]ilos.Class{Object}, []string{"STREAM"}, ""} + +// Implementation defined +var WrongNumberOfArguments = &builtinclass{[]ilos.Class{Error}, []string{"FORM", "ARGUMENTS"}, ""} +var Escape = &builtinclass{[]ilos.Class{Object}, []string{"TAG"}, ""} +var Throw = &builtinclass{[]ilos.Class{Escape}, []string{"OBJECT"}, ""} +var Go = &builtinclass{[]ilos.Class{Escape}, []string{}, ""} +var ReturnFrom = &builtinclass{[]ilos.Class{Escape}, []string{"OBJECT"}, ""} diff --git a/runtime/ilos/class/class.go b/runtime/ilos/class/class.go deleted file mode 100644 index cf7b2c3..0000000 --- a/runtime/ilos/class/class.go +++ /dev/null @@ -1,75 +0,0 @@ -package class - -import "github.com/ta2gch/iris/runtime/ilos" - -type builtinclass struct { - parents []ilos.Class - name string -} - -func (*builtinclass) Class() ilos.Class { - return BuiltInClass -} - -func (p *builtinclass) Parents() []ilos.Class { - return p.parents -} - -func (i *builtinclass) GetSlotValue(key ilos.Instance, _ ilos.Class) (ilos.Instance, bool) { - return nil, false -} - -func (i *builtinclass) SetSlotValue(key ilos.Instance, value ilos.Instance, _ ilos.Class) bool { - return false -} - -func (p *builtinclass) String() string { - return p.name -} - -var Object = &builtinclass{[]ilos.Class{}, ""} -var BuiltInClass = &builtinclass{[]ilos.Class{Object}, ""} -var StandardClass = &builtinclass{[]ilos.Class{Object}, ""} -var BasicArray = &builtinclass{[]ilos.Class{Object}, ""} -var BasicArrayStar = &builtinclass{[]ilos.Class{BasicArray}, ""} -var GeneralArrayStar = &builtinclass{[]ilos.Class{BasicArrayStar}, ""} -var BasicVector = &builtinclass{[]ilos.Class{BasicArray}, ""} -var GeneraVector = &builtinclass{[]ilos.Class{BasicVector}, ""} -var String = &builtinclass{[]ilos.Class{BasicVector}, ""} -var Character = &builtinclass{[]ilos.Class{Object}, ""} -var Function = &builtinclass{[]ilos.Class{Object}, ""} -var GenericFunction = &builtinclass{[]ilos.Class{Function}, ""} -var StandardGenericFunction = &builtinclass{[]ilos.Class{GenericFunction}, ""} -var List = &builtinclass{[]ilos.Class{Object}, ""} -var Cons = &builtinclass{[]ilos.Class{List}, ""} -var Null = &builtinclass{[]ilos.Class{List}, ""} -var Symbol = &builtinclass{[]ilos.Class{Object}, ""} -var Number = &builtinclass{[]ilos.Class{Object}, ""} -var Integer = &builtinclass{[]ilos.Class{Number}, ""} -var Float = &builtinclass{[]ilos.Class{Number}, ""} -var SeriousCondition = &builtinclass{[]ilos.Class{Object}, ""} -var Error = &builtinclass{[]ilos.Class{SeriousCondition}, ""} -var ArithmeticError = &builtinclass{[]ilos.Class{Error}, ""} -var DivisionByZero = &builtinclass{[]ilos.Class{ArithmeticError}, ""} -var FloatingPointOnderflow = &builtinclass{[]ilos.Class{ArithmeticError}, ""} -var FloatingPointUnderflow = &builtinclass{[]ilos.Class{ArithmeticError}, ""} -var ControlError = &builtinclass{[]ilos.Class{Error}, ""} -var ParseError = &builtinclass{[]ilos.Class{Error}, ""} -var ProgramError = &builtinclass{[]ilos.Class{Error}, ""} -var DomainError = &builtinclass{[]ilos.Class{ProgramError}, ""} -var UndefinedEntity = &builtinclass{[]ilos.Class{ProgramError}, ""} -var UndefinedVariable = &builtinclass{[]ilos.Class{UndefinedEntity}, ""} -var UndefinedFunction = &builtinclass{[]ilos.Class{UndefinedEntity}, ""} -var SimpleError = &builtinclass{[]ilos.Class{Error}, ""} -var StreamError = &builtinclass{[]ilos.Class{Error}, ""} -var EndOfStream = &builtinclass{[]ilos.Class{StreamError}, ""} -var StorageExhausted = &builtinclass{[]ilos.Class{SeriousCondition}, ""} -var StandardObject = &builtinclass{[]ilos.Class{Object}, ""} -var Stream = &builtinclass{[]ilos.Class{Object}, ""} - -// Implementation defined -var WrongNumberOfArguments = &builtinclass{[]ilos.Class{Error}, ""} -var Escape = &builtinclass{[]ilos.Class{Object}, ""} -var Throw = &builtinclass{[]ilos.Class{Escape}, ""} -var Go = &builtinclass{[]ilos.Class{Escape}, ""} -var ReturnFrom = &builtinclass{[]ilos.Class{Escape}, ""} diff --git a/runtime/ilos/class/primitiveclass.go b/runtime/ilos/class/primitiveclass.go new file mode 100644 index 0000000..0c65765 --- /dev/null +++ b/runtime/ilos/class/primitiveclass.go @@ -0,0 +1,53 @@ +package class + +import "github.com/ta2gch/iris/runtime/ilos" + +type primitiveclass struct { + parents []ilos.Class + name string +} + +func (*primitiveclass) Class() ilos.Class { + return BuiltInClass +} + +func (p *primitiveclass) Parents() []ilos.Class { + return p.parents +} + +func (p *primitiveclass) Slots() []string { + return []string{} +} + +func (i *primitiveclass) GetSlotValue(key ilos.Instance, _ ilos.Class) (ilos.Instance, bool) { + return nil, false +} + +func (i *primitiveclass) SetSlotValue(key ilos.Instance, value ilos.Instance, _ ilos.Class) bool { + return false +} + +func (p *primitiveclass) String() string { + return p.name +} + +var Object = &primitiveclass{[]ilos.Class{}, ""} +var BuiltInClass = &primitiveclass{[]ilos.Class{Object}, ""} +var StandardClass = &primitiveclass{[]ilos.Class{Object}, ""} +var BasicArray = &primitiveclass{[]ilos.Class{Object}, ""} +var BasicArrayStar = &primitiveclass{[]ilos.Class{BasicArray}, ""} +var GeneralArrayStar = &primitiveclass{[]ilos.Class{BasicArrayStar}, ""} +var BasicVector = &primitiveclass{[]ilos.Class{BasicArray}, ""} +var GeneraVector = &primitiveclass{[]ilos.Class{BasicVector}, ""} +var String = &primitiveclass{[]ilos.Class{BasicVector}, ""} +var Character = &primitiveclass{[]ilos.Class{Object}, ""} +var Function = &primitiveclass{[]ilos.Class{Object}, ""} +var GenericFunction = &primitiveclass{[]ilos.Class{Function}, ""} +var StandardGenericFunction = &primitiveclass{[]ilos.Class{GenericFunction}, ""} +var List = &primitiveclass{[]ilos.Class{Object}, ""} +var Cons = &primitiveclass{[]ilos.Class{List}, ""} +var Null = &primitiveclass{[]ilos.Class{List}, ""} +var Symbol = &primitiveclass{[]ilos.Class{Object}, ""} +var Number = &primitiveclass{[]ilos.Class{Object}, ""} +var Integer = &primitiveclass{[]ilos.Class{Number}, ""} +var Float = &primitiveclass{[]ilos.Class{Number}, ""} diff --git a/runtime/ilos/ilos.go b/runtime/ilos/ilos.go index 926fa4c..0e9c333 100644 --- a/runtime/ilos/ilos.go +++ b/runtime/ilos/ilos.go @@ -3,6 +3,7 @@ package ilos type Class interface { Class() Class Parents() []Class + Slots() []string GetSlotValue(Instance, Class) (Instance, bool) SetSlotValue(Instance, Instance, Class) bool String() string diff --git a/runtime/ilos/instance/extension.go b/runtime/ilos/instance/extension.go deleted file mode 100644 index a138646..0000000 --- a/runtime/ilos/instance/extension.go +++ /dev/null @@ -1,59 +0,0 @@ -package instance - -import ( - "github.com/ta2gch/iris/runtime/ilos" - "github.com/ta2gch/iris/runtime/ilos/class" -) - -func NewThrow(tag, object ilos.Instance) ilos.Instance { - i := new(instance) - i.class = class.Throw - i.slots = map[ilos.Instance]ilos.Instance{} - i.slots[NewSymbol("TAG")] = tag - i.slots[NewSymbol("OBJECT")] = object - return i -} - -func NewReturnFrom(tag, object ilos.Instance) ilos.Instance { - i := new(instance) - i.class = class.ReturnFrom - i.slots = map[ilos.Instance]ilos.Instance{} - i.slots[NewSymbol("TAG")] = tag - i.slots[NewSymbol("OBJECT")] = object - return i -} - -func NewGo(tag ilos.Instance) ilos.Instance { - i := new(instance) - i.class = class.Go - i.slots = map[ilos.Instance]ilos.Instance{} - i.slots[NewSymbol("TAG")] = tag - return i -} - -func NewWrongNumberOfArguments(function, arguments ilos.Instance) ilos.Instance { - i := new(instance) - i.class = class.WrongNumberOfArguments - i.slots = map[ilos.Instance]ilos.Instance{} - i.slots[NewSymbol("FORM")] = function - i.slots[NewSymbol("ARGUMENTS")] = arguments - return i -} - -func NewUndefinedFunction(name ilos.Instance) ilos.Instance { - i := new(instance) - i.class = class.UndefinedFunction - i.slots = map[ilos.Instance]ilos.Instance{} - i.slots[NewSymbol("NAME")] = name - i.slots[NewSymbol("NAMESPACE")] = NewSymbol("FUNCTION") - return i -} - -func NewUndefinedVariable(name ilos.Instance) ilos.Instance { - i := new(instance) - i.class = class.UndefinedVariable - i.slots = map[ilos.Instance]ilos.Instance{} - i.slots[NewSymbol("NAME")] = name - i.slots[NewSymbol("NAMESPACE")] = NewSymbol("VARIABLE") - return i -} diff --git a/runtime/ilos/instance/instance.go b/runtime/ilos/instance/instance.go index 74bbfea..21cecbc 100644 --- a/runtime/ilos/instance/instance.go +++ b/runtime/ilos/instance/instance.go @@ -3,17 +3,50 @@ package instance import ( "fmt" + "github.com/ta2gch/iris/runtime/environment" "github.com/ta2gch/iris/runtime/ilos" + "github.com/ta2gch/iris/runtime/ilos/class" ) // // instance // +func New(c ilos.Class, s ...interface{}) ilos.Instance { + switch c { + case class.Integer: + return NewInteger(s[0].(int)) + case class.Float: + return NewFloat(s[0].(float64)) + case class.String: + return NewString(s[0].(string)) + case class.Symbol: + return NewSymbol(s[0].(string)) + case class.Character: + return NewCharacter(s[0].(rune)) + case class.Function: + return NewFunction(s[0].(func(ilos.Instance, *environment.Environment, *environment.Environment) (ilos.Instance, ilos.Instance))) + case class.Cons: + return NewCons(s[0].(ilos.Instance), s[1].(ilos.Instance)) + case class.Null: + return NewNull() + default: + p := []ilos.Instance{} + for _, q := range c.Parents() { + p = append(p, New(q, s...)) + } + t := map[string]ilos.Instance{} + for _, n := range c.Slots() { + t[n] = s[0].(map[string]ilos.Instance)[n] + } + return &instance{c, p, t} + } +} + type instance struct { class ilos.Class supers []ilos.Instance - slots map[ilos.Instance]ilos.Instance + slots map[string]ilos.Instance } func (i *instance) Class() ilos.Class { @@ -21,7 +54,7 @@ func (i *instance) Class() ilos.Class { } func (i *instance) GetSlotValue(key ilos.Instance, class ilos.Class) (ilos.Instance, bool) { - if v, ok := i.slots[key]; ok && i.class == class { + if v, ok := i.slots[string(key.(Symbol))]; ok && i.class == class { return v, ok } for _, s := range i.supers { @@ -33,8 +66,8 @@ func (i *instance) GetSlotValue(key ilos.Instance, class ilos.Class) (ilos.Insta } func (i *instance) SetSlotValue(key ilos.Instance, value ilos.Instance, class ilos.Class) bool { - if _, ok := i.slots[key]; ok && i.class == class { - i.slots[key] = value + if _, ok := i.slots[string(key.(Symbol))]; ok && i.class == class { + i.slots[string(key.(Symbol))] = value return true } for _, s := range i.supers { diff --git a/runtime/ilos/instance/serious-error.go b/runtime/ilos/instance/serious-error.go deleted file mode 100644 index abcb247..0000000 --- a/runtime/ilos/instance/serious-error.go +++ /dev/null @@ -1,63 +0,0 @@ -package instance - -import ( - "github.com/ta2gch/iris/runtime/ilos" - "github.com/ta2gch/iris/runtime/ilos/class" -) - -// -// ParseError -// - -func NewArithmeticError(operation, operands ilos.Instance) ilos.Instance { - i := new(instance) - i.class = class.ArithmeticError - i.slots = map[ilos.Instance]ilos.Instance{} - i.slots[NewSymbol("OPERATION")] = operation - i.slots[NewSymbol("OPERANDS")] = operands - return i -} - -func NewDomainError(object, expectedClass ilos.Instance) ilos.Instance { - i := new(instance) - i.class = class.DomainError - i.slots = map[ilos.Instance]ilos.Instance{} - i.slots[NewSymbol("STRING")] = object - i.slots[NewSymbol("EXPECTED-CLASS")] = expectedClass - return i -} - -func NewParseError(str, expectedClass ilos.Instance) ilos.Instance { - i := new(instance) - i.class = class.ParseError - i.slots = map[ilos.Instance]ilos.Instance{} - i.slots[NewSymbol("STRING")] = str - i.slots[NewSymbol("EXPECTED-CLASS")] = expectedClass - return i -} - -func NewSimpleError(formatString, formatArguments ilos.Instance) ilos.Instance { - i := new(instance) - i.class = class.SimpleError - i.slots = map[ilos.Instance]ilos.Instance{} - i.slots[NewSymbol("FORMAT-STRING")] = formatString - i.slots[NewSymbol("FORMAT-ARGUMENTS")] = formatArguments - return i -} - -func NewStreamError(stream ilos.Instance) ilos.Instance { - i := new(instance) - i.class = class.StreamError - i.slots = map[ilos.Instance]ilos.Instance{} - i.slots[NewSymbol("STREAM")] = stream - return i -} - -func NewUndefinedEntityError(name, namespace ilos.Instance) ilos.Instance { - i := new(instance) - i.class = class.UndefinedEntity - i.slots = map[ilos.Instance]ilos.Instance{} - i.slots[NewSymbol("NAME")] = name - i.slots[NewSymbol("NAMESPACE")] = namespace - return i -} diff --git a/runtime/lambda.go b/runtime/lambda.go index 26a8571..17c837a 100644 --- a/runtime/lambda.go +++ b/runtime/lambda.go @@ -10,16 +10,19 @@ import ( func lambda(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { // args must be a instance of Cons, not Null, and ends with nil if !ilos.InstanceOf(args, class.Cons) || !UnsafeEndOfListIsNil(args) { // Checked at the head of test - return nil, instance.NewWrongNumberOfArguments(instance.NewSymbol("LAMBDA"), args) + return nil, instance.New(class.WrongNumberOfArguments, map[string]ilos.Instance{ + "FORM": instance.New(class.Symbol, "LAMBDA"), + "ARGUMENTS": args, + }) } lambdaList := instance.UnsafeCar(args) // lambda-list must be a instance of list and ends with nil if !ilos.InstanceOf(lambdaList, class.List) || !UnsafeEndOfListIsNil(lambdaList) { // Checked at the head of test - return nil, instance.NewParseError(lambdaList, class.List) + return nil, instance.New(class.ParseError, lambdaList, class.List) } forms := instance.UnsafeCdr(args) // Checked at the top of this function. (EndOfListIsNil) lexical := local - return instance.NewFunction(func(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { + return instance.New(class.Function, func(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { local.BlockTag = append(lexical.BlockTag, local.BlockTag...) local.TagBodyTag = append(lexical.TagBodyTag, local.TagBodyTag...) local.ThrowTag = append(lexical.ThrowTag, local.ThrowTag...) @@ -29,14 +32,17 @@ func lambda(args ilos.Instance, local *env.Environment, global *env.Environment) local.DynamicVariable = append(lexical.DynamicVariable, local.DynamicVariable...) // args must be a instance of list and end with nil if !ilos.InstanceOf(args, class.List) || !UnsafeEndOfListIsNil(args) { // Checked at the head of test - return nil, instance.NewParseError(args, class.List) + return nil, instance.New(class.DomainError, map[string]ilos.Instance{ + "OBJECT": args, + "EXPECTED-CLASS": class.List, + }) } cdr := lambdaList ok := false for ilos.InstanceOf(cdr, class.Cons) { car := instance.UnsafeCar(cdr) // Checked at the top of this loop. cdr = instance.UnsafeCdr(cdr) // Checked at the top of this loop. - if car == instance.NewSymbol(":REST") || car == instance.NewSymbol("&REST") { + if car == instance.New(class.Symbol, ":REST") || car == instance.New(class.Symbol, "&REST") { // fargs has only one symbol after &rest or :rest symbol. if ilos.InstanceOf(cdr, class.List) && UnsafeListLength(cdr) == 1 { // Checked at the head of test // If fargs has :rest or &rest symbol, The length of aargs must be greater than or equal to 'the length of fargs' - 2. @@ -46,10 +52,16 @@ func lambda(args ilos.Instance, local *env.Environment, global *env.Environment) ok = true break } else { - return nil, instance.NewWrongNumberOfArguments(instance.NewSymbol("ANONYMOUS-FUNCTION"), args) + return nil, instance.New(class.WrongNumberOfArguments, map[string]ilos.Instance{ + "FORM": instance.New(class.Symbol, "ANONYMOUS-FUNCTION"), + "ARGUMENTS": args, + }) } } else { - return nil, instance.NewWrongNumberOfArguments(instance.NewSymbol("LAMBDA"), lambdaList) + return nil, instance.New(class.WrongNumberOfArguments, map[string]ilos.Instance{ + "FORM": instance.New(class.Symbol, "LAMBDA"), + "ARGUMENTS": lambdaList, + }) } } } @@ -57,14 +69,17 @@ func lambda(args ilos.Instance, local *env.Environment, global *env.Environment) // aargs is a instance of list and ends nil becauseof the checking at this function. // lambda-list is a instance of list and ends nil becauseof the checking at the function, lambda. if !ok && UnsafeListLength(lambdaList) != UnsafeListLength(args) { - return nil, instance.NewWrongNumberOfArguments(instance.NewSymbol("ANONYMOUS-FUNCTION"), args) + return nil, instance.New(class.WrongNumberOfArguments, map[string]ilos.Instance{ + "FORM": instance.New(class.Symbol, "ANONYMOUS-FUNCTION"), + "ARGUMENTS": args, + }) } fargs := lambdaList aargs := args for ilos.InstanceOf(fargs, class.Cons) && ilos.InstanceOf(aargs, class.Cons) { key := instance.UnsafeCar(fargs) // Checked at the top of this loop. value := instance.UnsafeCar(aargs) // Checked at the top of this loop. - if key == instance.NewSymbol(":REST") || key == instance.NewSymbol("&REST") { + if key == instance.New(class.Symbol, ":REST") || key == instance.New(class.Symbol, "&REST") { cadr := instance.UnsafeCar(instance.UnsafeCdr(fargs)) // Checked before type checking secion local.Variable.Define(cadr, aargs) break @@ -74,7 +89,7 @@ func lambda(args ilos.Instance, local *env.Environment, global *env.Environment) aargs = instance.UnsafeCdr(aargs) // Checked at the top of this loop } body := forms - ret := instance.NewNull() + ret := instance.New(class.Null) var err ilos.Instance for ilos.InstanceOf(body, class.Cons) { exp := instance.UnsafeCar(body) // Checked at the top of this loop diff --git a/runtime/quote.go b/runtime/quote.go index 2a82c9b..b0a954b 100644 --- a/runtime/quote.go +++ b/runtime/quote.go @@ -10,7 +10,10 @@ import ( func quote(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { // args must be a instance of Cons, not Null, and ends with nil if !ilos.InstanceOf(args, class.Cons) || !UnsafeEndOfListIsNil(args) || UnsafeListLength(args) != 1 { // Checked at the head of test - return nil, instance.NewWrongNumberOfArguments(instance.NewSymbol("QUOTE"), args) + return nil, instance.New(class.WrongNumberOfArguments, map[string]ilos.Instance{ + "FORM": instance.New(class.Symbol, "QUOTE"), + "ARGUMENTS": args, + }) } return instance.UnsafeCar(args), nil } diff --git a/runtime/return-from.go b/runtime/return-from.go index 8a6628f..2fe8e0c 100644 --- a/runtime/return-from.go +++ b/runtime/return-from.go @@ -10,7 +10,10 @@ import ( func returnFrom(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { // args must be a instance of Cons, not Null, and ends with nil if !ilos.InstanceOf(args, class.Cons) || !UnsafeEndOfListIsNil(args) || UnsafeListLength(args) != 2 { // Checked at the head of test - return nil, instance.NewWrongNumberOfArguments(instance.NewSymbol("RETURN-FROM"), args) + return nil, instance.New(class.WrongNumberOfArguments, map[string]ilos.Instance{ + "FORM": instance.New(class.Symbol, "RETURN-FROM"), + "ARGUMENTS": args, + }) } car := instance.UnsafeCar(args) // Checked at the top of this function tag, err := Eval(car, local, global) @@ -18,7 +21,10 @@ func returnFrom(args ilos.Instance, local *env.Environment, global *env.Environm return nil, err } if ilos.InstanceOf(tag, class.Number) || ilos.InstanceOf(tag, class.Character) { - return nil, instance.NewDomainError(tag, class.Object) + return nil, instance.New(class.DomainError, map[string]ilos.Instance{ + "OBJECT": tag, + "EXPECTED-CLASS": class.Object, + }) } cadr := instance.UnsafeCar(instance.UnsafeCdr(args)) // Checked length is 2 at the top of this function object, err := Eval(cadr, local, global) @@ -26,7 +32,13 @@ func returnFrom(args ilos.Instance, local *env.Environment, global *env.Environm return nil, err } if _, ok := local.BlockTag.Get(tag); !ok { - return nil, instance.NewSimpleError(instance.NewString("%v is not defined as the tag"), car) + return nil, instance.New(class.SimpleError, map[string]ilos.Instance{ + "FORMAT-STRING": instance.New(class.String, "%v is not defined as the tag"), + "FORMAT-ARGUMENTS": car, + }) } - return nil, instance.NewReturnFrom(tag, object) + return nil, instance.New(class.ReturnFrom, map[string]ilos.Instance{ + "TAG": tag, + "OBJECT": object, + }) } diff --git a/runtime/tagbody.go b/runtime/tagbody.go index aeb7a19..fcdd463 100644 --- a/runtime/tagbody.go +++ b/runtime/tagbody.go @@ -10,7 +10,10 @@ import ( func tagbody(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { // args must be a instance of Cons, not Null, and ends with nil if !ilos.InstanceOf(args, class.Cons) || !UnsafeEndOfListIsNil(args) || UnsafeListLength(args) < 2 { // Checked at the head of test - return nil, instance.NewWrongNumberOfArguments(instance.NewSymbol("TAGBODY"), args) + return nil, instance.New(class.WrongNumberOfArguments, map[string]ilos.Instance{ + "FORM": instance.New(class.Symbol, "TAGBODY"), + "ARGUMENTS": args, + }) } localTags := []ilos.Instance{} cdr := args // Checked at the top of this function @@ -32,7 +35,7 @@ func tagbody(args ilos.Instance, local *env.Environment, global *env.Environment if fail != nil { tag: if ilos.InstanceOf(fail, class.Go) { - tag, _ := fail.GetSlotValue(instance.NewSymbol("TAG"), class.Go) // Checked at the top of this loop + tag, _ := fail.GetSlotValue(instance.New(class.Symbol, "TAG"), class.Escape) // Checked at the top of this loop found := false for _, localTag := range localTags { if tag == localTag { @@ -63,5 +66,5 @@ func tagbody(args ilos.Instance, local *env.Environment, global *env.Environment } cdr = cddr } - return instance.NewNull(), nil + return instance.New(class.Null), nil } diff --git a/runtime/throw.go b/runtime/throw.go index b0f4a23..81c24b8 100644 --- a/runtime/throw.go +++ b/runtime/throw.go @@ -10,7 +10,10 @@ import ( func throw(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { // args must be a instance of Cons, not Null, and ends with nil if !ilos.InstanceOf(args, class.Cons) || !UnsafeEndOfListIsNil(args) || UnsafeListLength(args) != 2 { // Checked at the head of test - return nil, instance.NewWrongNumberOfArguments(instance.NewSymbol("THROW"), args) + return nil, instance.New(class.WrongNumberOfArguments, map[string]ilos.Instance{ + "FORM": instance.New(class.Symbol, "THROW"), + "ARGUMENTS": args, + }) } car := instance.UnsafeCar(args) // Checked at the top of this function tag, err := Eval(car, local, global) @@ -18,7 +21,10 @@ func throw(args ilos.Instance, local *env.Environment, global *env.Environment) return nil, err } if ilos.InstanceOf(tag, class.Number) || ilos.InstanceOf(tag, class.Character) { - return nil, instance.NewDomainError(tag, class.Object) + return nil, instance.New(class.DomainError, map[string]ilos.Instance{ + "OBJECT": tag, + "EXPECTED-CLASS": class.Object, + }) } cadr := instance.UnsafeCar(instance.UnsafeCdr(args)) // Checked length is 2 at the top of this function object, err := Eval(cadr, local, global) @@ -26,7 +32,13 @@ func throw(args ilos.Instance, local *env.Environment, global *env.Environment) return nil, err } if _, ok := local.ThrowTag.Get(tag); !ok { - return nil, instance.NewSimpleError(instance.NewString("%v is not defined as the tag"), car) + return nil, instance.New(class.SimpleError, map[string]ilos.Instance{ + "FORMAT-STRING": instance.New(class.String, "%v is not defined as the tag"), + "FORMAT-ARGUMENTS": car, + }) } - return nil, instance.NewThrow(tag, object) + return nil, instance.New(class.Throw, map[string]ilos.Instance{ + "TAG": tag, + "OBJECT": object, + }) } From 7678af277384b2dedf3f0ff51f7d87f042a7afcc Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Wed, 9 Aug 2017 22:12:26 +0900 Subject: [PATCH 109/228] Rename TagClass's names --- runtime/block.go | 4 ++-- runtime/catch.go | 4 ++-- runtime/go.go | 2 +- runtime/ilos/class/builtinclass.go | 6 +++--- runtime/return-from.go | 2 +- runtime/tagbody.go | 2 +- runtime/throw.go | 2 +- 7 files changed, 11 insertions(+), 11 deletions(-) diff --git a/runtime/block.go b/runtime/block.go index 99b3eea..7c0b8db 100644 --- a/runtime/block.go +++ b/runtime/block.go @@ -38,10 +38,10 @@ func block(args ilos.Instance, local *env.Environment, global *env.Environment) cddr := instance.UnsafeCdr(cdr) // Checked at the top of this loop sucess, fail = Eval(cadr, local, global) if fail != nil { - if ilos.InstanceOf(fail, class.ReturnFrom) { + if ilos.InstanceOf(fail, class.BlockTag) { tag, _ := fail.GetSlotValue(instance.New(class.Symbol, "TAG"), class.Escape) // Checked at the head of this condition if car == tag { - obj, _ := fail.GetSlotValue(instance.New(class.Symbol, "OBJECT"), class.ReturnFrom) // Checked at the head of this condition + obj, _ := fail.GetSlotValue(instance.New(class.Symbol, "OBJECT"), class.BlockTag) // Checked at the head of this condition return obj, nil } } diff --git a/runtime/catch.go b/runtime/catch.go index 35707cd..02fdbb6 100644 --- a/runtime/catch.go +++ b/runtime/catch.go @@ -30,10 +30,10 @@ func catch(args ilos.Instance, local *env.Environment, global *env.Environment) cddr := instance.UnsafeCdr(cdr) // Checked at the top of this loop sucess, fail = Eval(cadr, local, global) if fail != nil { - if ilos.InstanceOf(fail, class.Throw) { + if ilos.InstanceOf(fail, class.CatchTag) { tag, _ := fail.GetSlotValue(instance.New(class.Symbol, "TAG"), class.Escape) // Checked at the head of this condition if car == tag { - obj, _ := fail.GetSlotValue(instance.New(class.Symbol, "OBJECT"), class.Throw) // Checked at the head of this condition + obj, _ := fail.GetSlotValue(instance.New(class.Symbol, "OBJECT"), class.CatchTag) // Checked at the head of this condition return obj, nil } } diff --git a/runtime/go.go b/runtime/go.go index b585a69..50d357c 100644 --- a/runtime/go.go +++ b/runtime/go.go @@ -22,5 +22,5 @@ func tagbodyGo(args ilos.Instance, local *env.Environment, global *env.Environme "FORMAT-ARGUMENTS": car, }) } - return nil, instance.New(class.Go, map[string]ilos.Instance{"TAG": car}) + return nil, instance.New(class.TagbodyTag, map[string]ilos.Instance{"TAG": car}) } diff --git a/runtime/ilos/class/builtinclass.go b/runtime/ilos/class/builtinclass.go index 9d26915..fcc3148 100644 --- a/runtime/ilos/class/builtinclass.go +++ b/runtime/ilos/class/builtinclass.go @@ -55,6 +55,6 @@ var Stream = &builtinclass{[]ilos.Class{Object}, []string{"STREAM"}, ""} // Implementation defined var WrongNumberOfArguments = &builtinclass{[]ilos.Class{Error}, []string{"FORM", "ARGUMENTS"}, ""} var Escape = &builtinclass{[]ilos.Class{Object}, []string{"TAG"}, ""} -var Throw = &builtinclass{[]ilos.Class{Escape}, []string{"OBJECT"}, ""} -var Go = &builtinclass{[]ilos.Class{Escape}, []string{}, ""} -var ReturnFrom = &builtinclass{[]ilos.Class{Escape}, []string{"OBJECT"}, ""} +var CatchTag = &builtinclass{[]ilos.Class{Escape}, []string{"OBJECT"}, ""} +var TagbodyTag = &builtinclass{[]ilos.Class{Escape}, []string{}, ""} +var BlockTag = &builtinclass{[]ilos.Class{Escape}, []string{"OBJECT"}, ""} diff --git a/runtime/return-from.go b/runtime/return-from.go index 2fe8e0c..83e46df 100644 --- a/runtime/return-from.go +++ b/runtime/return-from.go @@ -37,7 +37,7 @@ func returnFrom(args ilos.Instance, local *env.Environment, global *env.Environm "FORMAT-ARGUMENTS": car, }) } - return nil, instance.New(class.ReturnFrom, map[string]ilos.Instance{ + return nil, instance.New(class.BlockTag, map[string]ilos.Instance{ "TAG": tag, "OBJECT": object, }) diff --git a/runtime/tagbody.go b/runtime/tagbody.go index fcdd463..30c82ec 100644 --- a/runtime/tagbody.go +++ b/runtime/tagbody.go @@ -34,7 +34,7 @@ func tagbody(args ilos.Instance, local *env.Environment, global *env.Environment _, fail := Eval(cadr, local, global) if fail != nil { tag: - if ilos.InstanceOf(fail, class.Go) { + if ilos.InstanceOf(fail, class.TagbodyTag) { tag, _ := fail.GetSlotValue(instance.New(class.Symbol, "TAG"), class.Escape) // Checked at the top of this loop found := false for _, localTag := range localTags { diff --git a/runtime/throw.go b/runtime/throw.go index 81c24b8..8e63731 100644 --- a/runtime/throw.go +++ b/runtime/throw.go @@ -37,7 +37,7 @@ func throw(args ilos.Instance, local *env.Environment, global *env.Environment) "FORMAT-ARGUMENTS": car, }) } - return nil, instance.New(class.Throw, map[string]ilos.Instance{ + return nil, instance.New(class.CatchTag, map[string]ilos.Instance{ "TAG": tag, "OBJECT": object, }) From 43bb94e5510a418ab68a73df974c93fcdb51255f Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Wed, 9 Aug 2017 22:37:09 +0900 Subject: [PATCH 110/228] Changed the oder of arguments in instance.Of --- runtime/block.go | 8 ++-- runtime/catch.go | 8 ++-- runtime/eval.go | 16 +++---- runtime/function.go | 4 +- runtime/go.go | 2 +- runtime/ilos/class/builtinclass.go | 27 ----------- runtime/ilos/class/class.go | 72 ++++++++++++++++++++++++++++ runtime/ilos/class/primitiveclass.go | 21 -------- runtime/ilos/instance/basic-array.go | 8 ++-- runtime/ilos/instance/instance.go | 7 +++ runtime/ilos/instance/list.go | 4 +- runtime/lambda.go | 14 +++--- runtime/quote.go | 2 +- runtime/return-from.go | 4 +- runtime/tagbody.go | 16 +++---- runtime/throw.go | 4 +- runtime/util.go | 6 +-- 17 files changed, 127 insertions(+), 96 deletions(-) create mode 100644 runtime/ilos/class/class.go diff --git a/runtime/block.go b/runtime/block.go index 7c0b8db..2bf6930 100644 --- a/runtime/block.go +++ b/runtime/block.go @@ -17,7 +17,7 @@ import ( // According to this, the scope of name is dynamic. I guess it should be a static. func block(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { // args must be a instance of Cons, not Null, and ends with nil - if !ilos.InstanceOf(args, class.Cons) || !UnsafeEndOfListIsNil(args) || UnsafeListLength(args) < 2 { // Checked at the head of test + if !instance.Of(class.Cons, args) || !UnsafeEndOfListIsNil(args) || UnsafeListLength(args) < 2 { // Checked at the head of test return nil, instance.New(class.WrongNumberOfArguments, map[string]ilos.Instance{ "FORM": instance.New(class.Symbol, "BLOCK"), "ARGUMENTS": args, @@ -27,18 +27,18 @@ func block(args ilos.Instance, local *env.Environment, global *env.Environment) if err != nil { return nil, err } - if ilos.InstanceOf(car, class.Number) || ilos.InstanceOf(car, class.Character) { + if instance.Of(class.Number, car) || instance.Of(class.Character, car) { return nil, instance.New(class.DomainError, car, class.Object) } local.BlockTag.Define(car, car) cdr := instance.UnsafeCdr(args) // Checked at the top of this function var sucess, fail ilos.Instance - for ilos.InstanceOf(cdr, class.Cons) { + for instance.Of(class.Cons, cdr) { cadr := instance.UnsafeCar(cdr) // Checked at the top of this loop cddr := instance.UnsafeCdr(cdr) // Checked at the top of this loop sucess, fail = Eval(cadr, local, global) if fail != nil { - if ilos.InstanceOf(fail, class.BlockTag) { + if instance.Of(class.BlockTag, fail) { tag, _ := fail.GetSlotValue(instance.New(class.Symbol, "TAG"), class.Escape) // Checked at the head of this condition if car == tag { obj, _ := fail.GetSlotValue(instance.New(class.Symbol, "OBJECT"), class.BlockTag) // Checked at the head of this condition diff --git a/runtime/catch.go b/runtime/catch.go index 02fdbb6..2c9a238 100644 --- a/runtime/catch.go +++ b/runtime/catch.go @@ -9,7 +9,7 @@ import ( func catch(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { // args must be a instance of Cons, not Null, and ends with nil - if !ilos.InstanceOf(args, class.Cons) || !UnsafeEndOfListIsNil(args) || UnsafeListLength(args) < 2 { // Checked at the head of test + if !instance.Of(class.Cons, args) || !UnsafeEndOfListIsNil(args) || UnsafeListLength(args) < 2 { // Checked at the head of test return nil, instance.New(class.WrongNumberOfArguments, map[string]ilos.Instance{ "FORM": instance.New(class.Symbol, "CATCH"), "ARGUMENTS": args, @@ -19,18 +19,18 @@ func catch(args ilos.Instance, local *env.Environment, global *env.Environment) if err != nil { return nil, err } - if ilos.InstanceOf(car, class.Number) || ilos.InstanceOf(car, class.Character) { + if instance.Of(class.Number, car) || instance.Of(class.Character, car) { return nil, instance.New(class.DomainError, car, class.Object) } local.ThrowTag.Define(car, car) cdr := instance.UnsafeCdr(args) // Checked at the top of this function var sucess, fail ilos.Instance - for ilos.InstanceOf(cdr, class.Cons) { + for instance.Of(class.Cons, cdr) { cadr := instance.UnsafeCar(cdr) // Checked at the top of this loop cddr := instance.UnsafeCdr(cdr) // Checked at the top of this loop sucess, fail = Eval(cadr, local, global) if fail != nil { - if ilos.InstanceOf(fail, class.CatchTag) { + if instance.Of(class.CatchTag, fail) { tag, _ := fail.GetSlotValue(instance.New(class.Symbol, "TAG"), class.Escape) // Checked at the head of this condition if car == tag { obj, _ := fail.GetSlotValue(instance.New(class.Symbol, "OBJECT"), class.CatchTag) // Checked at the head of this condition diff --git a/runtime/eval.go b/runtime/eval.go index fbfdc8e..b49864f 100644 --- a/runtime/eval.go +++ b/runtime/eval.go @@ -9,11 +9,11 @@ import ( func evalArguments(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { // if args ends here - if ilos.InstanceOf(args, class.Null) { + if instance.Of(class.Null, args) { return instance.New(class.Null), nil } // args must be a instance of list and ends with nil - if !ilos.InstanceOf(args, class.List) || !UnsafeEndOfListIsNil(args) { + if !instance.Of(class.List, args) || !UnsafeEndOfListIsNil(args) { return nil, instance.New(class.ParseError, map[string]ilos.Instance{ "STRING": args, "EXPECTED-CLASS": class.List, @@ -35,7 +35,7 @@ func evalArguments(args ilos.Instance, local *env.Environment, global *env.Envir func evalFunction(obj ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { // obj, function call form, must be a instance of Cons, NOT Null, and ends with nil - if !ilos.InstanceOf(obj, class.Cons) || !UnsafeEndOfListIsNil(obj) { + if !instance.Of(class.Cons, obj) || !UnsafeEndOfListIsNil(obj) { return nil, instance.New(class.ParseError, map[string]ilos.Instance{ "STRING": obj, "EXPECTED-CLASS": class.Cons, @@ -48,7 +48,7 @@ func evalFunction(obj ilos.Instance, local *env.Environment, global *env.Environ cdr := instance.UnsafeCdr(obj) // Checked at the top of this function // eval if lambda form - if ilos.InstanceOf(car, class.Cons) { + if instance.Of(class.Cons, car) { caar := instance.UnsafeCar(car) // Checked at the top of this sentence if caar == instance.New(class.Symbol, "LAMBDA") { fun, err := Eval(car, local, global) @@ -71,7 +71,7 @@ func evalFunction(obj ilos.Instance, local *env.Environment, global *env.Environ } } // if function is not a lambda special form, first element must be a symbol - if !ilos.InstanceOf(car, class.Symbol) { + if !instance.Of(class.Symbol, car) { return nil, instance.New(class.DomainError, map[string]ilos.Instance{ "OBJECT": car, "EXPECTED-CLASS": class.Symbol, @@ -122,10 +122,10 @@ func evalFunction(obj ilos.Instance, local *env.Environment, global *env.Environ // Eval evaluates any classs func Eval(obj ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { - if ilos.InstanceOf(obj, class.Null) { + if instance.Of(class.Null, obj) { return instance.New(class.Null), nil } - if ilos.InstanceOf(obj, class.Symbol) { + if instance.Of(class.Symbol, obj) { if val, ok := local.Variable.Get(obj); ok { return val, nil } @@ -137,7 +137,7 @@ func Eval(obj ilos.Instance, local *env.Environment, global *env.Environment) (i "NAMESPACE": instance.New(class.Symbol, "VARIABLE"), }) } - if ilos.InstanceOf(obj, class.Cons) { + if instance.Of(class.Cons, obj) { ret, err := evalFunction(obj, local, global) if err != nil { return nil, err diff --git a/runtime/function.go b/runtime/function.go index e755838..3a9cfbd 100644 --- a/runtime/function.go +++ b/runtime/function.go @@ -9,7 +9,7 @@ import ( func function(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { // args must be a instance of Cons, not Null, and ends with nil - if !ilos.InstanceOf(args, class.Cons) || !UnsafeEndOfListIsNil(args) || UnsafeListLength(args) != 1 { // Checked at the head of test + if !instance.Of(class.Cons, args) || !UnsafeEndOfListIsNil(args) || UnsafeListLength(args) != 1 { // Checked at the head of test return nil, instance.New(class.WrongNumberOfArguments, map[string]ilos.Instance{ "FORM": instance.New(class.Symbol, "FUNCTION"), "ARGUMENTS": args, @@ -17,7 +17,7 @@ func function(args ilos.Instance, local *env.Environment, global *env.Environmen } car := instance.UnsafeCar(args) // Checked at the top of this function // car must be a symbol - if !ilos.InstanceOf(car, class.Symbol) { + if !instance.Of(class.Symbol, car) { return nil, instance.New(class.DomainError, map[string]ilos.Instance{ "OBJECT": car, "EXPECTED-CLASS": class.Symbol, diff --git a/runtime/go.go b/runtime/go.go index 50d357c..2b45a48 100644 --- a/runtime/go.go +++ b/runtime/go.go @@ -9,7 +9,7 @@ import ( func tagbodyGo(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { // args must be a instance of Cons, not Null, and ends with nil - if !ilos.InstanceOf(args, class.Cons) || !UnsafeEndOfListIsNil(args) || UnsafeListLength(args) != 1 { // Checked at the head of test + if !instance.Of(class.Cons, args) || !UnsafeEndOfListIsNil(args) || UnsafeListLength(args) != 1 { // Checked at the head of test return nil, instance.New(class.WrongNumberOfArguments, map[string]ilos.Instance{ "FORM": instance.New(class.Symbol, "GO"), "ARGUMENTS": args, diff --git a/runtime/ilos/class/builtinclass.go b/runtime/ilos/class/builtinclass.go index fcc3148..10ba3c4 100644 --- a/runtime/ilos/class/builtinclass.go +++ b/runtime/ilos/class/builtinclass.go @@ -31,30 +31,3 @@ func (i *builtinclass) SetSlotValue(key ilos.Instance, value ilos.Instance, _ il func (p *builtinclass) String() string { return p.name } - -var SeriousCondition = &builtinclass{[]ilos.Class{Object}, []string{}, ""} -var Error = &builtinclass{[]ilos.Class{SeriousCondition}, []string{}, ""} -var ArithmeticError = &builtinclass{[]ilos.Class{Error}, []string{"OPERATION", "OPERANDS"}, ""} -var DivisionByZero = &builtinclass{[]ilos.Class{ArithmeticError}, []string{}, ""} -var FloatingPointOnderflow = &builtinclass{[]ilos.Class{ArithmeticError}, []string{}, ""} -var FloatingPointUnderflow = &builtinclass{[]ilos.Class{ArithmeticError}, []string{}, ""} -var ControlError = &builtinclass{[]ilos.Class{Error}, []string{}, ""} -var ParseError = &builtinclass{[]ilos.Class{Error}, []string{"STRING", "EXPECTED-CLASS"}, ""} -var ProgramError = &builtinclass{[]ilos.Class{Error}, []string{}, ""} -var DomainError = &builtinclass{[]ilos.Class{ProgramError}, []string{"OBJECT", "EXPECTED-CLASS"}, ""} -var UndefinedEntity = &builtinclass{[]ilos.Class{ProgramError}, []string{"NAME", "NAMESPACE"}, ""} -var UndefinedVariable = &builtinclass{[]ilos.Class{UndefinedEntity}, []string{}, ""} -var UndefinedFunction = &builtinclass{[]ilos.Class{UndefinedEntity}, []string{}, ""} -var SimpleError = &builtinclass{[]ilos.Class{Error}, []string{"FORMAT-STRING", "FORMAT-ARGUMENTS"}, ""} -var StreamError = &builtinclass{[]ilos.Class{Error}, []string{}, ""} -var EndOfStream = &builtinclass{[]ilos.Class{StreamError}, []string{}, ""} -var StorageExhausted = &builtinclass{[]ilos.Class{SeriousCondition}, []string{}, ""} -var StandardObject = &builtinclass{[]ilos.Class{Object}, []string{}, ""} -var Stream = &builtinclass{[]ilos.Class{Object}, []string{"STREAM"}, ""} - -// Implementation defined -var WrongNumberOfArguments = &builtinclass{[]ilos.Class{Error}, []string{"FORM", "ARGUMENTS"}, ""} -var Escape = &builtinclass{[]ilos.Class{Object}, []string{"TAG"}, ""} -var CatchTag = &builtinclass{[]ilos.Class{Escape}, []string{"OBJECT"}, ""} -var TagbodyTag = &builtinclass{[]ilos.Class{Escape}, []string{}, ""} -var BlockTag = &builtinclass{[]ilos.Class{Escape}, []string{"OBJECT"}, ""} diff --git a/runtime/ilos/class/class.go b/runtime/ilos/class/class.go new file mode 100644 index 0000000..400a708 --- /dev/null +++ b/runtime/ilos/class/class.go @@ -0,0 +1,72 @@ +package class + +import "github.com/ta2gch/iris/runtime/ilos" + +func Is(c, p ilos.Class) bool { + var sub func(c, p ilos.Class) bool + sub = func(c, p ilos.Class) bool { + if c == p { + return true + } + for _, d := range c.Parents() { + if sub(d, p) { + return true + } + } + return false + } + for _, d := range c.Parents() { + if sub(d, p) { + return true + } + } + return false +} + +var Object = &primitiveclass{[]ilos.Class{}, ""} +var BuiltInClass = &primitiveclass{[]ilos.Class{Object}, ""} +var StandardClass = &primitiveclass{[]ilos.Class{Object}, ""} +var BasicArray = &primitiveclass{[]ilos.Class{Object}, ""} +var BasicArrayStar = &primitiveclass{[]ilos.Class{BasicArray}, ""} +var GeneralArrayStar = &primitiveclass{[]ilos.Class{BasicArrayStar}, ""} +var BasicVector = &primitiveclass{[]ilos.Class{BasicArray}, ""} +var GeneraVector = &primitiveclass{[]ilos.Class{BasicVector}, ""} +var String = &primitiveclass{[]ilos.Class{BasicVector}, ""} +var Character = &primitiveclass{[]ilos.Class{Object}, ""} +var Function = &primitiveclass{[]ilos.Class{Object}, ""} +var GenericFunction = &primitiveclass{[]ilos.Class{Function}, ""} +var StandardGenericFunction = &primitiveclass{[]ilos.Class{GenericFunction}, ""} +var List = &primitiveclass{[]ilos.Class{Object}, ""} +var Cons = &primitiveclass{[]ilos.Class{List}, ""} +var Null = &primitiveclass{[]ilos.Class{List}, ""} +var Symbol = &primitiveclass{[]ilos.Class{Object}, ""} +var Number = &primitiveclass{[]ilos.Class{Object}, ""} +var Integer = &primitiveclass{[]ilos.Class{Number}, ""} +var Float = &primitiveclass{[]ilos.Class{Number}, ""} + +var SeriousCondition = &builtinclass{[]ilos.Class{Object}, []string{}, ""} +var Error = &builtinclass{[]ilos.Class{SeriousCondition}, []string{}, ""} +var ArithmeticError = &builtinclass{[]ilos.Class{Error}, []string{"OPERATION", "OPERANDS"}, ""} +var DivisionByZero = &builtinclass{[]ilos.Class{ArithmeticError}, []string{}, ""} +var FloatingPointOnderflow = &builtinclass{[]ilos.Class{ArithmeticError}, []string{}, ""} +var FloatingPointUnderflow = &builtinclass{[]ilos.Class{ArithmeticError}, []string{}, ""} +var ControlError = &builtinclass{[]ilos.Class{Error}, []string{}, ""} +var ParseError = &builtinclass{[]ilos.Class{Error}, []string{"STRING", "EXPECTED-CLASS"}, ""} +var ProgramError = &builtinclass{[]ilos.Class{Error}, []string{}, ""} +var DomainError = &builtinclass{[]ilos.Class{ProgramError}, []string{"OBJECT", "EXPECTED-CLASS"}, ""} +var UndefinedEntity = &builtinclass{[]ilos.Class{ProgramError}, []string{"NAME", "NAMESPACE"}, ""} +var UndefinedVariable = &builtinclass{[]ilos.Class{UndefinedEntity}, []string{}, ""} +var UndefinedFunction = &builtinclass{[]ilos.Class{UndefinedEntity}, []string{}, ""} +var SimpleError = &builtinclass{[]ilos.Class{Error}, []string{"FORMAT-STRING", "FORMAT-ARGUMENTS"}, ""} +var StreamError = &builtinclass{[]ilos.Class{Error}, []string{}, ""} +var EndOfStream = &builtinclass{[]ilos.Class{StreamError}, []string{}, ""} +var StorageExhausted = &builtinclass{[]ilos.Class{SeriousCondition}, []string{}, ""} +var StandardObject = &builtinclass{[]ilos.Class{Object}, []string{}, ""} +var Stream = &builtinclass{[]ilos.Class{Object}, []string{"STREAM"}, ""} + +// Implementation defined +var WrongNumberOfArguments = &builtinclass{[]ilos.Class{Error}, []string{"FORM", "ARGUMENTS"}, ""} +var Escape = &builtinclass{[]ilos.Class{Object}, []string{"TAG"}, ""} +var CatchTag = &builtinclass{[]ilos.Class{Escape}, []string{"OBJECT"}, ""} +var TagbodyTag = &builtinclass{[]ilos.Class{Escape}, []string{}, ""} +var BlockTag = &builtinclass{[]ilos.Class{Escape}, []string{"OBJECT"}, ""} diff --git a/runtime/ilos/class/primitiveclass.go b/runtime/ilos/class/primitiveclass.go index 0c65765..7b435c5 100644 --- a/runtime/ilos/class/primitiveclass.go +++ b/runtime/ilos/class/primitiveclass.go @@ -30,24 +30,3 @@ func (i *primitiveclass) SetSlotValue(key ilos.Instance, value ilos.Instance, _ func (p *primitiveclass) String() string { return p.name } - -var Object = &primitiveclass{[]ilos.Class{}, ""} -var BuiltInClass = &primitiveclass{[]ilos.Class{Object}, ""} -var StandardClass = &primitiveclass{[]ilos.Class{Object}, ""} -var BasicArray = &primitiveclass{[]ilos.Class{Object}, ""} -var BasicArrayStar = &primitiveclass{[]ilos.Class{BasicArray}, ""} -var GeneralArrayStar = &primitiveclass{[]ilos.Class{BasicArrayStar}, ""} -var BasicVector = &primitiveclass{[]ilos.Class{BasicArray}, ""} -var GeneraVector = &primitiveclass{[]ilos.Class{BasicVector}, ""} -var String = &primitiveclass{[]ilos.Class{BasicVector}, ""} -var Character = &primitiveclass{[]ilos.Class{Object}, ""} -var Function = &primitiveclass{[]ilos.Class{Object}, ""} -var GenericFunction = &primitiveclass{[]ilos.Class{Function}, ""} -var StandardGenericFunction = &primitiveclass{[]ilos.Class{GenericFunction}, ""} -var List = &primitiveclass{[]ilos.Class{Object}, ""} -var Cons = &primitiveclass{[]ilos.Class{List}, ""} -var Null = &primitiveclass{[]ilos.Class{List}, ""} -var Symbol = &primitiveclass{[]ilos.Class{Object}, ""} -var Number = &primitiveclass{[]ilos.Class{Object}, ""} -var Integer = &primitiveclass{[]ilos.Class{Number}, ""} -var Float = &primitiveclass{[]ilos.Class{Number}, ""} diff --git a/runtime/ilos/instance/basic-array.go b/runtime/ilos/instance/basic-array.go index c6e3f42..70a969d 100644 --- a/runtime/ilos/instance/basic-array.go +++ b/runtime/ilos/instance/basic-array.go @@ -33,11 +33,11 @@ func (a *GeneralArrayStar) GetSlotValue(key ilos.Instance, _ ilos.Class) (ilos.I } return cons, true } - if ilos.InstanceOf(key, class.List) { + if Of(class.List, key) { dim := [128]int{} idx := 0 cdr := key - for ilos.InstanceOf(cdr, class.Cons) { + for Of(class.Cons, cdr) { dim[idx] = int(UnsafeCar(cdr).(Integer)) cdr = UnsafeCdr(cdr) idx++ @@ -53,11 +53,11 @@ func (a *GeneralArrayStar) GetSlotValue(key ilos.Instance, _ ilos.Class) (ilos.I } func (a *GeneralArrayStar) SetSlotValue(key ilos.Instance, value ilos.Instance, _ ilos.Class) bool { - if ilos.InstanceOf(key, class.List) { + if Of(class.List, key) { dim := [128]int{} idx := 0 cdr := key - for ilos.InstanceOf(cdr, class.Cons) { + for Of(class.Cons, cdr) { dim[idx] = int(UnsafeCar(cdr).(Integer)) cdr = UnsafeCdr(cdr) idx++ diff --git a/runtime/ilos/instance/instance.go b/runtime/ilos/instance/instance.go index 21cecbc..91606a1 100644 --- a/runtime/ilos/instance/instance.go +++ b/runtime/ilos/instance/instance.go @@ -43,6 +43,13 @@ func New(c ilos.Class, s ...interface{}) ilos.Instance { } } +func Of(p ilos.Class, i ilos.Instance) bool { + if i.Class() == p { + return true + } + return class.Is(i.Class(), p) +} + type instance struct { class ilos.Class supers []ilos.Instance diff --git a/runtime/ilos/instance/list.go b/runtime/ilos/instance/list.go index dff2961..f31df4f 100644 --- a/runtime/ilos/instance/list.go +++ b/runtime/ilos/instance/list.go @@ -53,11 +53,11 @@ func (i *Cons) SetSlotValue(key ilos.Instance, value ilos.Instance, _ ilos.Class func (i *Cons) String() string { str := "(" + fmt.Sprint(i.car) cdr := i.cdr - for ilos.InstanceOf(cdr, class.Cons) { + for Of(class.Cons, cdr) { str += fmt.Sprintf(" %v", UnsafeCar(cdr)) cdr = UnsafeCdr(cdr) } - if ilos.InstanceOf(cdr, class.Null) { + if Of(class.Null, cdr) { str += ")" } else { str += fmt.Sprintf(" . %v)", cdr) diff --git a/runtime/lambda.go b/runtime/lambda.go index 17c837a..891edc6 100644 --- a/runtime/lambda.go +++ b/runtime/lambda.go @@ -9,7 +9,7 @@ import ( func lambda(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { // args must be a instance of Cons, not Null, and ends with nil - if !ilos.InstanceOf(args, class.Cons) || !UnsafeEndOfListIsNil(args) { // Checked at the head of test + if !instance.Of(class.Cons, args) || !UnsafeEndOfListIsNil(args) { // Checked at the head of test return nil, instance.New(class.WrongNumberOfArguments, map[string]ilos.Instance{ "FORM": instance.New(class.Symbol, "LAMBDA"), "ARGUMENTS": args, @@ -17,7 +17,7 @@ func lambda(args ilos.Instance, local *env.Environment, global *env.Environment) } lambdaList := instance.UnsafeCar(args) // lambda-list must be a instance of list and ends with nil - if !ilos.InstanceOf(lambdaList, class.List) || !UnsafeEndOfListIsNil(lambdaList) { // Checked at the head of test + if !instance.Of(class.List, lambdaList) || !UnsafeEndOfListIsNil(lambdaList) { // Checked at the head of test return nil, instance.New(class.ParseError, lambdaList, class.List) } forms := instance.UnsafeCdr(args) // Checked at the top of this function. (EndOfListIsNil) @@ -31,7 +31,7 @@ func lambda(args ilos.Instance, local *env.Environment, global *env.Environment) local.Macro = append(lexical.Macro, local.Macro...) local.DynamicVariable = append(lexical.DynamicVariable, local.DynamicVariable...) // args must be a instance of list and end with nil - if !ilos.InstanceOf(args, class.List) || !UnsafeEndOfListIsNil(args) { // Checked at the head of test + if !instance.Of(class.List, args) || !UnsafeEndOfListIsNil(args) { // Checked at the head of test return nil, instance.New(class.DomainError, map[string]ilos.Instance{ "OBJECT": args, "EXPECTED-CLASS": class.List, @@ -39,12 +39,12 @@ func lambda(args ilos.Instance, local *env.Environment, global *env.Environment) } cdr := lambdaList ok := false - for ilos.InstanceOf(cdr, class.Cons) { + for instance.Of(class.Cons, cdr) { car := instance.UnsafeCar(cdr) // Checked at the top of this loop. cdr = instance.UnsafeCdr(cdr) // Checked at the top of this loop. if car == instance.New(class.Symbol, ":REST") || car == instance.New(class.Symbol, "&REST") { // fargs has only one symbol after &rest or :rest symbol. - if ilos.InstanceOf(cdr, class.List) && UnsafeListLength(cdr) == 1 { // Checked at the head of test + if instance.Of(class.List, cdr) && UnsafeListLength(cdr) == 1 { // Checked at the head of test // If fargs has :rest or &rest symbol, The length of aargs must be greater than or equal to 'the length of fargs' - 2. // aargs is a instance of list and ends with nil becauseof the checking at this function. // lambda-list is a instance of list and ends with nil becauseof the checking at the function, lambda. @@ -76,7 +76,7 @@ func lambda(args ilos.Instance, local *env.Environment, global *env.Environment) } fargs := lambdaList aargs := args - for ilos.InstanceOf(fargs, class.Cons) && ilos.InstanceOf(aargs, class.Cons) { + for instance.Of(class.Cons, fargs) && instance.Of(class.Cons, aargs) { key := instance.UnsafeCar(fargs) // Checked at the top of this loop. value := instance.UnsafeCar(aargs) // Checked at the top of this loop. if key == instance.New(class.Symbol, ":REST") || key == instance.New(class.Symbol, "&REST") { @@ -91,7 +91,7 @@ func lambda(args ilos.Instance, local *env.Environment, global *env.Environment) body := forms ret := instance.New(class.Null) var err ilos.Instance - for ilos.InstanceOf(body, class.Cons) { + for instance.Of(class.Cons, body) { exp := instance.UnsafeCar(body) // Checked at the top of this loop ret, err = Eval(exp, local, global) if err != nil { diff --git a/runtime/quote.go b/runtime/quote.go index b0a954b..b7d055f 100644 --- a/runtime/quote.go +++ b/runtime/quote.go @@ -9,7 +9,7 @@ import ( func quote(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { // args must be a instance of Cons, not Null, and ends with nil - if !ilos.InstanceOf(args, class.Cons) || !UnsafeEndOfListIsNil(args) || UnsafeListLength(args) != 1 { // Checked at the head of test + if !instance.Of(class.Cons, args) || !UnsafeEndOfListIsNil(args) || UnsafeListLength(args) != 1 { // Checked at the head of test return nil, instance.New(class.WrongNumberOfArguments, map[string]ilos.Instance{ "FORM": instance.New(class.Symbol, "QUOTE"), "ARGUMENTS": args, diff --git a/runtime/return-from.go b/runtime/return-from.go index 83e46df..291b711 100644 --- a/runtime/return-from.go +++ b/runtime/return-from.go @@ -9,7 +9,7 @@ import ( func returnFrom(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { // args must be a instance of Cons, not Null, and ends with nil - if !ilos.InstanceOf(args, class.Cons) || !UnsafeEndOfListIsNil(args) || UnsafeListLength(args) != 2 { // Checked at the head of test + if !instance.Of(class.Cons, args) || !UnsafeEndOfListIsNil(args) || UnsafeListLength(args) != 2 { // Checked at the head of test return nil, instance.New(class.WrongNumberOfArguments, map[string]ilos.Instance{ "FORM": instance.New(class.Symbol, "RETURN-FROM"), "ARGUMENTS": args, @@ -20,7 +20,7 @@ func returnFrom(args ilos.Instance, local *env.Environment, global *env.Environm if err != nil { return nil, err } - if ilos.InstanceOf(tag, class.Number) || ilos.InstanceOf(tag, class.Character) { + if instance.Of(class.Number, tag) || instance.Of(class.Character, tag) { return nil, instance.New(class.DomainError, map[string]ilos.Instance{ "OBJECT": tag, "EXPECTED-CLASS": class.Object, diff --git a/runtime/tagbody.go b/runtime/tagbody.go index 30c82ec..5c02363 100644 --- a/runtime/tagbody.go +++ b/runtime/tagbody.go @@ -9,7 +9,7 @@ import ( func tagbody(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { // args must be a instance of Cons, not Null, and ends with nil - if !ilos.InstanceOf(args, class.Cons) || !UnsafeEndOfListIsNil(args) || UnsafeListLength(args) < 2 { // Checked at the head of test + if !instance.Of(class.Cons, args) || !UnsafeEndOfListIsNil(args) || UnsafeListLength(args) < 2 { // Checked at the head of test return nil, instance.New(class.WrongNumberOfArguments, map[string]ilos.Instance{ "FORM": instance.New(class.Symbol, "TAGBODY"), "ARGUMENTS": args, @@ -17,24 +17,24 @@ func tagbody(args ilos.Instance, local *env.Environment, global *env.Environment } localTags := []ilos.Instance{} cdr := args // Checked at the top of this function - for ilos.InstanceOf(cdr, class.Cons) { + for instance.Of(class.Cons, cdr) { cadr := instance.UnsafeCar(cdr) // Checked at the top of this loop cddr := instance.UnsafeCdr(cdr) // Checked at the top of this loop - if !ilos.InstanceOf(cadr, class.Cons) { + if !instance.Of(class.Cons, cadr) { local.TagBodyTag.Define(cadr, cddr) localTags = append(localTags, cadr) } cdr = cddr } cdr = args - for ilos.InstanceOf(cdr, class.Cons) { + for instance.Of(class.Cons, cdr) { cadr := instance.UnsafeCar(cdr) // Checked at the top of this loop cddr := instance.UnsafeCdr(cdr) // Checked at the top of this loop - if ilos.InstanceOf(cadr, class.Cons) { + if instance.Of(class.Cons, cadr) { _, fail := Eval(cadr, local, global) if fail != nil { tag: - if ilos.InstanceOf(fail, class.TagbodyTag) { + if instance.Of(class.TagbodyTag, fail) { tag, _ := fail.GetSlotValue(instance.New(class.Symbol, "TAG"), class.Escape) // Checked at the top of this loop found := false for _, localTag := range localTags { @@ -46,10 +46,10 @@ func tagbody(args ilos.Instance, local *env.Environment, global *env.Environment if found { forms, _ := local.TagBodyTag.Get(tag) // Checked in the function, tagbodyGo cdddr := forms - for ilos.InstanceOf(cdddr, class.Cons) { + for instance.Of(class.Cons, cdddr) { cadddr := instance.UnsafeCar(cdddr) // Checked at the top of this loop cddddr := instance.UnsafeCdr(cdddr) // Checked at the top of this loop - if ilos.InstanceOf(cadddr, class.Cons) { + if instance.Of(class.Cons, cadddr) { _, fail = Eval(cadddr, local, global) if fail != nil { goto tag diff --git a/runtime/throw.go b/runtime/throw.go index 8e63731..aaac6d8 100644 --- a/runtime/throw.go +++ b/runtime/throw.go @@ -9,7 +9,7 @@ import ( func throw(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { // args must be a instance of Cons, not Null, and ends with nil - if !ilos.InstanceOf(args, class.Cons) || !UnsafeEndOfListIsNil(args) || UnsafeListLength(args) != 2 { // Checked at the head of test + if !instance.Of(class.Cons, args) || !UnsafeEndOfListIsNil(args) || UnsafeListLength(args) != 2 { // Checked at the head of test return nil, instance.New(class.WrongNumberOfArguments, map[string]ilos.Instance{ "FORM": instance.New(class.Symbol, "THROW"), "ARGUMENTS": args, @@ -20,7 +20,7 @@ func throw(args ilos.Instance, local *env.Environment, global *env.Environment) if err != nil { return nil, err } - if ilos.InstanceOf(tag, class.Number) || ilos.InstanceOf(tag, class.Character) { + if instance.Of(class.Number, tag) || instance.Of(class.Character, tag) { return nil, instance.New(class.DomainError, map[string]ilos.Instance{ "OBJECT": tag, "EXPECTED-CLASS": class.Object, diff --git a/runtime/util.go b/runtime/util.go index 6e436d2..2213a32 100644 --- a/runtime/util.go +++ b/runtime/util.go @@ -11,10 +11,10 @@ import ( // So you have to check the instance. func UnsafeEndOfListIsNil(i ilos.Instance) bool { cdr := i - for ilos.InstanceOf(cdr, class.Cons) { + for instance.Of(class.Cons, cdr) { cdr = instance.UnsafeCdr(cdr) // Checked at the top of this loop } - if ilos.InstanceOf(cdr, class.Null) { + if instance.Of(class.Null, cdr) { return true } return false @@ -26,7 +26,7 @@ func UnsafeEndOfListIsNil(i ilos.Instance) bool { func UnsafeListLength(i ilos.Instance) int { cdr := i cnt := 0 - for ilos.InstanceOf(cdr, class.Cons) { + for instance.Of(class.Cons, cdr) { cdr = instance.UnsafeCdr(cdr) // Checked at the top of this loop cnt++ } From eaa7a00b37d6fec21c947a0b32b82ed5eb138dac Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Thu, 10 Aug 2017 08:57:48 +0900 Subject: [PATCH 111/228] Merge some file, block & return-from, catch & throw, tagbody & go --- runtime/block.go | 36 ++++++++++++++++++++++++++++++++++ runtime/catch.go | 36 ++++++++++++++++++++++++++++++++++ runtime/go.go | 26 ------------------------- runtime/return-from.go | 44 ------------------------------------------ runtime/tagbody.go | 18 +++++++++++++++++ runtime/throw.go | 44 ------------------------------------------ 6 files changed, 90 insertions(+), 114 deletions(-) delete mode 100644 runtime/go.go delete mode 100644 runtime/return-from.go delete mode 100644 runtime/throw.go diff --git a/runtime/block.go b/runtime/block.go index 2bf6930..858a246 100644 --- a/runtime/block.go +++ b/runtime/block.go @@ -51,3 +51,39 @@ func block(args ilos.Instance, local *env.Environment, global *env.Environment) } return sucess, nil } + +func returnFrom(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { + // args must be a instance of Cons, not Null, and ends with nil + if !instance.Of(class.Cons, args) || !UnsafeEndOfListIsNil(args) || UnsafeListLength(args) != 2 { // Checked at the head of test + return nil, instance.New(class.WrongNumberOfArguments, map[string]ilos.Instance{ + "FORM": instance.New(class.Symbol, "RETURN-FROM"), + "ARGUMENTS": args, + }) + } + car := instance.UnsafeCar(args) // Checked at the top of this function + tag, err := Eval(car, local, global) + if err != nil { + return nil, err + } + if instance.Of(class.Number, tag) || instance.Of(class.Character, tag) { + return nil, instance.New(class.DomainError, map[string]ilos.Instance{ + "OBJECT": tag, + "EXPECTED-CLASS": class.Object, + }) + } + cadr := instance.UnsafeCar(instance.UnsafeCdr(args)) // Checked length is 2 at the top of this function + object, err := Eval(cadr, local, global) + if err != nil { + return nil, err + } + if _, ok := local.BlockTag.Get(tag); !ok { + return nil, instance.New(class.SimpleError, map[string]ilos.Instance{ + "FORMAT-STRING": instance.New(class.String, "%v is not defined as the tag"), + "FORMAT-ARGUMENTS": car, + }) + } + return nil, instance.New(class.BlockTag, map[string]ilos.Instance{ + "TAG": tag, + "OBJECT": object, + }) +} diff --git a/runtime/catch.go b/runtime/catch.go index 2c9a238..ae936fc 100644 --- a/runtime/catch.go +++ b/runtime/catch.go @@ -43,3 +43,39 @@ func catch(args ilos.Instance, local *env.Environment, global *env.Environment) } return sucess, nil } + +func throw(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { + // args must be a instance of Cons, not Null, and ends with nil + if !instance.Of(class.Cons, args) || !UnsafeEndOfListIsNil(args) || UnsafeListLength(args) != 2 { // Checked at the head of test + return nil, instance.New(class.WrongNumberOfArguments, map[string]ilos.Instance{ + "FORM": instance.New(class.Symbol, "THROW"), + "ARGUMENTS": args, + }) + } + car := instance.UnsafeCar(args) // Checked at the top of this function + tag, err := Eval(car, local, global) + if err != nil { + return nil, err + } + if instance.Of(class.Number, tag) || instance.Of(class.Character, tag) { + return nil, instance.New(class.DomainError, map[string]ilos.Instance{ + "OBJECT": tag, + "EXPECTED-CLASS": class.Object, + }) + } + cadr := instance.UnsafeCar(instance.UnsafeCdr(args)) // Checked length is 2 at the top of this function + object, err := Eval(cadr, local, global) + if err != nil { + return nil, err + } + if _, ok := local.ThrowTag.Get(tag); !ok { + return nil, instance.New(class.SimpleError, map[string]ilos.Instance{ + "FORMAT-STRING": instance.New(class.String, "%v is not defined as the tag"), + "FORMAT-ARGUMENTS": car, + }) + } + return nil, instance.New(class.CatchTag, map[string]ilos.Instance{ + "TAG": tag, + "OBJECT": object, + }) +} diff --git a/runtime/go.go b/runtime/go.go deleted file mode 100644 index 2b45a48..0000000 --- a/runtime/go.go +++ /dev/null @@ -1,26 +0,0 @@ -package runtime - -import ( - env "github.com/ta2gch/iris/runtime/environment" - "github.com/ta2gch/iris/runtime/ilos" - "github.com/ta2gch/iris/runtime/ilos/class" - "github.com/ta2gch/iris/runtime/ilos/instance" -) - -func tagbodyGo(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { - // args must be a instance of Cons, not Null, and ends with nil - if !instance.Of(class.Cons, args) || !UnsafeEndOfListIsNil(args) || UnsafeListLength(args) != 1 { // Checked at the head of test - return nil, instance.New(class.WrongNumberOfArguments, map[string]ilos.Instance{ - "FORM": instance.New(class.Symbol, "GO"), - "ARGUMENTS": args, - }) - } - car := instance.UnsafeCar(args) // Checked at the top of this function - if _, ok := local.TagBodyTag.Get(car); !ok { - return nil, instance.New(class.SimpleError, map[string]ilos.Instance{ - "FORMAT-STRING": instance.New(class.String, "%v is not defined as the tag"), - "FORMAT-ARGUMENTS": car, - }) - } - return nil, instance.New(class.TagbodyTag, map[string]ilos.Instance{"TAG": car}) -} diff --git a/runtime/return-from.go b/runtime/return-from.go deleted file mode 100644 index 291b711..0000000 --- a/runtime/return-from.go +++ /dev/null @@ -1,44 +0,0 @@ -package runtime - -import ( - env "github.com/ta2gch/iris/runtime/environment" - "github.com/ta2gch/iris/runtime/ilos" - "github.com/ta2gch/iris/runtime/ilos/class" - "github.com/ta2gch/iris/runtime/ilos/instance" -) - -func returnFrom(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { - // args must be a instance of Cons, not Null, and ends with nil - if !instance.Of(class.Cons, args) || !UnsafeEndOfListIsNil(args) || UnsafeListLength(args) != 2 { // Checked at the head of test - return nil, instance.New(class.WrongNumberOfArguments, map[string]ilos.Instance{ - "FORM": instance.New(class.Symbol, "RETURN-FROM"), - "ARGUMENTS": args, - }) - } - car := instance.UnsafeCar(args) // Checked at the top of this function - tag, err := Eval(car, local, global) - if err != nil { - return nil, err - } - if instance.Of(class.Number, tag) || instance.Of(class.Character, tag) { - return nil, instance.New(class.DomainError, map[string]ilos.Instance{ - "OBJECT": tag, - "EXPECTED-CLASS": class.Object, - }) - } - cadr := instance.UnsafeCar(instance.UnsafeCdr(args)) // Checked length is 2 at the top of this function - object, err := Eval(cadr, local, global) - if err != nil { - return nil, err - } - if _, ok := local.BlockTag.Get(tag); !ok { - return nil, instance.New(class.SimpleError, map[string]ilos.Instance{ - "FORMAT-STRING": instance.New(class.String, "%v is not defined as the tag"), - "FORMAT-ARGUMENTS": car, - }) - } - return nil, instance.New(class.BlockTag, map[string]ilos.Instance{ - "TAG": tag, - "OBJECT": object, - }) -} diff --git a/runtime/tagbody.go b/runtime/tagbody.go index 5c02363..eb5b209 100644 --- a/runtime/tagbody.go +++ b/runtime/tagbody.go @@ -68,3 +68,21 @@ func tagbody(args ilos.Instance, local *env.Environment, global *env.Environment } return instance.New(class.Null), nil } + +func tagbodyGo(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { + // args must be a instance of Cons, not Null, and ends with nil + if !instance.Of(class.Cons, args) || !UnsafeEndOfListIsNil(args) || UnsafeListLength(args) != 1 { // Checked at the head of test + return nil, instance.New(class.WrongNumberOfArguments, map[string]ilos.Instance{ + "FORM": instance.New(class.Symbol, "GO"), + "ARGUMENTS": args, + }) + } + car := instance.UnsafeCar(args) // Checked at the top of this function + if _, ok := local.TagBodyTag.Get(car); !ok { + return nil, instance.New(class.SimpleError, map[string]ilos.Instance{ + "FORMAT-STRING": instance.New(class.String, "%v is not defined as the tag"), + "FORMAT-ARGUMENTS": car, + }) + } + return nil, instance.New(class.TagbodyTag, map[string]ilos.Instance{"TAG": car}) +} diff --git a/runtime/throw.go b/runtime/throw.go deleted file mode 100644 index aaac6d8..0000000 --- a/runtime/throw.go +++ /dev/null @@ -1,44 +0,0 @@ -package runtime - -import ( - env "github.com/ta2gch/iris/runtime/environment" - "github.com/ta2gch/iris/runtime/ilos" - "github.com/ta2gch/iris/runtime/ilos/class" - "github.com/ta2gch/iris/runtime/ilos/instance" -) - -func throw(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { - // args must be a instance of Cons, not Null, and ends with nil - if !instance.Of(class.Cons, args) || !UnsafeEndOfListIsNil(args) || UnsafeListLength(args) != 2 { // Checked at the head of test - return nil, instance.New(class.WrongNumberOfArguments, map[string]ilos.Instance{ - "FORM": instance.New(class.Symbol, "THROW"), - "ARGUMENTS": args, - }) - } - car := instance.UnsafeCar(args) // Checked at the top of this function - tag, err := Eval(car, local, global) - if err != nil { - return nil, err - } - if instance.Of(class.Number, tag) || instance.Of(class.Character, tag) { - return nil, instance.New(class.DomainError, map[string]ilos.Instance{ - "OBJECT": tag, - "EXPECTED-CLASS": class.Object, - }) - } - cadr := instance.UnsafeCar(instance.UnsafeCdr(args)) // Checked length is 2 at the top of this function - object, err := Eval(cadr, local, global) - if err != nil { - return nil, err - } - if _, ok := local.ThrowTag.Get(tag); !ok { - return nil, instance.New(class.SimpleError, map[string]ilos.Instance{ - "FORMAT-STRING": instance.New(class.String, "%v is not defined as the tag"), - "FORMAT-ARGUMENTS": car, - }) - } - return nil, instance.New(class.CatchTag, map[string]ilos.Instance{ - "TAG": tag, - "OBJECT": object, - }) -} From 44f8010fe13851f2d3e56a9f73ae3befd89004f8 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Thu, 10 Aug 2017 09:18:17 +0900 Subject: [PATCH 112/228] Changed name of environment of tag --- runtime/block.go | 2 +- runtime/catch.go | 4 ++-- runtime/environment/environment.go | 8 ++++---- runtime/eval.go | 4 ++-- runtime/lambda.go | 4 ++-- runtime/tagbody.go | 6 +++--- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/runtime/block.go b/runtime/block.go index 858a246..9ae6b81 100644 --- a/runtime/block.go +++ b/runtime/block.go @@ -30,7 +30,7 @@ func block(args ilos.Instance, local *env.Environment, global *env.Environment) if instance.Of(class.Number, car) || instance.Of(class.Character, car) { return nil, instance.New(class.DomainError, car, class.Object) } - local.BlockTag.Define(car, car) + local.BlockTag.Define(car, nil) cdr := instance.UnsafeCdr(args) // Checked at the top of this function var sucess, fail ilos.Instance for instance.Of(class.Cons, cdr) { diff --git a/runtime/catch.go b/runtime/catch.go index ae936fc..1f4a2d2 100644 --- a/runtime/catch.go +++ b/runtime/catch.go @@ -22,7 +22,7 @@ func catch(args ilos.Instance, local *env.Environment, global *env.Environment) if instance.Of(class.Number, car) || instance.Of(class.Character, car) { return nil, instance.New(class.DomainError, car, class.Object) } - local.ThrowTag.Define(car, car) + local.CatchTag.Define(car, nil) cdr := instance.UnsafeCdr(args) // Checked at the top of this function var sucess, fail ilos.Instance for instance.Of(class.Cons, cdr) { @@ -68,7 +68,7 @@ func throw(args ilos.Instance, local *env.Environment, global *env.Environment) if err != nil { return nil, err } - if _, ok := local.ThrowTag.Get(tag); !ok { + if _, ok := local.CatchTag.Get(tag); !ok { return nil, instance.New(class.SimpleError, map[string]ilos.Instance{ "FORMAT-STRING": instance.New(class.String, "%v is not defined as the tag"), "FORMAT-ARGUMENTS": car, diff --git a/runtime/environment/environment.go b/runtime/environment/environment.go index b347582..1e99e55 100644 --- a/runtime/environment/environment.go +++ b/runtime/environment/environment.go @@ -3,8 +3,8 @@ package environment // Environment struct is the struct for keeping functions and variables type Environment struct { BlockTag stack - TagBodyTag stack - ThrowTag stack + TagbodyTag stack + CatchTag stack Macro stack Function stack Variable stack @@ -15,8 +15,8 @@ type Environment struct { func New() *Environment { env := new(Environment) env.BlockTag = newStack() - env.TagBodyTag = newStack() - env.ThrowTag = newStack() + env.TagbodyTag = newStack() + env.CatchTag = newStack() env.Macro = newStack() env.Function = newStack() env.Variable = newStack() diff --git a/runtime/eval.go b/runtime/eval.go index b49864f..fd4ceb4 100644 --- a/runtime/eval.go +++ b/runtime/eval.go @@ -62,7 +62,7 @@ func evalFunction(obj ilos.Instance, local *env.Environment, global *env.Environ } env := env.New() env.DynamicVariable = append(local.DynamicVariable, env.DynamicVariable...) - env.ThrowTag = append(local.ThrowTag, env.ThrowTag...) + env.CatchTag = append(local.CatchTag, env.CatchTag...) ret, err := fun.(instance.Function)(args, env, global) if err != nil { return nil, err @@ -107,7 +107,7 @@ func evalFunction(obj ilos.Instance, local *env.Environment, global *env.Environ } env := env.New() env.DynamicVariable = append(local.DynamicVariable, env.DynamicVariable...) - env.ThrowTag = append(local.ThrowTag, env.ThrowTag...) + env.CatchTag = append(local.CatchTag, env.CatchTag...) ret, err := fun.(instance.Function)(args, env, global) if err != nil { return nil, err diff --git a/runtime/lambda.go b/runtime/lambda.go index 891edc6..4005263 100644 --- a/runtime/lambda.go +++ b/runtime/lambda.go @@ -24,8 +24,8 @@ func lambda(args ilos.Instance, local *env.Environment, global *env.Environment) lexical := local return instance.New(class.Function, func(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { local.BlockTag = append(lexical.BlockTag, local.BlockTag...) - local.TagBodyTag = append(lexical.TagBodyTag, local.TagBodyTag...) - local.ThrowTag = append(lexical.ThrowTag, local.ThrowTag...) + local.TagbodyTag = append(lexical.TagbodyTag, local.TagbodyTag...) + local.CatchTag = append(lexical.CatchTag, local.CatchTag...) local.Variable = append(lexical.Variable, local.Variable...) local.Function = append(lexical.Function, local.Function...) local.Macro = append(lexical.Macro, local.Macro...) diff --git a/runtime/tagbody.go b/runtime/tagbody.go index eb5b209..6f33c7d 100644 --- a/runtime/tagbody.go +++ b/runtime/tagbody.go @@ -21,7 +21,7 @@ func tagbody(args ilos.Instance, local *env.Environment, global *env.Environment cadr := instance.UnsafeCar(cdr) // Checked at the top of this loop cddr := instance.UnsafeCdr(cdr) // Checked at the top of this loop if !instance.Of(class.Cons, cadr) { - local.TagBodyTag.Define(cadr, cddr) + local.TagbodyTag.Define(cadr, nil) localTags = append(localTags, cadr) } cdr = cddr @@ -44,7 +44,7 @@ func tagbody(args ilos.Instance, local *env.Environment, global *env.Environment } } if found { - forms, _ := local.TagBodyTag.Get(tag) // Checked in the function, tagbodyGo + forms, _ := local.TagbodyTag.Get(tag) // Checked in the function, tagbodyGo cdddr := forms for instance.Of(class.Cons, cdddr) { cadddr := instance.UnsafeCar(cdddr) // Checked at the top of this loop @@ -78,7 +78,7 @@ func tagbodyGo(args ilos.Instance, local *env.Environment, global *env.Environme }) } car := instance.UnsafeCar(args) // Checked at the top of this function - if _, ok := local.TagBodyTag.Get(car); !ok { + if _, ok := local.TagbodyTag.Get(car); !ok { return nil, instance.New(class.SimpleError, map[string]ilos.Instance{ "FORMAT-STRING": instance.New(class.String, "%v is not defined as the tag"), "FORMAT-ARGUMENTS": car, From 896ab8c40b5294eaeee590fb74e3e9f761252da3 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Thu, 10 Aug 2017 17:47:54 +0900 Subject: [PATCH 113/228] Added New Functin Style --- docs/index.html | 48 +++++++++++++++ runtime/block.go | 49 ++++++---------- runtime/catch.go | 46 +++++---------- runtime/eval.go | 6 +- runtime/eval_test.go | 11 ++-- runtime/function.go | 20 ++----- runtime/ilos/class/class.go | 2 +- runtime/ilos/instance/basic-array.go | 87 ++-------------------------- runtime/ilos/instance/character.go | 4 -- runtime/ilos/instance/function.go | 52 +++++++++++++++-- runtime/ilos/instance/instance.go | 21 ++++--- runtime/ilos/instance/list.go | 8 --- runtime/ilos/instance/number.go | 8 --- runtime/ilos/instance/symbol.go | 4 -- runtime/lambda.go | 20 ++----- runtime/quote.go | 13 +---- runtime/runtime.go | 19 +++--- runtime/tagbody.go | 60 +++++-------------- 18 files changed, 190 insertions(+), 288 deletions(-) create mode 100644 docs/index.html diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 0000000..c62b646 --- /dev/null +++ b/docs/index.html @@ -0,0 +1,48 @@ + + + + + + + Iris + + + + + + +
+ +
+

+ Iris is a interpreter of ISLisp on Go/JavaScript. +

+
+
+
+ +
+
+
+

Copyright © 2017 TANIGUCHI Masaya All Rights Reserved.

+
+
+ + \ No newline at end of file diff --git a/runtime/block.go b/runtime/block.go index 9ae6b81..69b3e26 100644 --- a/runtime/block.go +++ b/runtime/block.go @@ -15,53 +15,39 @@ import ( // The extend of name is dynamic. (islisp-v23.pdf, 43-44) // NOTE: // According to this, the scope of name is dynamic. I guess it should be a static. -func block(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { - // args must be a instance of Cons, not Null, and ends with nil - if !instance.Of(class.Cons, args) || !UnsafeEndOfListIsNil(args) || UnsafeListLength(args) < 2 { // Checked at the head of test - return nil, instance.New(class.WrongNumberOfArguments, map[string]ilos.Instance{ - "FORM": instance.New(class.Symbol, "BLOCK"), - "ARGUMENTS": args, - }) - } - car, err := Eval(instance.UnsafeCar(args), local, global) // Checked at the top of this function +func block(local, global *env.Environment, tag ilos.Instance, body ...ilos.Instance) (ilos.Instance, ilos.Instance) { + var err ilos.Instance + tag, err = Eval(tag, local, global) // Checked at the top of this function if err != nil { return nil, err } - if instance.Of(class.Number, car) || instance.Of(class.Character, car) { - return nil, instance.New(class.DomainError, car, class.Object) + if instance.Of(class.Number, tag) || instance.Of(class.Character, tag) { + return nil, instance.New(class.DomainError, map[string]ilos.Instance{ + "OBJECT": tag, + "EXPECTED-CLASS": class.Object, + }) } - local.BlockTag.Define(car, nil) - cdr := instance.UnsafeCdr(args) // Checked at the top of this function + local.BlockTag.Define(tag, nil) var sucess, fail ilos.Instance - for instance.Of(class.Cons, cdr) { - cadr := instance.UnsafeCar(cdr) // Checked at the top of this loop - cddr := instance.UnsafeCdr(cdr) // Checked at the top of this loop + for _, cadr := range body { sucess, fail = Eval(cadr, local, global) if fail != nil { if instance.Of(class.BlockTag, fail) { - tag, _ := fail.GetSlotValue(instance.New(class.Symbol, "TAG"), class.Escape) // Checked at the head of this condition - if car == tag { + tag1, _ := fail.GetSlotValue(instance.New(class.Symbol, "TAG"), class.Escape) // Checked at the head of this condition + if tag == tag1 { obj, _ := fail.GetSlotValue(instance.New(class.Symbol, "OBJECT"), class.BlockTag) // Checked at the head of this condition return obj, nil } } return nil, fail } - cdr = cddr } return sucess, nil } -func returnFrom(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { - // args must be a instance of Cons, not Null, and ends with nil - if !instance.Of(class.Cons, args) || !UnsafeEndOfListIsNil(args) || UnsafeListLength(args) != 2 { // Checked at the head of test - return nil, instance.New(class.WrongNumberOfArguments, map[string]ilos.Instance{ - "FORM": instance.New(class.Symbol, "RETURN-FROM"), - "ARGUMENTS": args, - }) - } - car := instance.UnsafeCar(args) // Checked at the top of this function - tag, err := Eval(car, local, global) +func returnFrom(local, global *env.Environment, tag, object ilos.Instance) (ilos.Instance, ilos.Instance) { + var err ilos.Instance + tag, err = Eval(tag, local, global) if err != nil { return nil, err } @@ -71,15 +57,14 @@ func returnFrom(args ilos.Instance, local *env.Environment, global *env.Environm "EXPECTED-CLASS": class.Object, }) } - cadr := instance.UnsafeCar(instance.UnsafeCdr(args)) // Checked length is 2 at the top of this function - object, err := Eval(cadr, local, global) + object, err = Eval(object, local, global) if err != nil { return nil, err } if _, ok := local.BlockTag.Get(tag); !ok { return nil, instance.New(class.SimpleError, map[string]ilos.Instance{ "FORMAT-STRING": instance.New(class.String, "%v is not defined as the tag"), - "FORMAT-ARGUMENTS": car, + "FORMAT-ARGUMENTS": tag, }) } return nil, instance.New(class.BlockTag, map[string]ilos.Instance{ diff --git a/runtime/catch.go b/runtime/catch.go index 1f4a2d2..900df87 100644 --- a/runtime/catch.go +++ b/runtime/catch.go @@ -7,53 +7,36 @@ import ( "github.com/ta2gch/iris/runtime/ilos/instance" ) -func catch(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { - // args must be a instance of Cons, not Null, and ends with nil - if !instance.Of(class.Cons, args) || !UnsafeEndOfListIsNil(args) || UnsafeListLength(args) < 2 { // Checked at the head of test - return nil, instance.New(class.WrongNumberOfArguments, map[string]ilos.Instance{ - "FORM": instance.New(class.Symbol, "CATCH"), - "ARGUMENTS": args, - }) - } - car, err := Eval(instance.UnsafeCar(args), local, global) // Checked at the top of this function +func catch(local, global *env.Environment, tag ilos.Instance, body ...ilos.Instance) (ilos.Instance, ilos.Instance) { + var err ilos.Instance + tag, err = Eval(tag, local, global) if err != nil { return nil, err } - if instance.Of(class.Number, car) || instance.Of(class.Character, car) { - return nil, instance.New(class.DomainError, car, class.Object) + if instance.Of(class.Number, tag) || instance.Of(class.Character, tag) { + return nil, instance.New(class.DomainError, tag, class.Object) } - local.CatchTag.Define(car, nil) - cdr := instance.UnsafeCdr(args) // Checked at the top of this function + local.CatchTag.Define(tag, nil) var sucess, fail ilos.Instance - for instance.Of(class.Cons, cdr) { - cadr := instance.UnsafeCar(cdr) // Checked at the top of this loop - cddr := instance.UnsafeCdr(cdr) // Checked at the top of this loop + for _, cadr := range body { sucess, fail = Eval(cadr, local, global) if fail != nil { if instance.Of(class.CatchTag, fail) { - tag, _ := fail.GetSlotValue(instance.New(class.Symbol, "TAG"), class.Escape) // Checked at the head of this condition - if car == tag { + tag1, _ := fail.GetSlotValue(instance.New(class.Symbol, "TAG"), class.Escape) // Checked at the head of this condition + if tag == tag1 { obj, _ := fail.GetSlotValue(instance.New(class.Symbol, "OBJECT"), class.CatchTag) // Checked at the head of this condition return obj, nil } } return nil, fail } - cdr = cddr } return sucess, nil } -func throw(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { - // args must be a instance of Cons, not Null, and ends with nil - if !instance.Of(class.Cons, args) || !UnsafeEndOfListIsNil(args) || UnsafeListLength(args) != 2 { // Checked at the head of test - return nil, instance.New(class.WrongNumberOfArguments, map[string]ilos.Instance{ - "FORM": instance.New(class.Symbol, "THROW"), - "ARGUMENTS": args, - }) - } - car := instance.UnsafeCar(args) // Checked at the top of this function - tag, err := Eval(car, local, global) +func throw(local, global *env.Environment, tag, object ilos.Instance) (ilos.Instance, ilos.Instance) { + var err ilos.Instance + tag, err = Eval(tag, local, global) if err != nil { return nil, err } @@ -63,15 +46,14 @@ func throw(args ilos.Instance, local *env.Environment, global *env.Environment) "EXPECTED-CLASS": class.Object, }) } - cadr := instance.UnsafeCar(instance.UnsafeCdr(args)) // Checked length is 2 at the top of this function - object, err := Eval(cadr, local, global) + object, err = Eval(object, local, global) if err != nil { return nil, err } if _, ok := local.CatchTag.Get(tag); !ok { return nil, instance.New(class.SimpleError, map[string]ilos.Instance{ "FORMAT-STRING": instance.New(class.String, "%v is not defined as the tag"), - "FORMAT-ARGUMENTS": car, + "FORMAT-ARGUMENTS": tag, }) } return nil, instance.New(class.CatchTag, map[string]ilos.Instance{ diff --git a/runtime/eval.go b/runtime/eval.go index fd4ceb4..8603b9d 100644 --- a/runtime/eval.go +++ b/runtime/eval.go @@ -63,7 +63,7 @@ func evalFunction(obj ilos.Instance, local *env.Environment, global *env.Environ env := env.New() env.DynamicVariable = append(local.DynamicVariable, env.DynamicVariable...) env.CatchTag = append(local.CatchTag, env.CatchTag...) - ret, err := fun.(instance.Function)(args, env, global) + ret, err := fun.(instance.Callable).Apply(args, env, global) if err != nil { return nil, err } @@ -86,7 +86,7 @@ func evalFunction(obj ilos.Instance, local *env.Environment, global *env.Environ mac = m } if mac != nil { - ret, err := mac.(instance.Function)(cdr, local, global) + ret, err := mac.(instance.Callable).Apply(cdr, local, global) if err != nil { return nil, err } @@ -108,7 +108,7 @@ func evalFunction(obj ilos.Instance, local *env.Environment, global *env.Environ env := env.New() env.DynamicVariable = append(local.DynamicVariable, env.DynamicVariable...) env.CatchTag = append(local.CatchTag, env.CatchTag...) - ret, err := fun.(instance.Function)(args, env, global) + ret, err := fun.(instance.Callable).Apply(args, env, global) if err != nil { return nil, err } diff --git a/runtime/eval_test.go b/runtime/eval_test.go index 088fc5f..986c68d 100644 --- a/runtime/eval_test.go +++ b/runtime/eval_test.go @@ -23,14 +23,13 @@ func TestEval(t *testing.T) { Init() local := env.New() global := env.TopLevel - inc := func(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { - car := instance.UnsafeCar(args) - return instance.New(class.Integer, int(car.(instance.Integer))+1), nil + inc2 := func(local, global *env.Environment, arg ilos.Instance) (ilos.Instance, ilos.Instance) { + return instance.New(class.Integer, int(arg.(instance.Integer))+1), nil } local.Variable.Define(instance.New(class.Symbol, "PI"), instance.New(class.Float, 3.14)) - local.Function.Define(instance.New(class.Symbol, "INC"), instance.New(class.Function, inc)) - local.Macro.Define(instance.New(class.Symbol, "MINC"), instance.New(class.Function, func(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { - ret, err := Eval(instance.New(class.Cons, instance.New(class.Symbol, "INC"), args), local, global) + local.Function.Define(instance.New(class.Symbol, "INC"), instance.New(class.Function, inc2)) + local.Macro.Define(instance.New(class.Symbol, "MINC"), instance.New(class.Function, func(local *env.Environment, global *env.Environment, arg ilos.Instance) (ilos.Instance, ilos.Instance) { + ret, err := Eval(instance.New(class.Cons, instance.New(class.Symbol, "INC"), instance.New(class.Cons, arg, instance.New(class.Null))), local, global) return ret, err })) type args struct { diff --git a/runtime/function.go b/runtime/function.go index 3a9cfbd..cc4270c 100644 --- a/runtime/function.go +++ b/runtime/function.go @@ -7,30 +7,22 @@ import ( "github.com/ta2gch/iris/runtime/ilos/instance" ) -func function(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { - // args must be a instance of Cons, not Null, and ends with nil - if !instance.Of(class.Cons, args) || !UnsafeEndOfListIsNil(args) || UnsafeListLength(args) != 1 { // Checked at the head of test - return nil, instance.New(class.WrongNumberOfArguments, map[string]ilos.Instance{ - "FORM": instance.New(class.Symbol, "FUNCTION"), - "ARGUMENTS": args, - }) - } - car := instance.UnsafeCar(args) // Checked at the top of this function +func function(local, global *env.Environment, fun ilos.Instance) (ilos.Instance, ilos.Instance) { // car must be a symbol - if !instance.Of(class.Symbol, car) { + if !instance.Of(class.Symbol, fun) { return nil, instance.New(class.DomainError, map[string]ilos.Instance{ - "OBJECT": car, + "OBJECT": fun, "EXPECTED-CLASS": class.Symbol, }) } - if f, ok := local.Function.Get(car); ok { + if f, ok := local.Function.Get(fun); ok { return f, nil } - if f, ok := global.Function.Get(car); ok { + if f, ok := global.Function.Get(fun); ok { return f, nil } return nil, instance.New(class.UndefinedFunction, map[string]ilos.Instance{ - "NAME": car, + "NAME": fun, "NAMESPACE": instance.New(class.Symbol, "FUNCTION"), }) } diff --git a/runtime/ilos/class/class.go b/runtime/ilos/class/class.go index 400a708..069130e 100644 --- a/runtime/ilos/class/class.go +++ b/runtime/ilos/class/class.go @@ -30,7 +30,7 @@ var BasicArray = &primitiveclass{[]ilos.Class{Object}, ""} var BasicArrayStar = &primitiveclass{[]ilos.Class{BasicArray}, ""} var GeneralArrayStar = &primitiveclass{[]ilos.Class{BasicArrayStar}, ""} var BasicVector = &primitiveclass{[]ilos.Class{BasicArray}, ""} -var GeneraVector = &primitiveclass{[]ilos.Class{BasicVector}, ""} +var GeneralVector = &primitiveclass{[]ilos.Class{BasicVector}, ""} var String = &primitiveclass{[]ilos.Class{BasicVector}, ""} var Character = &primitiveclass{[]ilos.Class{Object}, ""} var Function = &primitiveclass{[]ilos.Class{Object}, ""} diff --git a/runtime/ilos/instance/basic-array.go b/runtime/ilos/instance/basic-array.go index 70a969d..87de6a4 100644 --- a/runtime/ilos/instance/basic-array.go +++ b/runtime/ilos/instance/basic-array.go @@ -6,94 +6,19 @@ import ( "github.com/ta2gch/iris/runtime/ilos/class" ) -// -// General Array Star -// - -type GeneralArrayStar struct { - dimension [128]int - array map[[128]int]ilos.Instance -} - -func NewGeneralArrayStar(key [128]int) ilos.Instance { - return &GeneralArrayStar{key, map[[128]int]ilos.Instance{}} -} - -func (*GeneralArrayStar) Class() ilos.Class { - return class.GeneralArrayStar -} - -func (a *GeneralArrayStar) GetSlotValue(key ilos.Instance, _ ilos.Class) (ilos.Instance, bool) { - if symbol, ok := key.(Symbol); ok && symbol == "LENGTH" { - cons := NewNull() - for i := 128; i > 0; i-- { - if a.dimension[i-1] != 0 { - cons = NewCons(NewInteger(a.dimension[i-1]), cons) - } - } - return cons, true - } - if Of(class.List, key) { - dim := [128]int{} - idx := 0 - cdr := key - for Of(class.Cons, cdr) { - dim[idx] = int(UnsafeCar(cdr).(Integer)) - cdr = UnsafeCdr(cdr) - idx++ - } - for i := 0; i < 128; i++ { - if a.dimension[i] != 0 && dim[i] >= a.dimension[i] { - return nil, false - } - } - return a.array[dim], true - } - return nil, false -} - -func (a *GeneralArrayStar) SetSlotValue(key ilos.Instance, value ilos.Instance, _ ilos.Class) bool { - if Of(class.List, key) { - dim := [128]int{} - idx := 0 - cdr := key - for Of(class.Cons, cdr) { - dim[idx] = int(UnsafeCar(cdr).(Integer)) - cdr = UnsafeCdr(cdr) - idx++ - } - for i := 0; i < 128; i++ { - if a.dimension[i] != 0 && dim[i] >= a.dimension[i] { - return false - } - } - a.array[dim] = value - return true - } - return false -} - -func (a *GeneralArrayStar) String() string { - return pp.Sprint(a.array) -} - // // General Vector // type GeneralVector []ilos.Instance -func NewGeneralVector(n int) ilos.Instance { - return GeneralVector(make([]ilos.Instance, n)) -} - func (GeneralVector) Class() ilos.Class { - return class.GeneraVector + return class.GeneralVector } func (i GeneralVector) GetSlotValue(key ilos.Instance, _ ilos.Class) (ilos.Instance, bool) { if symbol, ok := key.(Symbol); ok && symbol == "LENGTH" { - return NewInteger(len(i)), true + return New(class.Integer, len(i)), true } if index, ok := key.(Integer); ok && int(index) < len(i) { return i[int(index)], true @@ -119,20 +44,16 @@ func (i GeneralVector) String() string { type String []rune -func NewString(a string) ilos.Instance { - return String([]rune(a)) -} - func (String) Class() ilos.Class { return class.String } func (i String) GetSlotValue(key ilos.Instance, _ ilos.Class) (ilos.Instance, bool) { if symbol, ok := key.(Symbol); ok && symbol == "LENGTH" { - return NewInteger(len(i)), true + return New(class.Integer, len(i)), true } if index, ok := key.(Integer); ok && int(index) < len(i) { - return NewCharacter(i[int(index)]), true + return New(class.Character, i[int(index)]), true } return nil, false } diff --git a/runtime/ilos/instance/character.go b/runtime/ilos/instance/character.go index 2012e18..ffe5a10 100644 --- a/runtime/ilos/instance/character.go +++ b/runtime/ilos/instance/character.go @@ -11,10 +11,6 @@ import ( type Character rune -func NewCharacter(n rune) ilos.Instance { - return Character(n) -} - func (Character) Class() ilos.Class { return class.Character } diff --git a/runtime/ilos/instance/function.go b/runtime/ilos/instance/function.go index 320a555..5ec66bb 100644 --- a/runtime/ilos/instance/function.go +++ b/runtime/ilos/instance/function.go @@ -2,23 +2,49 @@ package instance import ( "fmt" + "reflect" "github.com/ta2gch/iris/runtime/environment" "github.com/ta2gch/iris/runtime/ilos" "github.com/ta2gch/iris/runtime/ilos/class" ) -type Function func(ilos.Instance, *environment.Environment, *environment.Environment) (ilos.Instance, ilos.Instance) +type Callable interface { + Apply(args ilos.Instance, local, global *environment.Environment) (ilos.Instance, ilos.Instance) +} + +type Lambda func(*environment.Environment, *environment.Environment, ilos.Instance) (ilos.Instance, ilos.Instance) + +func (Lambda) Class() ilos.Class { + return class.Function +} + +func (Lambda) GetSlotValue(key ilos.Instance, _ ilos.Class) (ilos.Instance, bool) { + return nil, false +} + +func (Lambda) SetSlotValue(key ilos.Instance, value ilos.Instance, _ ilos.Class) bool { + return false +} + +func (f Lambda) String() string { + return fmt.Sprintf("#%v", f.Class()) +} + +func (f Lambda) Apply(args ilos.Instance, local, global *environment.Environment) (ilos.Instance, ilos.Instance) { + a, b := f(local, global, args) + return a, b +} -func NewFunction(f func(ilos.Instance, *environment.Environment, *environment.Environment) (ilos.Instance, ilos.Instance)) ilos.Instance { - return Function(f) +type Function struct { + fn interface{} } func (Function) Class() ilos.Class { return class.Function } -func (f Function) GetSlotValue(key ilos.Instance, _ ilos.Class) (ilos.Instance, bool) { +func (Function) GetSlotValue(key ilos.Instance, _ ilos.Class) (ilos.Instance, bool) { return nil, false } @@ -29,3 +55,21 @@ func (Function) SetSlotValue(key ilos.Instance, value ilos.Instance, _ ilos.Clas func (f Function) String() string { return fmt.Sprintf("#%v", f.Class()) } + +func (f Function) Apply(args ilos.Instance, local, global *environment.Environment) (ilos.Instance, ilos.Instance) { + fv := reflect.ValueOf(f.fn) + cdr := args + argv := []reflect.Value{reflect.ValueOf(local), reflect.ValueOf(global)} + for Of(class.Cons, cdr) { + cadr := UnsafeCar(cdr) + cddr := UnsafeCdr(cdr) + argv = append(argv, reflect.ValueOf(cadr)) + cdr = cddr + } + rets := fv.Call(argv) + + a, _ := rets[0].Interface().(ilos.Instance) + b, _ := rets[1].Interface().(ilos.Instance) + return a, b + +} diff --git a/runtime/ilos/instance/instance.go b/runtime/ilos/instance/instance.go index 91606a1..9b3f997 100644 --- a/runtime/ilos/instance/instance.go +++ b/runtime/ilos/instance/instance.go @@ -3,7 +3,6 @@ package instance import ( "fmt" - "github.com/ta2gch/iris/runtime/environment" "github.com/ta2gch/iris/runtime/ilos" "github.com/ta2gch/iris/runtime/ilos/class" ) @@ -15,21 +14,25 @@ import ( func New(c ilos.Class, s ...interface{}) ilos.Instance { switch c { case class.Integer: - return NewInteger(s[0].(int)) + return Integer(s[0].(int)) case class.Float: - return NewFloat(s[0].(float64)) + return Float(s[0].(float64)) case class.String: - return NewString(s[0].(string)) + return String(s[0].(string)) case class.Symbol: - return NewSymbol(s[0].(string)) + return Symbol(s[0].(string)) case class.Character: - return NewCharacter(s[0].(rune)) + return Character(s[0].(rune)) case class.Function: - return NewFunction(s[0].(func(ilos.Instance, *environment.Environment, *environment.Environment) (ilos.Instance, ilos.Instance))) + return Function{s[0]} case class.Cons: - return NewCons(s[0].(ilos.Instance), s[1].(ilos.Instance)) + return &Cons{s[0].(ilos.Instance), s[1].(ilos.Instance)} case class.Null: - return NewNull() + return Null{} + case class.GeneralVector: + return GeneralVector(s[0].([]ilos.Instance)) + case class.String: + return String(s[0].(string)) default: p := []ilos.Instance{} for _, q := range c.Parents() { diff --git a/runtime/ilos/instance/list.go b/runtime/ilos/instance/list.go index f31df4f..32f0a95 100644 --- a/runtime/ilos/instance/list.go +++ b/runtime/ilos/instance/list.go @@ -16,10 +16,6 @@ type Cons struct { cdr ilos.Instance } -func NewCons(car ilos.Instance, cdr ilos.Instance) ilos.Instance { - return &Cons{car, cdr} -} - func (*Cons) Class() ilos.Class { return class.Cons } @@ -79,10 +75,6 @@ func UnsafeCdr(i ilos.Instance) ilos.Instance { type Null struct{} -func NewNull() ilos.Instance { - return Null{} -} - func (Null) Class() ilos.Class { return class.Null } diff --git a/runtime/ilos/instance/number.go b/runtime/ilos/instance/number.go index a524b5c..e187445 100644 --- a/runtime/ilos/instance/number.go +++ b/runtime/ilos/instance/number.go @@ -13,10 +13,6 @@ import ( type Integer int -func NewInteger(n int) ilos.Instance { - return Integer(n) -} - func (Integer) Class() ilos.Class { return class.Integer } @@ -39,10 +35,6 @@ func (i Integer) String() string { type Float float64 -func NewFloat(n float64) ilos.Instance { - return Float(n) -} - func (Float) Class() ilos.Class { return class.Float } diff --git a/runtime/ilos/instance/symbol.go b/runtime/ilos/instance/symbol.go index 5c5b8b8..73d8b60 100644 --- a/runtime/ilos/instance/symbol.go +++ b/runtime/ilos/instance/symbol.go @@ -11,10 +11,6 @@ import ( type Symbol string -func NewSymbol(n string) ilos.Instance { - return Symbol(n) -} - func (Symbol) Class() ilos.Class { return class.Symbol } diff --git a/runtime/lambda.go b/runtime/lambda.go index 4005263..08800d7 100644 --- a/runtime/lambda.go +++ b/runtime/lambda.go @@ -7,22 +7,13 @@ import ( "github.com/ta2gch/iris/runtime/ilos/instance" ) -func lambda(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { - // args must be a instance of Cons, not Null, and ends with nil - if !instance.Of(class.Cons, args) || !UnsafeEndOfListIsNil(args) { // Checked at the head of test - return nil, instance.New(class.WrongNumberOfArguments, map[string]ilos.Instance{ - "FORM": instance.New(class.Symbol, "LAMBDA"), - "ARGUMENTS": args, - }) - } - lambdaList := instance.UnsafeCar(args) +func lambda(local, global *env.Environment, lambdaList ilos.Instance, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { // lambda-list must be a instance of list and ends with nil if !instance.Of(class.List, lambdaList) || !UnsafeEndOfListIsNil(lambdaList) { // Checked at the head of test return nil, instance.New(class.ParseError, lambdaList, class.List) } - forms := instance.UnsafeCdr(args) // Checked at the top of this function. (EndOfListIsNil) lexical := local - return instance.New(class.Function, func(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { + return instance.Lambda(func(local, global *env.Environment, args ilos.Instance) (ilos.Instance, ilos.Instance) { local.BlockTag = append(lexical.BlockTag, local.BlockTag...) local.TagbodyTag = append(lexical.TagbodyTag, local.TagbodyTag...) local.CatchTag = append(lexical.CatchTag, local.CatchTag...) @@ -88,16 +79,13 @@ func lambda(args ilos.Instance, local *env.Environment, global *env.Environment) fargs = instance.UnsafeCdr(fargs) // Checked at the top of this loop aargs = instance.UnsafeCdr(aargs) // Checked at the top of this loop } - body := forms ret := instance.New(class.Null) var err ilos.Instance - for instance.Of(class.Cons, body) { - exp := instance.UnsafeCar(body) // Checked at the top of this loop - ret, err = Eval(exp, local, global) + for _, form := range forms { + ret, err = Eval(form, local, global) if err != nil { return nil, err } - body = instance.UnsafeCdr(body) // Checked at the top of this loop } return ret, nil }), nil diff --git a/runtime/quote.go b/runtime/quote.go index b7d055f..6b97efc 100644 --- a/runtime/quote.go +++ b/runtime/quote.go @@ -3,17 +3,8 @@ package runtime import ( env "github.com/ta2gch/iris/runtime/environment" "github.com/ta2gch/iris/runtime/ilos" - "github.com/ta2gch/iris/runtime/ilos/class" - "github.com/ta2gch/iris/runtime/ilos/instance" ) -func quote(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { - // args must be a instance of Cons, not Null, and ends with nil - if !instance.Of(class.Cons, args) || !UnsafeEndOfListIsNil(args) || UnsafeListLength(args) != 1 { // Checked at the head of test - return nil, instance.New(class.WrongNumberOfArguments, map[string]ilos.Instance{ - "FORM": instance.New(class.Symbol, "QUOTE"), - "ARGUMENTS": args, - }) - } - return instance.UnsafeCar(args), nil +func quote(local, global *env.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { + return obj, nil } diff --git a/runtime/runtime.go b/runtime/runtime.go index dbfa629..de709a8 100644 --- a/runtime/runtime.go +++ b/runtime/runtime.go @@ -2,17 +2,18 @@ package runtime import ( e "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/ilos/class" i "github.com/ta2gch/iris/runtime/ilos/instance" ) func Init() { - e.TopLevel.Macro.Define(i.NewSymbol("LAMBDA"), i.NewFunction(lambda)) - e.TopLevel.Macro.Define(i.NewSymbol("QUOTE"), i.NewFunction(quote)) - e.TopLevel.Macro.Define(i.NewSymbol("THROW"), i.NewFunction(throw)) - e.TopLevel.Macro.Define(i.NewSymbol("CATCH"), i.NewFunction(catch)) - e.TopLevel.Macro.Define(i.NewSymbol("BLOCK"), i.NewFunction(block)) - e.TopLevel.Macro.Define(i.NewSymbol("RETURN-FROM"), i.NewFunction(returnFrom)) - e.TopLevel.Macro.Define(i.NewSymbol("TAGBODY"), i.NewFunction(tagbody)) - e.TopLevel.Macro.Define(i.NewSymbol("GO"), i.NewFunction(tagbodyGo)) - e.TopLevel.Macro.Define(i.NewSymbol("FUNCTION"), i.NewFunction(function)) + e.TopLevel.Macro.Define(i.New(class.Symbol, "LAMBDA"), i.New(class.Function, lambda)) + e.TopLevel.Macro.Define(i.New(class.Symbol, "QUOTE"), i.New(class.Function, quote)) + e.TopLevel.Macro.Define(i.New(class.Symbol, "THROW"), i.New(class.Function, throw)) + e.TopLevel.Macro.Define(i.New(class.Symbol, "CATCH"), i.New(class.Function, catch)) + e.TopLevel.Macro.Define(i.New(class.Symbol, "BLOCK"), i.New(class.Function, block)) + e.TopLevel.Macro.Define(i.New(class.Symbol, "RETURN-FROM"), i.New(class.Function, returnFrom)) + e.TopLevel.Macro.Define(i.New(class.Symbol, "TAGBODY"), i.New(class.Function, tagbody)) + e.TopLevel.Macro.Define(i.New(class.Symbol, "GO"), i.New(class.Function, tagbodyGo)) + e.TopLevel.Macro.Define(i.New(class.Symbol, "FUNCTION"), i.New(class.Function, function)) } diff --git a/runtime/tagbody.go b/runtime/tagbody.go index 6f33c7d..ea59d82 100644 --- a/runtime/tagbody.go +++ b/runtime/tagbody.go @@ -7,55 +7,36 @@ import ( "github.com/ta2gch/iris/runtime/ilos/instance" ) -func tagbody(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { - // args must be a instance of Cons, not Null, and ends with nil - if !instance.Of(class.Cons, args) || !UnsafeEndOfListIsNil(args) || UnsafeListLength(args) < 2 { // Checked at the head of test - return nil, instance.New(class.WrongNumberOfArguments, map[string]ilos.Instance{ - "FORM": instance.New(class.Symbol, "TAGBODY"), - "ARGUMENTS": args, - }) - } - localTags := []ilos.Instance{} - cdr := args // Checked at the top of this function - for instance.Of(class.Cons, cdr) { - cadr := instance.UnsafeCar(cdr) // Checked at the top of this loop - cddr := instance.UnsafeCdr(cdr) // Checked at the top of this loop +func tagbody(local, global *env.Environment, body ...ilos.Instance) (ilos.Instance, ilos.Instance) { + for idx, cadr := range body { + cddr := instance.New(class.GeneralVector, body[idx+1:]) if !instance.Of(class.Cons, cadr) { - local.TagbodyTag.Define(cadr, nil) - localTags = append(localTags, cadr) + local.TagbodyTag.Define(cadr, cddr) } - cdr = cddr } - cdr = args - for instance.Of(class.Cons, cdr) { - cadr := instance.UnsafeCar(cdr) // Checked at the top of this loop - cddr := instance.UnsafeCdr(cdr) // Checked at the top of this loop + for _, cadr := range body { if instance.Of(class.Cons, cadr) { _, fail := Eval(cadr, local, global) if fail != nil { - tag: + TAG: if instance.Of(class.TagbodyTag, fail) { tag, _ := fail.GetSlotValue(instance.New(class.Symbol, "TAG"), class.Escape) // Checked at the top of this loop found := false - for _, localTag := range localTags { - if tag == localTag { + for _, tag1 := range body { + if tag == tag1 { found = true break } } if found { forms, _ := local.TagbodyTag.Get(tag) // Checked in the function, tagbodyGo - cdddr := forms - for instance.Of(class.Cons, cdddr) { - cadddr := instance.UnsafeCar(cdddr) // Checked at the top of this loop - cddddr := instance.UnsafeCdr(cdddr) // Checked at the top of this loop - if instance.Of(class.Cons, cadddr) { - _, fail = Eval(cadddr, local, global) + for _, form := range forms.(instance.GeneralVector) { + if instance.Of(class.Cons, form) { + _, fail = Eval(form, local, global) if fail != nil { - goto tag + goto TAG } } - cdddr = cddddr } break } @@ -64,25 +45,16 @@ func tagbody(args ilos.Instance, local *env.Environment, global *env.Environment return nil, fail } } - cdr = cddr } return instance.New(class.Null), nil } -func tagbodyGo(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { - // args must be a instance of Cons, not Null, and ends with nil - if !instance.Of(class.Cons, args) || !UnsafeEndOfListIsNil(args) || UnsafeListLength(args) != 1 { // Checked at the head of test - return nil, instance.New(class.WrongNumberOfArguments, map[string]ilos.Instance{ - "FORM": instance.New(class.Symbol, "GO"), - "ARGUMENTS": args, - }) - } - car := instance.UnsafeCar(args) // Checked at the top of this function - if _, ok := local.TagbodyTag.Get(car); !ok { +func tagbodyGo(local, global *env.Environment, tag ilos.Instance) (ilos.Instance, ilos.Instance) { + if _, ok := local.TagbodyTag.Get(tag); !ok { return nil, instance.New(class.SimpleError, map[string]ilos.Instance{ "FORMAT-STRING": instance.New(class.String, "%v is not defined as the tag"), - "FORMAT-ARGUMENTS": car, + "FORMAT-ARGUMENTS": tag, }) } - return nil, instance.New(class.TagbodyTag, map[string]ilos.Instance{"TAG": car}) + return nil, instance.New(class.TagbodyTag, map[string]ilos.Instance{"TAG": tag}) } From 1cf8044c1c1b322da278090ea4e221da80c0c5d3 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Thu, 10 Aug 2017 17:53:26 +0900 Subject: [PATCH 114/228] Changed the order of argumgnets in Eval --- runtime/block.go | 8 ++++---- runtime/catch.go | 8 ++++---- runtime/eval.go | 18 +++++++++--------- runtime/eval_test.go | 8 ++++---- runtime/lambda.go | 2 +- runtime/tagbody.go | 4 ++-- 6 files changed, 24 insertions(+), 24 deletions(-) diff --git a/runtime/block.go b/runtime/block.go index 69b3e26..de4276c 100644 --- a/runtime/block.go +++ b/runtime/block.go @@ -17,7 +17,7 @@ import ( // According to this, the scope of name is dynamic. I guess it should be a static. func block(local, global *env.Environment, tag ilos.Instance, body ...ilos.Instance) (ilos.Instance, ilos.Instance) { var err ilos.Instance - tag, err = Eval(tag, local, global) // Checked at the top of this function + tag, err = Eval(local, global, tag) // Checked at the top of this function if err != nil { return nil, err } @@ -30,7 +30,7 @@ func block(local, global *env.Environment, tag ilos.Instance, body ...ilos.Insta local.BlockTag.Define(tag, nil) var sucess, fail ilos.Instance for _, cadr := range body { - sucess, fail = Eval(cadr, local, global) + sucess, fail = Eval(local, global, cadr) if fail != nil { if instance.Of(class.BlockTag, fail) { tag1, _ := fail.GetSlotValue(instance.New(class.Symbol, "TAG"), class.Escape) // Checked at the head of this condition @@ -47,7 +47,7 @@ func block(local, global *env.Environment, tag ilos.Instance, body ...ilos.Insta func returnFrom(local, global *env.Environment, tag, object ilos.Instance) (ilos.Instance, ilos.Instance) { var err ilos.Instance - tag, err = Eval(tag, local, global) + tag, err = Eval(local, global, tag) if err != nil { return nil, err } @@ -57,7 +57,7 @@ func returnFrom(local, global *env.Environment, tag, object ilos.Instance) (ilos "EXPECTED-CLASS": class.Object, }) } - object, err = Eval(object, local, global) + object, err = Eval(local, global, object) if err != nil { return nil, err } diff --git a/runtime/catch.go b/runtime/catch.go index 900df87..4b31102 100644 --- a/runtime/catch.go +++ b/runtime/catch.go @@ -9,7 +9,7 @@ import ( func catch(local, global *env.Environment, tag ilos.Instance, body ...ilos.Instance) (ilos.Instance, ilos.Instance) { var err ilos.Instance - tag, err = Eval(tag, local, global) + tag, err = Eval(local, global, tag) if err != nil { return nil, err } @@ -19,7 +19,7 @@ func catch(local, global *env.Environment, tag ilos.Instance, body ...ilos.Insta local.CatchTag.Define(tag, nil) var sucess, fail ilos.Instance for _, cadr := range body { - sucess, fail = Eval(cadr, local, global) + sucess, fail = Eval(local, global, cadr) if fail != nil { if instance.Of(class.CatchTag, fail) { tag1, _ := fail.GetSlotValue(instance.New(class.Symbol, "TAG"), class.Escape) // Checked at the head of this condition @@ -36,7 +36,7 @@ func catch(local, global *env.Environment, tag ilos.Instance, body ...ilos.Insta func throw(local, global *env.Environment, tag, object ilos.Instance) (ilos.Instance, ilos.Instance) { var err ilos.Instance - tag, err = Eval(tag, local, global) + tag, err = Eval(local, global, tag) if err != nil { return nil, err } @@ -46,7 +46,7 @@ func throw(local, global *env.Environment, tag, object ilos.Instance) (ilos.Inst "EXPECTED-CLASS": class.Object, }) } - object, err = Eval(object, local, global) + object, err = Eval(local, global, object) if err != nil { return nil, err } diff --git a/runtime/eval.go b/runtime/eval.go index 8603b9d..560d3b8 100644 --- a/runtime/eval.go +++ b/runtime/eval.go @@ -7,7 +7,7 @@ import ( "github.com/ta2gch/iris/runtime/ilos/instance" ) -func evalArguments(args ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { +func evalArguments(local *env.Environment, global *env.Environment, args ilos.Instance) (ilos.Instance, ilos.Instance) { // if args ends here if instance.Of(class.Null, args) { return instance.New(class.Null), nil @@ -21,11 +21,11 @@ func evalArguments(args ilos.Instance, local *env.Environment, global *env.Envir } car := instance.UnsafeCar(args) // Checked there cdr := instance.UnsafeCdr(args) // Checked there - a, err := Eval(car, local, global) + a, err := Eval(local, global, car) if err != nil { return nil, err } - b, err := evalArguments(cdr, local, global) + b, err := evalArguments(local, global, cdr) if err != nil { return nil, err } @@ -33,7 +33,7 @@ func evalArguments(args ilos.Instance, local *env.Environment, global *env.Envir } -func evalFunction(obj ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { +func evalFunction(local *env.Environment, global *env.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { // obj, function call form, must be a instance of Cons, NOT Null, and ends with nil if !instance.Of(class.Cons, obj) || !UnsafeEndOfListIsNil(obj) { return nil, instance.New(class.ParseError, map[string]ilos.Instance{ @@ -51,12 +51,12 @@ func evalFunction(obj ilos.Instance, local *env.Environment, global *env.Environ if instance.Of(class.Cons, car) { caar := instance.UnsafeCar(car) // Checked at the top of this sentence if caar == instance.New(class.Symbol, "LAMBDA") { - fun, err := Eval(car, local, global) + fun, err := Eval(local, global, car) if err != nil { return nil, err } - args, err := evalArguments(cdr, local, global) + args, err := evalArguments(local, global, cdr) if err != nil { return nil, err } @@ -101,7 +101,7 @@ func evalFunction(obj ilos.Instance, local *env.Environment, global *env.Environ fun = f } if fun != nil { - args, err := evalArguments(cdr, local, global) + args, err := evalArguments(local, global, cdr) if err != nil { return nil, err } @@ -121,7 +121,7 @@ func evalFunction(obj ilos.Instance, local *env.Environment, global *env.Environ } // Eval evaluates any classs -func Eval(obj ilos.Instance, local *env.Environment, global *env.Environment) (ilos.Instance, ilos.Instance) { +func Eval(local *env.Environment, global *env.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { if instance.Of(class.Null, obj) { return instance.New(class.Null), nil } @@ -138,7 +138,7 @@ func Eval(obj ilos.Instance, local *env.Environment, global *env.Environment) (i }) } if instance.Of(class.Cons, obj) { - ret, err := evalFunction(obj, local, global) + ret, err := evalFunction(local, global, obj) if err != nil { return nil, err } diff --git a/runtime/eval_test.go b/runtime/eval_test.go index 986c68d..416ef19 100644 --- a/runtime/eval_test.go +++ b/runtime/eval_test.go @@ -29,7 +29,7 @@ func TestEval(t *testing.T) { local.Variable.Define(instance.New(class.Symbol, "PI"), instance.New(class.Float, 3.14)) local.Function.Define(instance.New(class.Symbol, "INC"), instance.New(class.Function, inc2)) local.Macro.Define(instance.New(class.Symbol, "MINC"), instance.New(class.Function, func(local *env.Environment, global *env.Environment, arg ilos.Instance) (ilos.Instance, ilos.Instance) { - ret, err := Eval(instance.New(class.Cons, instance.New(class.Symbol, "INC"), instance.New(class.Cons, arg, instance.New(class.Null))), local, global) + ret, err := Eval(local, global, instance.New(class.Cons, instance.New(class.Symbol, "INC"), instance.New(class.Cons, arg, instance.New(class.Null)))) return ret, err })) type args struct { @@ -100,13 +100,13 @@ func TestEval(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := Eval(tt.args.obj, tt.args.local, tt.args.global) + got, err := Eval(tt.args.local, tt.args.global, tt.args.obj) if (err != nil) != tt.wantErr { - t.Errorf("Eval() error = %v, wantErr %v", err, tt.wantErr) + t.Errorf("Eval(err, tt.wantErr, ) error = %v, wantErr %v") return } if !reflect.DeepEqual(got, tt.want) { - t.Errorf("Eval() = %v, want %v", got, tt.want) + t.Errorf("Eval(got, tt.want, ) = %v, want %v") } }) } diff --git a/runtime/lambda.go b/runtime/lambda.go index 08800d7..44a4f39 100644 --- a/runtime/lambda.go +++ b/runtime/lambda.go @@ -82,7 +82,7 @@ func lambda(local, global *env.Environment, lambdaList ilos.Instance, forms ...i ret := instance.New(class.Null) var err ilos.Instance for _, form := range forms { - ret, err = Eval(form, local, global) + ret, err = Eval(local, global, form) if err != nil { return nil, err } diff --git a/runtime/tagbody.go b/runtime/tagbody.go index ea59d82..4585028 100644 --- a/runtime/tagbody.go +++ b/runtime/tagbody.go @@ -16,7 +16,7 @@ func tagbody(local, global *env.Environment, body ...ilos.Instance) (ilos.Instan } for _, cadr := range body { if instance.Of(class.Cons, cadr) { - _, fail := Eval(cadr, local, global) + _, fail := Eval(local, global, cadr) if fail != nil { TAG: if instance.Of(class.TagbodyTag, fail) { @@ -32,7 +32,7 @@ func tagbody(local, global *env.Environment, body ...ilos.Instance) (ilos.Instan forms, _ := local.TagbodyTag.Get(tag) // Checked in the function, tagbodyGo for _, form := range forms.(instance.GeneralVector) { if instance.Of(class.Cons, form) { - _, fail = Eval(form, local, global) + _, fail = Eval(local, global, form) if fail != nil { goto TAG } From 863222b9c175394fb05674211e905114cf3345b1 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Thu, 10 Aug 2017 17:59:25 +0900 Subject: [PATCH 115/228] Changed the name of interface --- runtime/eval.go | 6 ++-- runtime/ilos/instance/function.go | 25 +-------------- runtime/lambda.go | 51 +++++++++++++++++++++++-------- 3 files changed, 42 insertions(+), 40 deletions(-) diff --git a/runtime/eval.go b/runtime/eval.go index 560d3b8..44f2bfb 100644 --- a/runtime/eval.go +++ b/runtime/eval.go @@ -63,7 +63,7 @@ func evalFunction(local *env.Environment, global *env.Environment, obj ilos.Inst env := env.New() env.DynamicVariable = append(local.DynamicVariable, env.DynamicVariable...) env.CatchTag = append(local.CatchTag, env.CatchTag...) - ret, err := fun.(instance.Callable).Apply(args, env, global) + ret, err := fun.(instance.Applicable).Apply(args, env, global) if err != nil { return nil, err } @@ -86,7 +86,7 @@ func evalFunction(local *env.Environment, global *env.Environment, obj ilos.Inst mac = m } if mac != nil { - ret, err := mac.(instance.Callable).Apply(cdr, local, global) + ret, err := mac.(instance.Applicable).Apply(cdr, local, global) if err != nil { return nil, err } @@ -108,7 +108,7 @@ func evalFunction(local *env.Environment, global *env.Environment, obj ilos.Inst env := env.New() env.DynamicVariable = append(local.DynamicVariable, env.DynamicVariable...) env.CatchTag = append(local.CatchTag, env.CatchTag...) - ret, err := fun.(instance.Callable).Apply(args, env, global) + ret, err := fun.(instance.Applicable).Apply(args, env, global) if err != nil { return nil, err } diff --git a/runtime/ilos/instance/function.go b/runtime/ilos/instance/function.go index 5ec66bb..da8702c 100644 --- a/runtime/ilos/instance/function.go +++ b/runtime/ilos/instance/function.go @@ -9,33 +9,10 @@ import ( "github.com/ta2gch/iris/runtime/ilos/class" ) -type Callable interface { +type Applicable interface { Apply(args ilos.Instance, local, global *environment.Environment) (ilos.Instance, ilos.Instance) } -type Lambda func(*environment.Environment, *environment.Environment, ilos.Instance) (ilos.Instance, ilos.Instance) - -func (Lambda) Class() ilos.Class { - return class.Function -} - -func (Lambda) GetSlotValue(key ilos.Instance, _ ilos.Class) (ilos.Instance, bool) { - return nil, false -} - -func (Lambda) SetSlotValue(key ilos.Instance, value ilos.Instance, _ ilos.Class) bool { - return false -} - -func (f Lambda) String() string { - return fmt.Sprintf("#%v", f.Class()) -} - -func (f Lambda) Apply(args ilos.Instance, local, global *environment.Environment) (ilos.Instance, ilos.Instance) { - a, b := f(local, global, args) - return a, b -} - type Function struct { fn interface{} } diff --git a/runtime/lambda.go b/runtime/lambda.go index 44a4f39..556471a 100644 --- a/runtime/lambda.go +++ b/runtime/lambda.go @@ -1,19 +1,44 @@ package runtime import ( + "fmt" + env "github.com/ta2gch/iris/runtime/environment" "github.com/ta2gch/iris/runtime/ilos" "github.com/ta2gch/iris/runtime/ilos/class" "github.com/ta2gch/iris/runtime/ilos/instance" ) -func lambda(local, global *env.Environment, lambdaList ilos.Instance, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { - // lambda-list must be a instance of list and ends with nil - if !instance.Of(class.List, lambdaList) || !UnsafeEndOfListIsNil(lambdaList) { // Checked at the head of test - return nil, instance.New(class.ParseError, lambdaList, class.List) +type lambdaFunction func(*env.Environment, *env.Environment, ilos.Instance) (ilos.Instance, ilos.Instance) + +func (lambdaFunction) Class() ilos.Class { + return class.Function +} + +func (lambdaFunction) GetSlotValue(key ilos.Instance, _ ilos.Class) (ilos.Instance, bool) { + return nil, false +} + +func (lambdaFunction) SetSlotValue(key ilos.Instance, value ilos.Instance, _ ilos.Class) bool { + return false +} + +func (f lambdaFunction) String() string { + return fmt.Sprintf("#%v", f.Class()) +} + +func (f lambdaFunction) Apply(args ilos.Instance, local, global *env.Environment) (ilos.Instance, ilos.Instance) { + a, b := f(local, global, args) + return a, b +} + +func lambda(local, global *env.Environment, lambdaFunctionList ilos.Instance, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { + // lambdaFunction-list must be a instance of list and ends with nil + if !instance.Of(class.List, lambdaFunctionList) || !UnsafeEndOfListIsNil(lambdaFunctionList) { // Checked at the head of test + return nil, instance.New(class.ParseError, lambdaFunctionList, class.List) } lexical := local - return instance.Lambda(func(local, global *env.Environment, args ilos.Instance) (ilos.Instance, ilos.Instance) { + return lambdaFunction(func(local, global *env.Environment, args ilos.Instance) (ilos.Instance, ilos.Instance) { local.BlockTag = append(lexical.BlockTag, local.BlockTag...) local.TagbodyTag = append(lexical.TagbodyTag, local.TagbodyTag...) local.CatchTag = append(lexical.CatchTag, local.CatchTag...) @@ -28,7 +53,7 @@ func lambda(local, global *env.Environment, lambdaList ilos.Instance, forms ...i "EXPECTED-CLASS": class.List, }) } - cdr := lambdaList + cdr := lambdaFunctionList ok := false for instance.Of(class.Cons, cdr) { car := instance.UnsafeCar(cdr) // Checked at the top of this loop. @@ -38,8 +63,8 @@ func lambda(local, global *env.Environment, lambdaList ilos.Instance, forms ...i if instance.Of(class.List, cdr) && UnsafeListLength(cdr) == 1 { // Checked at the head of test // If fargs has :rest or &rest symbol, The length of aargs must be greater than or equal to 'the length of fargs' - 2. // aargs is a instance of list and ends with nil becauseof the checking at this function. - // lambda-list is a instance of list and ends with nil becauseof the checking at the function, lambda. - if UnsafeListLength(lambdaList)-2 <= UnsafeListLength(args) { + // lambdaFunction-list is a instance of list and ends with nil becauseof the checking at the function, lambdaFunction. + if UnsafeListLength(lambdaFunctionList)-2 <= UnsafeListLength(args) { ok = true break } else { @@ -50,22 +75,22 @@ func lambda(local, global *env.Environment, lambdaList ilos.Instance, forms ...i } } else { return nil, instance.New(class.WrongNumberOfArguments, map[string]ilos.Instance{ - "FORM": instance.New(class.Symbol, "LAMBDA"), - "ARGUMENTS": lambdaList, + "FORM": instance.New(class.Symbol, "lambdaFunction"), + "ARGUMENTS": lambdaFunctionList, }) } } } // If fargs doesn't have them, The length of aargs must be equal to the length of fargs. // aargs is a instance of list and ends nil becauseof the checking at this function. - // lambda-list is a instance of list and ends nil becauseof the checking at the function, lambda. - if !ok && UnsafeListLength(lambdaList) != UnsafeListLength(args) { + // lambdaFunction-list is a instance of list and ends nil becauseof the checking at the function, lambdaFunction. + if !ok && UnsafeListLength(lambdaFunctionList) != UnsafeListLength(args) { return nil, instance.New(class.WrongNumberOfArguments, map[string]ilos.Instance{ "FORM": instance.New(class.Symbol, "ANONYMOUS-FUNCTION"), "ARGUMENTS": args, }) } - fargs := lambdaList + fargs := lambdaFunctionList aargs := args for instance.Of(class.Cons, fargs) && instance.Of(class.Cons, aargs) { key := instance.UnsafeCar(fargs) // Checked at the top of this loop. From fb41947ed9790a634513b7a28254b66cbe1411be Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Thu, 10 Aug 2017 21:25:18 +0900 Subject: [PATCH 116/228] Added test for length of arguments --- runtime/ilos/instance/function.go | 13 ++++++++++--- runtime/lambda.go | 18 +++++++++--------- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/runtime/ilos/instance/function.go b/runtime/ilos/instance/function.go index da8702c..4b70339 100644 --- a/runtime/ilos/instance/function.go +++ b/runtime/ilos/instance/function.go @@ -3,6 +3,7 @@ package instance import ( "fmt" "reflect" + "runtime" "github.com/ta2gch/iris/runtime/environment" "github.com/ta2gch/iris/runtime/ilos" @@ -14,7 +15,7 @@ type Applicable interface { } type Function struct { - fn interface{} + function interface{} } func (Function) Class() ilos.Class { @@ -34,7 +35,8 @@ func (f Function) String() string { } func (f Function) Apply(args ilos.Instance, local, global *environment.Environment) (ilos.Instance, ilos.Instance) { - fv := reflect.ValueOf(f.fn) + fv := reflect.ValueOf(f.function) + ft := reflect.TypeOf(f.function) cdr := args argv := []reflect.Value{reflect.ValueOf(local), reflect.ValueOf(global)} for Of(class.Cons, cdr) { @@ -43,8 +45,13 @@ func (f Function) Apply(args ilos.Instance, local, global *environment.Environme argv = append(argv, reflect.ValueOf(cadr)) cdr = cddr } + if ft.NumIn() != len(argv) && (!ft.IsVariadic() || ft.NumIn()-2 > len(argv)) { + return nil, New(class.WrongNumberOfArguments, map[string]ilos.Instance{ + "FORM": New(class.Symbol, runtime.FuncForPC(fv.Pointer()).Name()), + "ARGUMENTS": args, + }) + } rets := fv.Call(argv) - a, _ := rets[0].Interface().(ilos.Instance) b, _ := rets[1].Interface().(ilos.Instance) return a, b diff --git a/runtime/lambda.go b/runtime/lambda.go index 556471a..eb71ac1 100644 --- a/runtime/lambda.go +++ b/runtime/lambda.go @@ -32,10 +32,10 @@ func (f lambdaFunction) Apply(args ilos.Instance, local, global *env.Environment return a, b } -func lambda(local, global *env.Environment, lambdaFunctionList ilos.Instance, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func lambda(local, global *env.Environment, lambdaList ilos.Instance, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { // lambdaFunction-list must be a instance of list and ends with nil - if !instance.Of(class.List, lambdaFunctionList) || !UnsafeEndOfListIsNil(lambdaFunctionList) { // Checked at the head of test - return nil, instance.New(class.ParseError, lambdaFunctionList, class.List) + if !instance.Of(class.List, lambdaList) || !UnsafeEndOfListIsNil(lambdaList) { // Checked at the head of test + return nil, instance.New(class.ParseError, lambdaList, class.List) } lexical := local return lambdaFunction(func(local, global *env.Environment, args ilos.Instance) (ilos.Instance, ilos.Instance) { @@ -53,7 +53,7 @@ func lambda(local, global *env.Environment, lambdaFunctionList ilos.Instance, fo "EXPECTED-CLASS": class.List, }) } - cdr := lambdaFunctionList + cdr := lambdaList ok := false for instance.Of(class.Cons, cdr) { car := instance.UnsafeCar(cdr) // Checked at the top of this loop. @@ -64,7 +64,7 @@ func lambda(local, global *env.Environment, lambdaFunctionList ilos.Instance, fo // If fargs has :rest or &rest symbol, The length of aargs must be greater than or equal to 'the length of fargs' - 2. // aargs is a instance of list and ends with nil becauseof the checking at this function. // lambdaFunction-list is a instance of list and ends with nil becauseof the checking at the function, lambdaFunction. - if UnsafeListLength(lambdaFunctionList)-2 <= UnsafeListLength(args) { + if UnsafeListLength(lambdaList)-2 <= UnsafeListLength(args) { ok = true break } else { @@ -76,21 +76,21 @@ func lambda(local, global *env.Environment, lambdaFunctionList ilos.Instance, fo } else { return nil, instance.New(class.WrongNumberOfArguments, map[string]ilos.Instance{ "FORM": instance.New(class.Symbol, "lambdaFunction"), - "ARGUMENTS": lambdaFunctionList, + "ARGUMENTS": lambdaList, }) } } } // If fargs doesn't have them, The length of aargs must be equal to the length of fargs. // aargs is a instance of list and ends nil becauseof the checking at this function. - // lambdaFunction-list is a instance of list and ends nil becauseof the checking at the function, lambdaFunction. - if !ok && UnsafeListLength(lambdaFunctionList) != UnsafeListLength(args) { + // lambda-list is a instance of list and ends nil becauseof the checking at the function, lambdaFunction. + if !ok && UnsafeListLength(lambdaList) != UnsafeListLength(args) { return nil, instance.New(class.WrongNumberOfArguments, map[string]ilos.Instance{ "FORM": instance.New(class.Symbol, "ANONYMOUS-FUNCTION"), "ARGUMENTS": args, }) } - fargs := lambdaFunctionList + fargs := lambdaList aargs := args for instance.Of(class.Cons, fargs) && instance.Of(class.Cons, aargs) { key := instance.UnsafeCar(fargs) // Checked at the top of this loop. From bced2af1c996e85d442f3080e790849038b45ed9 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Thu, 10 Aug 2017 22:52:42 +0900 Subject: [PATCH 117/228] Added tests --- runtime/block.go | 2 +- runtime/block_test.go | 47 ++++++++++++++++++++++ runtime/catch_test.go | 47 ++++++++++++++++++++++ runtime/eval_test.go | 65 +++++-------------------------- runtime/ilos/instance/instance.go | 6 +-- runtime/lambda_test.go | 53 +++++++++++++++++++++++++ runtime/runtime.go | 19 --------- runtime/tagbody_test.go | 57 +++++++++++++++++++++++++++ runtime/util.go | 24 ++++++++++++ 9 files changed, 240 insertions(+), 80 deletions(-) create mode 100644 runtime/block_test.go create mode 100644 runtime/catch_test.go create mode 100644 runtime/lambda_test.go delete mode 100644 runtime/runtime.go create mode 100644 runtime/tagbody_test.go diff --git a/runtime/block.go b/runtime/block.go index de4276c..b609401 100644 --- a/runtime/block.go +++ b/runtime/block.go @@ -45,7 +45,7 @@ func block(local, global *env.Environment, tag ilos.Instance, body ...ilos.Insta return sucess, nil } -func returnFrom(local, global *env.Environment, tag, object ilos.Instance) (ilos.Instance, ilos.Instance) { +func return_from(local, global *env.Environment, tag, object ilos.Instance) (ilos.Instance, ilos.Instance) { var err ilos.Instance tag, err = Eval(local, global, tag) if err != nil { diff --git a/runtime/block_test.go b/runtime/block_test.go new file mode 100644 index 0000000..424afb7 --- /dev/null +++ b/runtime/block_test.go @@ -0,0 +1,47 @@ +package runtime + +import ( + "reflect" + "testing" + + env "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/ilos" +) + +func TestBlock(t *testing.T) { + local, global := env.New(), env.TopLevel + defmacro("BLOCK", block) + defmacro("RETURN-FROM", return_from) + defmacro("QUOTE", quote) + type args struct { + local *env.Environment + global *env.Environment + obj ilos.Instance + } + tests := []struct { + name string + args args + want ilos.Instance + wantErr bool + }{ + { + name: "block & return-from", + args: args{local, global, readFromString("(block 'foo 1 (return-from 'foo 1))")}, + want: readFromString("1"), + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := Eval(tt.args.local, tt.args.global, tt.args.obj) + if (err != nil) != tt.wantErr { + t.Errorf("Eval() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("Eval() = %v, want %v", got, tt.want) + t.Errorf("Eval() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/runtime/catch_test.go b/runtime/catch_test.go new file mode 100644 index 0000000..ba0d669 --- /dev/null +++ b/runtime/catch_test.go @@ -0,0 +1,47 @@ +package runtime + +import ( + "reflect" + "testing" + + env "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/ilos" +) + +func TestCatch(t *testing.T) { + local, global := env.New(), env.TopLevel + defmacro("CATCH", catch) + defmacro("THROW", throw) + defmacro("QUOTE", quote) + type args struct { + local *env.Environment + global *env.Environment + obj ilos.Instance + } + tests := []struct { + name string + args args + want ilos.Instance + wantErr bool + }{ + { + name: "catch & throw", + args: args{local, global, readFromString("(catch 'foo 1 (throw 'foo 1))")}, + want: readFromString("1"), + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := Eval(tt.args.local, tt.args.global, tt.args.obj) + if (err != nil) != tt.wantErr { + t.Errorf("Eval() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("Eval() = %v, want %v", got, tt.want) + t.Errorf("Eval() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/runtime/eval_test.go b/runtime/eval_test.go index 416ef19..e955b7f 100644 --- a/runtime/eval_test.go +++ b/runtime/eval_test.go @@ -2,36 +2,25 @@ package runtime import ( "reflect" - "strings" "testing" - "github.com/ta2gch/iris/reader/parser" - "github.com/ta2gch/iris/reader/tokenizer" - env "github.com/ta2gch/iris/runtime/environment" "github.com/ta2gch/iris/runtime/ilos" "github.com/ta2gch/iris/runtime/ilos/class" "github.com/ta2gch/iris/runtime/ilos/instance" ) -func read(s string) ilos.Instance { - e, _ := parser.Parse(tokenizer.New(strings.NewReader(s))) - return e -} - func TestEval(t *testing.T) { - Init() local := env.New() global := env.TopLevel - inc2 := func(local, global *env.Environment, arg ilos.Instance) (ilos.Instance, ilos.Instance) { + defun("INC", func(local, global *env.Environment, arg ilos.Instance) (ilos.Instance, ilos.Instance) { return instance.New(class.Integer, int(arg.(instance.Integer))+1), nil - } - local.Variable.Define(instance.New(class.Symbol, "PI"), instance.New(class.Float, 3.14)) - local.Function.Define(instance.New(class.Symbol, "INC"), instance.New(class.Function, inc2)) - local.Macro.Define(instance.New(class.Symbol, "MINC"), instance.New(class.Function, func(local *env.Environment, global *env.Environment, arg ilos.Instance) (ilos.Instance, ilos.Instance) { + }) + defglobal("PI", instance.New(class.Float, 3.14)) + defmacro("MINC", func(local *env.Environment, global *env.Environment, arg ilos.Instance) (ilos.Instance, ilos.Instance) { ret, err := Eval(local, global, instance.New(class.Cons, instance.New(class.Symbol, "INC"), instance.New(class.Cons, arg, instance.New(class.Null)))) return ret, err - })) + }) type args struct { obj ilos.Instance local *env.Environment @@ -51,62 +40,26 @@ func TestEval(t *testing.T) { }, { name: "local function", - args: args{read("(inc (inc 1))"), local, global}, + args: args{readFromString("(inc (inc 1))"), local, global}, want: instance.New(class.Integer, 3), wantErr: false, }, { name: "local macro", - args: args{read("(minc (minc 1))"), local, global}, + args: args{readFromString("(minc (minc 1))"), local, global}, want: instance.New(class.Integer, 3), wantErr: false, }, - { - name: "lambda form", - args: args{read("((lambda (x)) 1)"), local, global}, - want: instance.New(class.Null), - wantErr: false, - }, - { - name: "lambda form", - args: args{read("((lambda (:rest xs) xs) 1 2)"), local, global}, - want: read("(1 2)"), - wantErr: false, - }, - { - name: "catch & throw", - args: args{read("(catch 'foo 1 (throw 'foo 1))"), local, global}, - want: read("1"), - wantErr: false, - }, - { - name: "block & return-from", - args: args{read("(block 'foo 1 (return-from'foo 1))"), local, global}, - want: read("1"), - wantErr: false, - }, - { - name: "tagbody & go", - args: args{read("(catch 'foo (tagbody (go bar) (throw 'foo 1) bar))"), local, global}, - want: instance.New(class.Null), - wantErr: false, - }, - { - name: "nested tagbody & go", - args: args{read("(catch 'foo (tagbody (tagbody (go bar) (throw 'foo 1) bar (go foobar)) foobar))"), local, global}, - want: instance.New(class.Null), - wantErr: false, - }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got, err := Eval(tt.args.local, tt.args.global, tt.args.obj) if (err != nil) != tt.wantErr { - t.Errorf("Eval(err, tt.wantErr, ) error = %v, wantErr %v") + t.Errorf("Eval() error = %v, wantErr %v", err, tt.wantErr) return } if !reflect.DeepEqual(got, tt.want) { - t.Errorf("Eval(got, tt.want, ) = %v, want %v") + t.Errorf("Eval() = %v, want %v", got, tt.want) } }) } diff --git a/runtime/ilos/instance/instance.go b/runtime/ilos/instance/instance.go index 9b3f997..11cb366 100644 --- a/runtime/ilos/instance/instance.go +++ b/runtime/ilos/instance/instance.go @@ -1,8 +1,7 @@ package instance import ( - "fmt" - + "github.com/k0kubun/pp" "github.com/ta2gch/iris/runtime/ilos" "github.com/ta2gch/iris/runtime/ilos/class" ) @@ -89,6 +88,5 @@ func (i *instance) SetSlotValue(key ilos.Instance, value ilos.Instance, class il } func (i *instance) String() string { - class := fmt.Sprint(i.class) - return fmt.Sprintf("#%v %v>", class[:len(class)-1], i.slots) + return pp.Sprint(i) } diff --git a/runtime/lambda_test.go b/runtime/lambda_test.go new file mode 100644 index 0000000..4ba59d8 --- /dev/null +++ b/runtime/lambda_test.go @@ -0,0 +1,53 @@ +package runtime + +import ( + "reflect" + "testing" + + env "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/ilos" + "github.com/ta2gch/iris/runtime/ilos/class" + "github.com/ta2gch/iris/runtime/ilos/instance" +) + +func TestLambda(t *testing.T) { + local, global := env.New(), env.TopLevel + defmacro("LAMBDA", lambda) + type args struct { + local *env.Environment + global *env.Environment + obj ilos.Instance + } + tests := []struct { + name string + args args + want ilos.Instance + wantErr bool + }{ + { + name: "lambda form", + args: args{local, global, readFromString("((lambda (x)) 1)")}, + want: instance.New(class.Null), + wantErr: false, + }, + { + name: "lambda form", + args: args{local, global, readFromString("((lambda (:rest xs) xs) 1 2)")}, + want: readFromString("(1 2)"), + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := Eval(tt.args.local, tt.args.global, tt.args.obj) + if (err != nil) != tt.wantErr { + t.Errorf("Eval() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("Eval() = %v, want %v", got, tt.want) + t.Errorf("Eval() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/runtime/runtime.go b/runtime/runtime.go deleted file mode 100644 index de709a8..0000000 --- a/runtime/runtime.go +++ /dev/null @@ -1,19 +0,0 @@ -package runtime - -import ( - e "github.com/ta2gch/iris/runtime/environment" - "github.com/ta2gch/iris/runtime/ilos/class" - i "github.com/ta2gch/iris/runtime/ilos/instance" -) - -func Init() { - e.TopLevel.Macro.Define(i.New(class.Symbol, "LAMBDA"), i.New(class.Function, lambda)) - e.TopLevel.Macro.Define(i.New(class.Symbol, "QUOTE"), i.New(class.Function, quote)) - e.TopLevel.Macro.Define(i.New(class.Symbol, "THROW"), i.New(class.Function, throw)) - e.TopLevel.Macro.Define(i.New(class.Symbol, "CATCH"), i.New(class.Function, catch)) - e.TopLevel.Macro.Define(i.New(class.Symbol, "BLOCK"), i.New(class.Function, block)) - e.TopLevel.Macro.Define(i.New(class.Symbol, "RETURN-FROM"), i.New(class.Function, returnFrom)) - e.TopLevel.Macro.Define(i.New(class.Symbol, "TAGBODY"), i.New(class.Function, tagbody)) - e.TopLevel.Macro.Define(i.New(class.Symbol, "GO"), i.New(class.Function, tagbodyGo)) - e.TopLevel.Macro.Define(i.New(class.Symbol, "FUNCTION"), i.New(class.Function, function)) -} diff --git a/runtime/tagbody_test.go b/runtime/tagbody_test.go new file mode 100644 index 0000000..685babb --- /dev/null +++ b/runtime/tagbody_test.go @@ -0,0 +1,57 @@ +package runtime + +import ( + "reflect" + "testing" + + env "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/ilos" + "github.com/ta2gch/iris/runtime/ilos/class" + "github.com/ta2gch/iris/runtime/ilos/instance" +) + +func TestTagbody(t *testing.T) { + local, global := env.New(), env.TopLevel + defmacro("TAGBODY", tagbody) + defmacro("GO", tagbodyGo) + defmacro("CATCH", catch) + defmacro("THROW", throw) + defmacro("QUOTE", quote) + type args struct { + local *env.Environment + global *env.Environment + obj ilos.Instance + } + tests := []struct { + name string + args args + want ilos.Instance + wantErr bool + }{ + { + name: "tagbody & go", + args: args{local, global, readFromString("(catch 'foo (tagbody (go bar) (throw 'foo 1) bar))")}, + want: instance.New(class.Null), + wantErr: false, + }, + { + name: "nested tagbody & go", + args: args{local, global, readFromString("(catch 'foo (tagbody (tagbody (go bar) (throw 'foo 1) bar (go foobar)) foobar))")}, + want: instance.New(class.Null), + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := Eval(tt.args.local, tt.args.global, tt.args.obj) + if (err != nil) != tt.wantErr { + t.Errorf("Eval() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("Eval() = %v, want %v", got, tt.want) + t.Errorf("Eval() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/runtime/util.go b/runtime/util.go index 2213a32..0ed201f 100644 --- a/runtime/util.go +++ b/runtime/util.go @@ -1,6 +1,12 @@ package runtime import ( + "strings" + + "github.com/ta2gch/iris/runtime/environment" + + "github.com/ta2gch/iris/reader/parser" + "github.com/ta2gch/iris/reader/tokenizer" "github.com/ta2gch/iris/runtime/ilos" "github.com/ta2gch/iris/runtime/ilos/class" "github.com/ta2gch/iris/runtime/ilos/instance" @@ -32,3 +38,21 @@ func UnsafeListLength(i ilos.Instance) int { } return cnt } + +func readFromString(s string) ilos.Instance { + e, _ := parser.Parse(tokenizer.New(strings.NewReader(s))) + return e +} + +func defmacro(name string, macro interface{}) { + symbol := instance.New(class.Symbol, name) + environment.TopLevel.Macro.Define(symbol, instance.New(class.Function, macro)) +} +func defun(name string, function interface{}) { + symbol := instance.New(class.Symbol, name) + environment.TopLevel.Function.Define(symbol, instance.New(class.Function, function)) +} +func defglobal(name string, value ilos.Instance) { + symbol := instance.New(class.Symbol, name) + environment.TopLevel.Variable.Define(symbol, value) +} From e803f00d41a08b3a2b648c1203affbf47a726703 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Fri, 11 Aug 2017 00:32:43 +0900 Subject: [PATCH 118/228] Changed the order of aruguments in Apply --- runtime/eval.go | 98 +++++++++++++++++++++---------- runtime/ilos/instance/function.go | 60 ++++++++++++++++--- runtime/ilos/instance/instance.go | 5 +- runtime/lambda.go | 90 +++++++--------------------- runtime/util.go | 4 +- 5 files changed, 145 insertions(+), 112 deletions(-) diff --git a/runtime/eval.go b/runtime/eval.go index 44f2bfb..6aa43ae 100644 --- a/runtime/eval.go +++ b/runtime/eval.go @@ -7,7 +7,7 @@ import ( "github.com/ta2gch/iris/runtime/ilos/instance" ) -func evalArguments(local *env.Environment, global *env.Environment, args ilos.Instance) (ilos.Instance, ilos.Instance) { +func evalArguments(local, global *env.Environment, args ilos.Instance) (ilos.Instance, ilos.Instance) { // if args ends here if instance.Of(class.Null, args) { return instance.New(class.Null), nil @@ -33,7 +33,40 @@ func evalArguments(local *env.Environment, global *env.Environment, args ilos.In } -func evalFunction(local *env.Environment, global *env.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { +func evalLambda(local, global *env.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { + // obj, function call form, must be a instance of Cons, NOT Null, and ends with nil + if !instance.Of(class.Cons, obj) || !UnsafeEndOfListIsNil(obj) { + return nil, instance.New(class.ParseError, map[string]ilos.Instance{ + "STRING": obj, + "EXPECTED-CLASS": class.Cons, + }) + } + // get function symbol + car := instance.UnsafeCar(obj) // Checked at the top of this function + + // get function arguments + cdr := instance.UnsafeCdr(obj) // Checked at the top of this function + + fun, err := Eval(local, global, car) + if err != nil { + return nil, err + } + + args, err := evalArguments(local, global, cdr) + if err != nil { + return nil, err + } + env := env.New() + env.DynamicVariable = append(local.DynamicVariable, env.DynamicVariable...) + env.CatchTag = append(local.CatchTag, env.CatchTag...) + ret, err := fun.(instance.Applicable).Apply(env, global, args) + if err != nil { + return nil, err + } + return ret, nil +} + +func evalFunction(local, global *env.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { // obj, function call form, must be a instance of Cons, NOT Null, and ends with nil if !instance.Of(class.Cons, obj) || !UnsafeEndOfListIsNil(obj) { return nil, instance.New(class.ParseError, map[string]ilos.Instance{ @@ -51,23 +84,8 @@ func evalFunction(local *env.Environment, global *env.Environment, obj ilos.Inst if instance.Of(class.Cons, car) { caar := instance.UnsafeCar(car) // Checked at the top of this sentence if caar == instance.New(class.Symbol, "LAMBDA") { - fun, err := Eval(local, global, car) - if err != nil { - return nil, err - } - - args, err := evalArguments(local, global, cdr) - if err != nil { - return nil, err - } - env := env.New() - env.DynamicVariable = append(local.DynamicVariable, env.DynamicVariable...) - env.CatchTag = append(local.CatchTag, env.CatchTag...) - ret, err := fun.(instance.Applicable).Apply(args, env, global) - if err != nil { - return nil, err - } - return ret, nil + ret, err := evalLambda(local, global, obj) + return ret, err } } // if function is not a lambda special form, first element must be a symbol @@ -86,7 +104,15 @@ func evalFunction(local *env.Environment, global *env.Environment, obj ilos.Inst mac = m } if mac != nil { - ret, err := mac.(instance.Applicable).Apply(cdr, local, global) + env := env.New() + env.BlockTag = append(local.BlockTag, env.BlockTag...) + env.TagbodyTag = append(local.TagbodyTag, env.TagbodyTag...) + env.CatchTag = append(local.CatchTag, env.CatchTag...) + env.Variable = append(local.Variable, env.Variable...) + env.Function = append(local.Function, env.Function...) + env.Macro = append(local.Macro, env.Macro...) + env.DynamicVariable = append(local.DynamicVariable, env.DynamicVariable...) + ret, err := mac.(instance.Applicable).Apply(env, global, cdr) if err != nil { return nil, err } @@ -106,9 +132,9 @@ func evalFunction(local *env.Environment, global *env.Environment, obj ilos.Inst return nil, err } env := env.New() - env.DynamicVariable = append(local.DynamicVariable, env.DynamicVariable...) env.CatchTag = append(local.CatchTag, env.CatchTag...) - ret, err := fun.(instance.Applicable).Apply(args, env, global) + env.DynamicVariable = append(local.DynamicVariable, env.DynamicVariable...) + ret, err := fun.(instance.Applicable).Apply(env, global, args) if err != nil { return nil, err } @@ -120,22 +146,30 @@ func evalFunction(local *env.Environment, global *env.Environment, obj ilos.Inst }) } +func evalVariable(local, global *env.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { + if val, ok := local.Variable.Get(obj); ok { + return val, nil + } + if val, ok := global.Variable.Get(obj); ok { + return val, nil + } + return nil, instance.New(class.UndefinedVariable, map[string]ilos.Instance{ + "NAME": obj, + "NAMESPACE": instance.New(class.Symbol, "VARIABLE"), + }) +} + // Eval evaluates any classs -func Eval(local *env.Environment, global *env.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { +func Eval(local, global *env.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { if instance.Of(class.Null, obj) { return instance.New(class.Null), nil } if instance.Of(class.Symbol, obj) { - if val, ok := local.Variable.Get(obj); ok { - return val, nil - } - if val, ok := global.Variable.Get(obj); ok { - return val, nil + ret, err := evalVariable(local, global, obj) + if err != nil { + return nil, err } - return nil, instance.New(class.UndefinedVariable, map[string]ilos.Instance{ - "NAME": obj, - "NAMESPACE": instance.New(class.Symbol, "VARIABLE"), - }) + return ret, nil } if instance.Of(class.Cons, obj) { ret, err := evalFunction(local, global, obj) diff --git a/runtime/ilos/instance/function.go b/runtime/ilos/instance/function.go index 4b70339..593a1e5 100644 --- a/runtime/ilos/instance/function.go +++ b/runtime/ilos/instance/function.go @@ -11,30 +11,31 @@ import ( ) type Applicable interface { - Apply(args ilos.Instance, local, global *environment.Environment) (ilos.Instance, ilos.Instance) + Apply(*environment.Environment, *environment.Environment, ilos.Instance) (ilos.Instance, ilos.Instance) } -type Function struct { +type NativeFunction struct { + name Symbol function interface{} } -func (Function) Class() ilos.Class { +func (NativeFunction) Class() ilos.Class { return class.Function } -func (Function) GetSlotValue(key ilos.Instance, _ ilos.Class) (ilos.Instance, bool) { +func (NativeFunction) GetSlotValue(key ilos.Instance, _ ilos.Class) (ilos.Instance, bool) { return nil, false } -func (Function) SetSlotValue(key ilos.Instance, value ilos.Instance, _ ilos.Class) bool { +func (NativeFunction) SetSlotValue(key ilos.Instance, value ilos.Instance, _ ilos.Class) bool { return false } -func (f Function) String() string { +func (f NativeFunction) String() string { return fmt.Sprintf("#%v", f.Class()) } -func (f Function) Apply(args ilos.Instance, local, global *environment.Environment) (ilos.Instance, ilos.Instance) { +func (f NativeFunction) Apply(local, global *environment.Environment, args ilos.Instance) (ilos.Instance, ilos.Instance) { fv := reflect.ValueOf(f.function) ft := reflect.TypeOf(f.function) cdr := args @@ -57,3 +58,48 @@ func (f Function) Apply(args ilos.Instance, local, global *environment.Environme return a, b } + +type Function struct { + name Symbol + function interface{} + min int + max int +} + +func (Function) Class() ilos.Class { + return class.Function +} + +func (Function) GetSlotValue(key ilos.Instance, _ ilos.Class) (ilos.Instance, bool) { + return nil, false +} + +func (Function) SetSlotValue(key ilos.Instance, value ilos.Instance, _ ilos.Class) bool { + return false +} + +func (f Function) String() string { + return fmt.Sprintf("#%v", f.Class()) +} + +func (f Function) Apply(local, global *environment.Environment, args ilos.Instance) (ilos.Instance, ilos.Instance) { + cnt := 0 + cdr := args + for Of(class.Cons, cdr) { + cadr := UnsafeCar(cdr) + cddr := UnsafeCdr(cdr) + cnt++ + if cadr == New(class.Symbol, ":REST") || cadr == New(class.Symbol, "&REST") { + break + } + cdr = cddr + } + if cnt < f.min || f.max < cnt { + return nil, New(class.WrongNumberOfArguments, map[string]ilos.Instance{ + "FORM": New(class.Symbol, f.name), + "ARGUMENTS": args, + }) + } + a, b := f.function.(func(*environment.Environment, *environment.Environment, ilos.Instance) (ilos.Instance, ilos.Instance))(local, global, args) + return a, b +} diff --git a/runtime/ilos/instance/instance.go b/runtime/ilos/instance/instance.go index 11cb366..365ba0d 100644 --- a/runtime/ilos/instance/instance.go +++ b/runtime/ilos/instance/instance.go @@ -23,7 +23,10 @@ func New(c ilos.Class, s ...interface{}) ilos.Instance { case class.Character: return Character(s[0].(rune)) case class.Function: - return Function{s[0]} + if len(s) == 4 { + return Function{s[0].(Symbol), s[1], s[2].(int), s[3].(int)} + } + return NativeFunction{s[0].(Symbol), s[1]} case class.Cons: return &Cons{s[0].(ilos.Instance), s[1].(ilos.Instance)} case class.Null: diff --git a/runtime/lambda.go b/runtime/lambda.go index eb71ac1..502e2ab 100644 --- a/runtime/lambda.go +++ b/runtime/lambda.go @@ -1,7 +1,7 @@ package runtime import ( - "fmt" + "math" env "github.com/ta2gch/iris/runtime/environment" "github.com/ta2gch/iris/runtime/ilos" @@ -9,36 +9,30 @@ import ( "github.com/ta2gch/iris/runtime/ilos/instance" ) -type lambdaFunction func(*env.Environment, *env.Environment, ilos.Instance) (ilos.Instance, ilos.Instance) - -func (lambdaFunction) Class() ilos.Class { - return class.Function -} - -func (lambdaFunction) GetSlotValue(key ilos.Instance, _ ilos.Class) (ilos.Instance, bool) { - return nil, false -} - -func (lambdaFunction) SetSlotValue(key ilos.Instance, value ilos.Instance, _ ilos.Class) bool { - return false -} - -func (f lambdaFunction) String() string { - return fmt.Sprintf("#%v", f.Class()) -} - -func (f lambdaFunction) Apply(args ilos.Instance, local, global *env.Environment) (ilos.Instance, ilos.Instance) { - a, b := f(local, global, args) - return a, b -} - func lambda(local, global *env.Environment, lambdaList ilos.Instance, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { // lambdaFunction-list must be a instance of list and ends with nil if !instance.Of(class.List, lambdaList) || !UnsafeEndOfListIsNil(lambdaList) { // Checked at the head of test return nil, instance.New(class.ParseError, lambdaList, class.List) } lexical := local - return lambdaFunction(func(local, global *env.Environment, args ilos.Instance) (ilos.Instance, ilos.Instance) { + cdr := lambdaList + cnt := 0 + min := 0 + max := 0 + for instance.Of(class.Cons, cdr) { + cadr := instance.UnsafeCar(cdr) + cddr := instance.UnsafeCdr(cdr) + cnt++ + if cadr == instance.New(class.Symbol, ":REST") || cadr == instance.New(class.Symbol, "&REST") { + min = cnt + max = math.MaxInt64 + break + } + min = cnt + max = cnt + cdr = cddr + } + return instance.New(class.Function, instance.New(class.Symbol, "ANONYMOUS-FUNCTION"), func(local, global *env.Environment, args ilos.Instance) (ilos.Instance, ilos.Instance) { local.BlockTag = append(lexical.BlockTag, local.BlockTag...) local.TagbodyTag = append(lexical.TagbodyTag, local.TagbodyTag...) local.CatchTag = append(lexical.CatchTag, local.CatchTag...) @@ -46,50 +40,6 @@ func lambda(local, global *env.Environment, lambdaList ilos.Instance, forms ...i local.Function = append(lexical.Function, local.Function...) local.Macro = append(lexical.Macro, local.Macro...) local.DynamicVariable = append(lexical.DynamicVariable, local.DynamicVariable...) - // args must be a instance of list and end with nil - if !instance.Of(class.List, args) || !UnsafeEndOfListIsNil(args) { // Checked at the head of test - return nil, instance.New(class.DomainError, map[string]ilos.Instance{ - "OBJECT": args, - "EXPECTED-CLASS": class.List, - }) - } - cdr := lambdaList - ok := false - for instance.Of(class.Cons, cdr) { - car := instance.UnsafeCar(cdr) // Checked at the top of this loop. - cdr = instance.UnsafeCdr(cdr) // Checked at the top of this loop. - if car == instance.New(class.Symbol, ":REST") || car == instance.New(class.Symbol, "&REST") { - // fargs has only one symbol after &rest or :rest symbol. - if instance.Of(class.List, cdr) && UnsafeListLength(cdr) == 1 { // Checked at the head of test - // If fargs has :rest or &rest symbol, The length of aargs must be greater than or equal to 'the length of fargs' - 2. - // aargs is a instance of list and ends with nil becauseof the checking at this function. - // lambdaFunction-list is a instance of list and ends with nil becauseof the checking at the function, lambdaFunction. - if UnsafeListLength(lambdaList)-2 <= UnsafeListLength(args) { - ok = true - break - } else { - return nil, instance.New(class.WrongNumberOfArguments, map[string]ilos.Instance{ - "FORM": instance.New(class.Symbol, "ANONYMOUS-FUNCTION"), - "ARGUMENTS": args, - }) - } - } else { - return nil, instance.New(class.WrongNumberOfArguments, map[string]ilos.Instance{ - "FORM": instance.New(class.Symbol, "lambdaFunction"), - "ARGUMENTS": lambdaList, - }) - } - } - } - // If fargs doesn't have them, The length of aargs must be equal to the length of fargs. - // aargs is a instance of list and ends nil becauseof the checking at this function. - // lambda-list is a instance of list and ends nil becauseof the checking at the function, lambdaFunction. - if !ok && UnsafeListLength(lambdaList) != UnsafeListLength(args) { - return nil, instance.New(class.WrongNumberOfArguments, map[string]ilos.Instance{ - "FORM": instance.New(class.Symbol, "ANONYMOUS-FUNCTION"), - "ARGUMENTS": args, - }) - } fargs := lambdaList aargs := args for instance.Of(class.Cons, fargs) && instance.Of(class.Cons, aargs) { @@ -113,5 +63,5 @@ func lambda(local, global *env.Environment, lambdaList ilos.Instance, forms ...i } } return ret, nil - }), nil + }, min, max), nil } diff --git a/runtime/util.go b/runtime/util.go index 0ed201f..6164326 100644 --- a/runtime/util.go +++ b/runtime/util.go @@ -46,11 +46,11 @@ func readFromString(s string) ilos.Instance { func defmacro(name string, macro interface{}) { symbol := instance.New(class.Symbol, name) - environment.TopLevel.Macro.Define(symbol, instance.New(class.Function, macro)) + environment.TopLevel.Macro.Define(symbol, instance.New(class.Function, symbol, macro)) } func defun(name string, function interface{}) { symbol := instance.New(class.Symbol, name) - environment.TopLevel.Function.Define(symbol, instance.New(class.Function, function)) + environment.TopLevel.Function.Define(symbol, instance.New(class.Function, symbol, function)) } func defglobal(name string, value ilos.Instance) { symbol := instance.New(class.Symbol, name) From 16cb45d65d0700c665965d8f3996404412c06dc8 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Fri, 11 Aug 2017 01:01:45 +0900 Subject: [PATCH 119/228] Changed the test for arguments --- runtime/ilos/instance/function.go | 46 ++++++++++++++++--------------- runtime/ilos/instance/instance.go | 4 +-- runtime/lambda.go | 28 ++++--------------- 3 files changed, 32 insertions(+), 46 deletions(-) diff --git a/runtime/ilos/instance/function.go b/runtime/ilos/instance/function.go index 593a1e5..9dfa08f 100644 --- a/runtime/ilos/instance/function.go +++ b/runtime/ilos/instance/function.go @@ -3,7 +3,6 @@ package instance import ( "fmt" "reflect" - "runtime" "github.com/ta2gch/iris/runtime/environment" "github.com/ta2gch/iris/runtime/ilos" @@ -48,7 +47,7 @@ func (f NativeFunction) Apply(local, global *environment.Environment, args ilos. } if ft.NumIn() != len(argv) && (!ft.IsVariadic() || ft.NumIn()-2 > len(argv)) { return nil, New(class.WrongNumberOfArguments, map[string]ilos.Instance{ - "FORM": New(class.Symbol, runtime.FuncForPC(fv.Pointer()).Name()), + "FORM": f.name, "ARGUMENTS": args, }) } @@ -60,10 +59,9 @@ func (f NativeFunction) Apply(local, global *environment.Environment, args ilos. } type Function struct { - name Symbol - function interface{} - min int - max int + name Symbol + lambdaList ilos.Instance + function interface{} } func (Function) Class() ilos.Class { @@ -83,23 +81,27 @@ func (f Function) String() string { } func (f Function) Apply(local, global *environment.Environment, args ilos.Instance) (ilos.Instance, ilos.Instance) { - cnt := 0 - cdr := args - for Of(class.Cons, cdr) { - cadr := UnsafeCar(cdr) - cddr := UnsafeCdr(cdr) - cnt++ - if cadr == New(class.Symbol, ":REST") || cadr == New(class.Symbol, "&REST") { - break + a := args + b := f.lambdaList + for Of(class.Cons, a) && Of(class.Cons, b) { + car := UnsafeCar(b) + if car == New(class.Symbol, ":REST") || car == New(class.Symbol, "&REST") { + c, d := f.function.(func(*environment.Environment, *environment.Environment, ilos.Instance) (ilos.Instance, ilos.Instance))(local, global, args) + return c, d } - cdr = cddr + a = UnsafeCdr(a) + b = UnsafeCdr(b) } - if cnt < f.min || f.max < cnt { - return nil, New(class.WrongNumberOfArguments, map[string]ilos.Instance{ - "FORM": New(class.Symbol, f.name), - "ARGUMENTS": args, - }) + if Of(class.Cons, a) && (UnsafeCar(a) == New(class.Symbol, ":REST") || UnsafeCar(a) == New(class.Symbol, "&REST")) { + c, d := f.function.(func(*environment.Environment, *environment.Environment, ilos.Instance) (ilos.Instance, ilos.Instance))(local, global, args) + return c, d } - a, b := f.function.(func(*environment.Environment, *environment.Environment, ilos.Instance) (ilos.Instance, ilos.Instance))(local, global, args) - return a, b + if Of(class.Null, a) && Of(class.Null, b) { + c, d := f.function.(func(*environment.Environment, *environment.Environment, ilos.Instance) (ilos.Instance, ilos.Instance))(local, global, args) + return c, d + } + return nil, New(class.WrongNumberOfArguments, map[string]ilos.Instance{ + "FORM": New(class.Symbol, f.name), + "ARGUMENTS": args, + }) } diff --git a/runtime/ilos/instance/instance.go b/runtime/ilos/instance/instance.go index 365ba0d..95baac2 100644 --- a/runtime/ilos/instance/instance.go +++ b/runtime/ilos/instance/instance.go @@ -23,8 +23,8 @@ func New(c ilos.Class, s ...interface{}) ilos.Instance { case class.Character: return Character(s[0].(rune)) case class.Function: - if len(s) == 4 { - return Function{s[0].(Symbol), s[1], s[2].(int), s[3].(int)} + if len(s) == 3 { + return Function{s[0].(Symbol), s[1].(ilos.Instance), s[2]} } return NativeFunction{s[0].(Symbol), s[1]} case class.Cons: diff --git a/runtime/lambda.go b/runtime/lambda.go index 502e2ab..73fe428 100644 --- a/runtime/lambda.go +++ b/runtime/lambda.go @@ -1,8 +1,6 @@ package runtime import ( - "math" - env "github.com/ta2gch/iris/runtime/environment" "github.com/ta2gch/iris/runtime/ilos" "github.com/ta2gch/iris/runtime/ilos/class" @@ -12,27 +10,13 @@ import ( func lambda(local, global *env.Environment, lambdaList ilos.Instance, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { // lambdaFunction-list must be a instance of list and ends with nil if !instance.Of(class.List, lambdaList) || !UnsafeEndOfListIsNil(lambdaList) { // Checked at the head of test - return nil, instance.New(class.ParseError, lambdaList, class.List) + return nil, instance.New(class.DomainError, map[string]ilos.Instance{ + "OBJECT": lambdaList, + "EXPECTED-CLASS": class.List, + }) } lexical := local - cdr := lambdaList - cnt := 0 - min := 0 - max := 0 - for instance.Of(class.Cons, cdr) { - cadr := instance.UnsafeCar(cdr) - cddr := instance.UnsafeCdr(cdr) - cnt++ - if cadr == instance.New(class.Symbol, ":REST") || cadr == instance.New(class.Symbol, "&REST") { - min = cnt - max = math.MaxInt64 - break - } - min = cnt - max = cnt - cdr = cddr - } - return instance.New(class.Function, instance.New(class.Symbol, "ANONYMOUS-FUNCTION"), func(local, global *env.Environment, args ilos.Instance) (ilos.Instance, ilos.Instance) { + return instance.New(class.Function, instance.New(class.Symbol, "ANONYMOUS-FUNCTION"), lambdaList, func(local, global *env.Environment, args ilos.Instance) (ilos.Instance, ilos.Instance) { local.BlockTag = append(lexical.BlockTag, local.BlockTag...) local.TagbodyTag = append(lexical.TagbodyTag, local.TagbodyTag...) local.CatchTag = append(lexical.CatchTag, local.CatchTag...) @@ -63,5 +47,5 @@ func lambda(local, global *env.Environment, lambdaList ilos.Instance, forms ...i } } return ret, nil - }, min, max), nil + }), nil } From 060757768e8c98d4e5f9dce90c9e8aa850c63f05 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Fri, 11 Aug 2017 11:10:40 +0900 Subject: [PATCH 120/228] refactor lambda --- runtime/ilos/instance/function.go | 60 ++++--------------------------- runtime/ilos/instance/instance.go | 5 +-- runtime/lambda.go | 42 ++++++++++++++++------ runtime/lambda_test.go | 22 ++++++++++-- 4 files changed, 59 insertions(+), 70 deletions(-) diff --git a/runtime/ilos/instance/function.go b/runtime/ilos/instance/function.go index 9dfa08f..59a7b04 100644 --- a/runtime/ilos/instance/function.go +++ b/runtime/ilos/instance/function.go @@ -13,28 +13,28 @@ type Applicable interface { Apply(*environment.Environment, *environment.Environment, ilos.Instance) (ilos.Instance, ilos.Instance) } -type NativeFunction struct { +type Function struct { name Symbol function interface{} } -func (NativeFunction) Class() ilos.Class { +func (Function) Class() ilos.Class { return class.Function } -func (NativeFunction) GetSlotValue(key ilos.Instance, _ ilos.Class) (ilos.Instance, bool) { +func (Function) GetSlotValue(key ilos.Instance, _ ilos.Class) (ilos.Instance, bool) { return nil, false } -func (NativeFunction) SetSlotValue(key ilos.Instance, value ilos.Instance, _ ilos.Class) bool { +func (Function) SetSlotValue(key ilos.Instance, value ilos.Instance, _ ilos.Class) bool { return false } -func (f NativeFunction) String() string { +func (f Function) String() string { return fmt.Sprintf("#%v", f.Class()) } -func (f NativeFunction) Apply(local, global *environment.Environment, args ilos.Instance) (ilos.Instance, ilos.Instance) { +func (f Function) Apply(local, global *environment.Environment, args ilos.Instance) (ilos.Instance, ilos.Instance) { fv := reflect.ValueOf(f.function) ft := reflect.TypeOf(f.function) cdr := args @@ -57,51 +57,3 @@ func (f NativeFunction) Apply(local, global *environment.Environment, args ilos. return a, b } - -type Function struct { - name Symbol - lambdaList ilos.Instance - function interface{} -} - -func (Function) Class() ilos.Class { - return class.Function -} - -func (Function) GetSlotValue(key ilos.Instance, _ ilos.Class) (ilos.Instance, bool) { - return nil, false -} - -func (Function) SetSlotValue(key ilos.Instance, value ilos.Instance, _ ilos.Class) bool { - return false -} - -func (f Function) String() string { - return fmt.Sprintf("#%v", f.Class()) -} - -func (f Function) Apply(local, global *environment.Environment, args ilos.Instance) (ilos.Instance, ilos.Instance) { - a := args - b := f.lambdaList - for Of(class.Cons, a) && Of(class.Cons, b) { - car := UnsafeCar(b) - if car == New(class.Symbol, ":REST") || car == New(class.Symbol, "&REST") { - c, d := f.function.(func(*environment.Environment, *environment.Environment, ilos.Instance) (ilos.Instance, ilos.Instance))(local, global, args) - return c, d - } - a = UnsafeCdr(a) - b = UnsafeCdr(b) - } - if Of(class.Cons, a) && (UnsafeCar(a) == New(class.Symbol, ":REST") || UnsafeCar(a) == New(class.Symbol, "&REST")) { - c, d := f.function.(func(*environment.Environment, *environment.Environment, ilos.Instance) (ilos.Instance, ilos.Instance))(local, global, args) - return c, d - } - if Of(class.Null, a) && Of(class.Null, b) { - c, d := f.function.(func(*environment.Environment, *environment.Environment, ilos.Instance) (ilos.Instance, ilos.Instance))(local, global, args) - return c, d - } - return nil, New(class.WrongNumberOfArguments, map[string]ilos.Instance{ - "FORM": New(class.Symbol, f.name), - "ARGUMENTS": args, - }) -} diff --git a/runtime/ilos/instance/instance.go b/runtime/ilos/instance/instance.go index 95baac2..d557cf5 100644 --- a/runtime/ilos/instance/instance.go +++ b/runtime/ilos/instance/instance.go @@ -23,10 +23,7 @@ func New(c ilos.Class, s ...interface{}) ilos.Instance { case class.Character: return Character(s[0].(rune)) case class.Function: - if len(s) == 3 { - return Function{s[0].(Symbol), s[1].(ilos.Instance), s[2]} - } - return NativeFunction{s[0].(Symbol), s[1]} + return Function{s[0].(Symbol), s[1]} case class.Cons: return &Cons{s[0].(ilos.Instance), s[1].(ilos.Instance)} case class.Null: diff --git a/runtime/lambda.go b/runtime/lambda.go index 73fe428..711e60e 100644 --- a/runtime/lambda.go +++ b/runtime/lambda.go @@ -16,7 +16,19 @@ func lambda(local, global *env.Environment, lambdaList ilos.Instance, forms ...i }) } lexical := local - return instance.New(class.Function, instance.New(class.Symbol, "ANONYMOUS-FUNCTION"), lambdaList, func(local, global *env.Environment, args ilos.Instance) (ilos.Instance, ilos.Instance) { + cdr := lambdaList + parameters := []ilos.Instance{} + variadic := false + for instance.Of(class.Cons, cdr) { + cadr := instance.UnsafeCar(cdr) + if cadr == instance.New(class.Symbol, ":REST") || cadr == instance.New(class.Symbol, "&REST") { + variadic = true + } + parameters = append(parameters, cadr) + cdr = instance.UnsafeCdr(cdr) + } + name := instance.New(class.Symbol, "ANONYMOUS-FUNCTION") + return instance.New(class.Function, name, func(local, global *env.Environment, args ...ilos.Instance) (ilos.Instance, ilos.Instance) { local.BlockTag = append(lexical.BlockTag, local.BlockTag...) local.TagbodyTag = append(lexical.TagbodyTag, local.TagbodyTag...) local.CatchTag = append(lexical.CatchTag, local.CatchTag...) @@ -24,19 +36,29 @@ func lambda(local, global *env.Environment, lambdaList ilos.Instance, forms ...i local.Function = append(lexical.Function, local.Function...) local.Macro = append(lexical.Macro, local.Macro...) local.DynamicVariable = append(lexical.DynamicVariable, local.DynamicVariable...) - fargs := lambdaList - aargs := args - for instance.Of(class.Cons, fargs) && instance.Of(class.Cons, aargs) { - key := instance.UnsafeCar(fargs) // Checked at the top of this loop. - value := instance.UnsafeCar(aargs) // Checked at the top of this loop. + if (variadic && len(parameters)-2 > len(args)) || (!variadic && len(parameters) != len(args)) { + v := instance.New(class.Null) + for i := len(args) - 1; i >= 0; i-- { + v = instance.New(class.Cons, args[i], v) + } + return nil, instance.New(class.WrongNumberOfArguments, map[string]ilos.Instance{ + "FORM": name, + "ARGUMENTS": v, + }) + } + for idx := range parameters { + key := parameters[idx] if key == instance.New(class.Symbol, ":REST") || key == instance.New(class.Symbol, "&REST") { - cadr := instance.UnsafeCar(instance.UnsafeCdr(fargs)) // Checked before type checking secion - local.Variable.Define(cadr, aargs) + key := parameters[idx+1] + value := instance.New(class.Null) + for i := len(args) - 1; i >= idx; i-- { + value = instance.New(class.Cons, args[i], value) + } + local.Variable.Define(key, value) break } + value := args[idx] local.Variable.Define(key, value) - fargs = instance.UnsafeCdr(fargs) // Checked at the top of this loop - aargs = instance.UnsafeCdr(aargs) // Checked at the top of this loop } ret := instance.New(class.Null) var err ilos.Instance diff --git a/runtime/lambda_test.go b/runtime/lambda_test.go index 4ba59d8..8705af2 100644 --- a/runtime/lambda_test.go +++ b/runtime/lambda_test.go @@ -25,17 +25,35 @@ func TestLambda(t *testing.T) { wantErr bool }{ { - name: "lambda form", + name: "case1", args: args{local, global, readFromString("((lambda (x)) 1)")}, want: instance.New(class.Null), wantErr: false, }, { - name: "lambda form", + name: "case2", args: args{local, global, readFromString("((lambda (:rest xs) xs) 1 2)")}, want: readFromString("(1 2)"), wantErr: false, }, + { + name: "case3", + args: args{local, global, readFromString("((lambda (:rest xs) xs))")}, + want: readFromString("nil"), + wantErr: false, + }, + { + name: "case4", + args: args{local, global, readFromString("((lambda (x) x) 1 2)")}, + want: nil, + wantErr: true, + }, + { + name: "case5", + args: args{local, global, readFromString("((lambda (x :rest xs) x))")}, + want: nil, + wantErr: true, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { From 54625f3e3fd59eea7ca42f029bc7dc5d6dfc4752 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Fri, 11 Aug 2017 11:18:26 +0900 Subject: [PATCH 121/228] refactor --- reader/parser/parser_test.go | 46 +++++++++++++++---------------- runtime/block.go | 6 ++-- runtime/block_test.go | 16 +++++------ runtime/catch.go | 6 ++-- runtime/catch_test.go | 28 +++++++++---------- runtime/eval.go | 40 +++++++++++++-------------- runtime/eval_test.go | 26 ++++++++--------- runtime/function.go | 4 +-- runtime/ilos/instance/function.go | 6 ++-- runtime/lambda.go | 18 ++++++------ runtime/lambda_test.go | 24 ++++++++-------- runtime/quote.go | 4 +-- runtime/tagbody.go | 6 ++-- runtime/tagbody_test.go | 18 ++++++------ 14 files changed, 124 insertions(+), 124 deletions(-) diff --git a/reader/parser/parser_test.go b/reader/parser/parser_test.go index 6138e9e..06b0fd5 100644 --- a/reader/parser/parser_test.go +++ b/reader/parser/parser_test.go @@ -10,12 +10,12 @@ import ( ) func Test_parseAtom(t *testing.T) { - type args struct { + type arguments struct { tok string } tests := []struct { name string - args args + arguments arguments want ilos.Instance wantErr bool }{ @@ -24,43 +24,43 @@ func Test_parseAtom(t *testing.T) { // { name: "default", - args: args{"3.14"}, + arguments: arguments{"3.14"}, want: instance.New(class.Float, 3.14), wantErr: false, }, { name: "signed", - args: args{"-5.0"}, + arguments: arguments{"-5.0"}, want: instance.New(class.Float, -5.0), wantErr: false, }, { name: "exponential", - args: args{"-5.0E3"}, + arguments: arguments{"-5.0E3"}, want: instance.New(class.Float, -5.0*1000), wantErr: false, }, { name: "signed exponential", - args: args{"5.0E-3"}, + arguments: arguments{"5.0E-3"}, want: instance.New(class.Float, 5.0*1.0/1000.0), wantErr: false, }, { name: "without point", - args: args{"5E-3"}, + arguments: arguments{"5E-3"}, want: instance.New(class.Float, 5.0*1.0/1000.0), wantErr: false, }, { name: "invalid case", - args: args{"3E-3.0"}, + arguments: arguments{"3E-3.0"}, want: nil, wantErr: true, }, { name: "without point", - args: args{"5E-"}, + arguments: arguments{"5E-"}, want: nil, wantErr: true, }, @@ -69,55 +69,55 @@ func Test_parseAtom(t *testing.T) { // { name: "default", - args: args{"5"}, + arguments: arguments{"5"}, want: instance.New(class.Integer, 5), wantErr: false, }, { name: "signed", - args: args{"-5"}, + arguments: arguments{"-5"}, want: instance.New(class.Integer, -5), wantErr: false, }, { name: "binary", - args: args{"#B00101"}, + arguments: arguments{"#B00101"}, want: instance.New(class.Integer, 5), wantErr: false, }, { name: "signed binary", - args: args{"#b+00101"}, + arguments: arguments{"#b+00101"}, want: instance.New(class.Integer, 5), wantErr: false, }, { name: "octal", - args: args{"#o00101"}, + arguments: arguments{"#o00101"}, want: instance.New(class.Integer, 65), wantErr: false, }, { name: "signed octal", - args: args{"#O-00101"}, + arguments: arguments{"#O-00101"}, want: instance.New(class.Integer, -65), wantErr: false, }, { name: "hexadecimal", - args: args{"#X00101"}, + arguments: arguments{"#X00101"}, want: instance.New(class.Integer, 257), wantErr: false, }, { name: "signed hexadecimal", - args: args{"#x-00101"}, + arguments: arguments{"#x-00101"}, want: instance.New(class.Integer, -257), wantErr: false, }, { name: "invalid binary", - args: args{"-#x00101"}, + arguments: arguments{"-#x00101"}, want: nil, wantErr: true, }, @@ -126,32 +126,32 @@ func Test_parseAtom(t *testing.T) { // { name: "default", - args: args{"#\\a"}, + arguments: arguments{"#\\a"}, want: instance.New(class.Character, 'a'), wantErr: false, }, { name: "newline", - args: args{"#\\newline"}, + arguments: arguments{"#\\newline"}, want: instance.New(class.Character, '\n'), wantErr: false, }, { name: "space", - args: args{"#\\space"}, + arguments: arguments{"#\\space"}, want: instance.New(class.Character, ' '), wantErr: false, }, { name: "invalid character name", - args: args{"#\\foo"}, + arguments: arguments{"#\\foo"}, want: nil, wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := parseAtom(tt.args.tok) + got, err := parseAtom(tt.arguments.tok) if (err != nil) != tt.wantErr { t.Errorf("parseAtom() error = %v, wantErr %v", err, tt.wantErr) return diff --git a/runtime/block.go b/runtime/block.go index b609401..4f5d6d1 100644 --- a/runtime/block.go +++ b/runtime/block.go @@ -1,7 +1,7 @@ package runtime import ( - env "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/environment" "github.com/ta2gch/iris/runtime/ilos" "github.com/ta2gch/iris/runtime/ilos/class" "github.com/ta2gch/iris/runtime/ilos/instance" @@ -15,7 +15,7 @@ import ( // The extend of name is dynamic. (islisp-v23.pdf, 43-44) // NOTE: // According to this, the scope of name is dynamic. I guess it should be a static. -func block(local, global *env.Environment, tag ilos.Instance, body ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func block(local, global *environment.Environment, tag ilos.Instance, body ...ilos.Instance) (ilos.Instance, ilos.Instance) { var err ilos.Instance tag, err = Eval(local, global, tag) // Checked at the top of this function if err != nil { @@ -45,7 +45,7 @@ func block(local, global *env.Environment, tag ilos.Instance, body ...ilos.Insta return sucess, nil } -func return_from(local, global *env.Environment, tag, object ilos.Instance) (ilos.Instance, ilos.Instance) { +func return_from(local, global *environment.Environment, tag, object ilos.Instance) (ilos.Instance, ilos.Instance) { var err ilos.Instance tag, err = Eval(local, global, tag) if err != nil { diff --git a/runtime/block_test.go b/runtime/block_test.go index 424afb7..3c62ba5 100644 --- a/runtime/block_test.go +++ b/runtime/block_test.go @@ -4,36 +4,36 @@ import ( "reflect" "testing" - env "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/environment" "github.com/ta2gch/iris/runtime/ilos" ) func TestBlock(t *testing.T) { - local, global := env.New(), env.TopLevel + local, global := environment.New(), environment.TopLevel defmacro("BLOCK", block) defmacro("RETURN-FROM", return_from) defmacro("QUOTE", quote) - type args struct { - local *env.Environment - global *env.Environment + type arguments struct { + local *environment.Environment + global *environment.Environment obj ilos.Instance } tests := []struct { name string - args args + arguments arguments want ilos.Instance wantErr bool }{ { name: "block & return-from", - args: args{local, global, readFromString("(block 'foo 1 (return-from 'foo 1))")}, + arguments: arguments{local, global, readFromString("(block 'foo 1 (return-from 'foo 1))")}, want: readFromString("1"), wantErr: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := Eval(tt.args.local, tt.args.global, tt.args.obj) + got, err := Eval(tt.arguments.local, tt.arguments.global, tt.arguments.obj) if (err != nil) != tt.wantErr { t.Errorf("Eval() error = %v, wantErr %v", err, tt.wantErr) return diff --git a/runtime/catch.go b/runtime/catch.go index 4b31102..5774254 100644 --- a/runtime/catch.go +++ b/runtime/catch.go @@ -1,13 +1,13 @@ package runtime import ( - env "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/environment" "github.com/ta2gch/iris/runtime/ilos" "github.com/ta2gch/iris/runtime/ilos/class" "github.com/ta2gch/iris/runtime/ilos/instance" ) -func catch(local, global *env.Environment, tag ilos.Instance, body ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func catch(local, global *environment.Environment, tag ilos.Instance, body ...ilos.Instance) (ilos.Instance, ilos.Instance) { var err ilos.Instance tag, err = Eval(local, global, tag) if err != nil { @@ -34,7 +34,7 @@ func catch(local, global *env.Environment, tag ilos.Instance, body ...ilos.Insta return sucess, nil } -func throw(local, global *env.Environment, tag, object ilos.Instance) (ilos.Instance, ilos.Instance) { +func throw(local, global *environment.Environment, tag, object ilos.Instance) (ilos.Instance, ilos.Instance) { var err ilos.Instance tag, err = Eval(local, global, tag) if err != nil { diff --git a/runtime/catch_test.go b/runtime/catch_test.go index ba0d669..4d3d6d9 100644 --- a/runtime/catch_test.go +++ b/runtime/catch_test.go @@ -4,36 +4,36 @@ import ( "reflect" "testing" - env "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/environment" "github.com/ta2gch/iris/runtime/ilos" ) func TestCatch(t *testing.T) { - local, global := env.New(), env.TopLevel + local, global := environment.New(), environment.TopLevel defmacro("CATCH", catch) defmacro("THROW", throw) defmacro("QUOTE", quote) - type args struct { - local *env.Environment - global *env.Environment + type arguments struct { + local *environment.Environment + global *environment.Environment obj ilos.Instance } tests := []struct { - name string - args args - want ilos.Instance - wantErr bool + name string + arguments arguments + want ilos.Instance + wantErr bool }{ { - name: "catch & throw", - args: args{local, global, readFromString("(catch 'foo 1 (throw 'foo 1))")}, - want: readFromString("1"), - wantErr: false, + name: "catch & throw", + arguments: arguments{local, global, readFromString("(catch 'foo 1 (throw 'foo 1))")}, + want: readFromString("1"), + wantErr: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := Eval(tt.args.local, tt.args.global, tt.args.obj) + got, err := Eval(tt.arguments.local, tt.arguments.global, tt.arguments.obj) if (err != nil) != tt.wantErr { t.Errorf("Eval() error = %v, wantErr %v", err, tt.wantErr) return diff --git a/runtime/eval.go b/runtime/eval.go index 6aa43ae..c2574bf 100644 --- a/runtime/eval.go +++ b/runtime/eval.go @@ -1,26 +1,26 @@ package runtime import ( - env "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/environment" "github.com/ta2gch/iris/runtime/ilos" "github.com/ta2gch/iris/runtime/ilos/class" "github.com/ta2gch/iris/runtime/ilos/instance" ) -func evalArguments(local, global *env.Environment, args ilos.Instance) (ilos.Instance, ilos.Instance) { - // if args ends here - if instance.Of(class.Null, args) { +func evalArguments(local, global *environment.Environment, arguments ilos.Instance) (ilos.Instance, ilos.Instance) { + // if arguments ends here + if instance.Of(class.Null, arguments) { return instance.New(class.Null), nil } - // args must be a instance of list and ends with nil - if !instance.Of(class.List, args) || !UnsafeEndOfListIsNil(args) { + // arguments must be a instance of list and ends with nil + if !instance.Of(class.List, arguments) || !UnsafeEndOfListIsNil(arguments) { return nil, instance.New(class.ParseError, map[string]ilos.Instance{ - "STRING": args, + "STRING": arguments, "EXPECTED-CLASS": class.List, }) } - car := instance.UnsafeCar(args) // Checked there - cdr := instance.UnsafeCdr(args) // Checked there + car := instance.UnsafeCar(arguments) // Checked there + cdr := instance.UnsafeCdr(arguments) // Checked there a, err := Eval(local, global, car) if err != nil { return nil, err @@ -33,7 +33,7 @@ func evalArguments(local, global *env.Environment, args ilos.Instance) (ilos.Ins } -func evalLambda(local, global *env.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { +func evalLambda(local, global *environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { // obj, function call form, must be a instance of Cons, NOT Null, and ends with nil if !instance.Of(class.Cons, obj) || !UnsafeEndOfListIsNil(obj) { return nil, instance.New(class.ParseError, map[string]ilos.Instance{ @@ -52,21 +52,21 @@ func evalLambda(local, global *env.Environment, obj ilos.Instance) (ilos.Instanc return nil, err } - args, err := evalArguments(local, global, cdr) + arguments, err := evalArguments(local, global, cdr) if err != nil { return nil, err } - env := env.New() + env := environment.New() env.DynamicVariable = append(local.DynamicVariable, env.DynamicVariable...) env.CatchTag = append(local.CatchTag, env.CatchTag...) - ret, err := fun.(instance.Applicable).Apply(env, global, args) + ret, err := fun.(instance.Applicable).Apply(env, global, arguments) if err != nil { return nil, err } return ret, nil } -func evalFunction(local, global *env.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { +func evalFunction(local, global *environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { // obj, function call form, must be a instance of Cons, NOT Null, and ends with nil if !instance.Of(class.Cons, obj) || !UnsafeEndOfListIsNil(obj) { return nil, instance.New(class.ParseError, map[string]ilos.Instance{ @@ -104,7 +104,7 @@ func evalFunction(local, global *env.Environment, obj ilos.Instance) (ilos.Insta mac = m } if mac != nil { - env := env.New() + env := environment.New() env.BlockTag = append(local.BlockTag, env.BlockTag...) env.TagbodyTag = append(local.TagbodyTag, env.TagbodyTag...) env.CatchTag = append(local.CatchTag, env.CatchTag...) @@ -127,14 +127,14 @@ func evalFunction(local, global *env.Environment, obj ilos.Instance) (ilos.Insta fun = f } if fun != nil { - args, err := evalArguments(local, global, cdr) + arguments, err := evalArguments(local, global, cdr) if err != nil { return nil, err } - env := env.New() + env := environment.New() env.CatchTag = append(local.CatchTag, env.CatchTag...) env.DynamicVariable = append(local.DynamicVariable, env.DynamicVariable...) - ret, err := fun.(instance.Applicable).Apply(env, global, args) + ret, err := fun.(instance.Applicable).Apply(env, global, arguments) if err != nil { return nil, err } @@ -146,7 +146,7 @@ func evalFunction(local, global *env.Environment, obj ilos.Instance) (ilos.Insta }) } -func evalVariable(local, global *env.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { +func evalVariable(local, global *environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { if val, ok := local.Variable.Get(obj); ok { return val, nil } @@ -160,7 +160,7 @@ func evalVariable(local, global *env.Environment, obj ilos.Instance) (ilos.Insta } // Eval evaluates any classs -func Eval(local, global *env.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { +func Eval(local, global *environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { if instance.Of(class.Null, obj) { return instance.New(class.Null), nil } diff --git a/runtime/eval_test.go b/runtime/eval_test.go index e955b7f..8226293 100644 --- a/runtime/eval_test.go +++ b/runtime/eval_test.go @@ -4,56 +4,56 @@ import ( "reflect" "testing" - env "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/environment" "github.com/ta2gch/iris/runtime/ilos" "github.com/ta2gch/iris/runtime/ilos/class" "github.com/ta2gch/iris/runtime/ilos/instance" ) func TestEval(t *testing.T) { - local := env.New() - global := env.TopLevel - defun("INC", func(local, global *env.Environment, arg ilos.Instance) (ilos.Instance, ilos.Instance) { + local := environment.New() + global := environment.TopLevel + defun("INC", func(local, global *environment.Environment, arg ilos.Instance) (ilos.Instance, ilos.Instance) { return instance.New(class.Integer, int(arg.(instance.Integer))+1), nil }) defglobal("PI", instance.New(class.Float, 3.14)) - defmacro("MINC", func(local *env.Environment, global *env.Environment, arg ilos.Instance) (ilos.Instance, ilos.Instance) { + defmacro("MINC", func(local *environment.Environment, global *environment.Environment, arg ilos.Instance) (ilos.Instance, ilos.Instance) { ret, err := Eval(local, global, instance.New(class.Cons, instance.New(class.Symbol, "INC"), instance.New(class.Cons, arg, instance.New(class.Null)))) return ret, err }) - type args struct { + type arguments struct { obj ilos.Instance - local *env.Environment - global *env.Environment + local *environment.Environment + global *environment.Environment } tests := []struct { name string - args args + arguments arguments want ilos.Instance wantErr bool }{ { name: "local variable", - args: args{instance.New(class.Symbol, "PI"), local, global}, + arguments: arguments{instance.New(class.Symbol, "PI"), local, global}, want: instance.New(class.Float, 3.14), wantErr: false, }, { name: "local function", - args: args{readFromString("(inc (inc 1))"), local, global}, + arguments: arguments{readFromString("(inc (inc 1))"), local, global}, want: instance.New(class.Integer, 3), wantErr: false, }, { name: "local macro", - args: args{readFromString("(minc (minc 1))"), local, global}, + arguments: arguments{readFromString("(minc (minc 1))"), local, global}, want: instance.New(class.Integer, 3), wantErr: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := Eval(tt.args.local, tt.args.global, tt.args.obj) + got, err := Eval(tt.arguments.local, tt.arguments.global, tt.arguments.obj) if (err != nil) != tt.wantErr { t.Errorf("Eval() error = %v, wantErr %v", err, tt.wantErr) return diff --git a/runtime/function.go b/runtime/function.go index cc4270c..ec10cab 100644 --- a/runtime/function.go +++ b/runtime/function.go @@ -1,13 +1,13 @@ package runtime import ( - env "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/environment" "github.com/ta2gch/iris/runtime/ilos" "github.com/ta2gch/iris/runtime/ilos/class" "github.com/ta2gch/iris/runtime/ilos/instance" ) -func function(local, global *env.Environment, fun ilos.Instance) (ilos.Instance, ilos.Instance) { +func function(local, global *environment.Environment, fun ilos.Instance) (ilos.Instance, ilos.Instance) { // car must be a symbol if !instance.Of(class.Symbol, fun) { return nil, instance.New(class.DomainError, map[string]ilos.Instance{ diff --git a/runtime/ilos/instance/function.go b/runtime/ilos/instance/function.go index 59a7b04..b5b6e95 100644 --- a/runtime/ilos/instance/function.go +++ b/runtime/ilos/instance/function.go @@ -34,10 +34,10 @@ func (f Function) String() string { return fmt.Sprintf("#%v", f.Class()) } -func (f Function) Apply(local, global *environment.Environment, args ilos.Instance) (ilos.Instance, ilos.Instance) { +func (f Function) Apply(local, global *environment.Environment, arguments ilos.Instance) (ilos.Instance, ilos.Instance) { fv := reflect.ValueOf(f.function) ft := reflect.TypeOf(f.function) - cdr := args + cdr := arguments argv := []reflect.Value{reflect.ValueOf(local), reflect.ValueOf(global)} for Of(class.Cons, cdr) { cadr := UnsafeCar(cdr) @@ -48,7 +48,7 @@ func (f Function) Apply(local, global *environment.Environment, args ilos.Instan if ft.NumIn() != len(argv) && (!ft.IsVariadic() || ft.NumIn()-2 > len(argv)) { return nil, New(class.WrongNumberOfArguments, map[string]ilos.Instance{ "FORM": f.name, - "ARGUMENTS": args, + "ARGUMENTS": arguments, }) } rets := fv.Call(argv) diff --git a/runtime/lambda.go b/runtime/lambda.go index 711e60e..91397fc 100644 --- a/runtime/lambda.go +++ b/runtime/lambda.go @@ -1,13 +1,13 @@ package runtime import ( - env "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/environment" "github.com/ta2gch/iris/runtime/ilos" "github.com/ta2gch/iris/runtime/ilos/class" "github.com/ta2gch/iris/runtime/ilos/instance" ) -func lambda(local, global *env.Environment, lambdaList ilos.Instance, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func lambda(local, global *environment.Environment, lambdaList ilos.Instance, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { // lambdaFunction-list must be a instance of list and ends with nil if !instance.Of(class.List, lambdaList) || !UnsafeEndOfListIsNil(lambdaList) { // Checked at the head of test return nil, instance.New(class.DomainError, map[string]ilos.Instance{ @@ -28,7 +28,7 @@ func lambda(local, global *env.Environment, lambdaList ilos.Instance, forms ...i cdr = instance.UnsafeCdr(cdr) } name := instance.New(class.Symbol, "ANONYMOUS-FUNCTION") - return instance.New(class.Function, name, func(local, global *env.Environment, args ...ilos.Instance) (ilos.Instance, ilos.Instance) { + return instance.New(class.Function, name, func(local, global *environment.Environment, arguments ...ilos.Instance) (ilos.Instance, ilos.Instance) { local.BlockTag = append(lexical.BlockTag, local.BlockTag...) local.TagbodyTag = append(lexical.TagbodyTag, local.TagbodyTag...) local.CatchTag = append(lexical.CatchTag, local.CatchTag...) @@ -36,10 +36,10 @@ func lambda(local, global *env.Environment, lambdaList ilos.Instance, forms ...i local.Function = append(lexical.Function, local.Function...) local.Macro = append(lexical.Macro, local.Macro...) local.DynamicVariable = append(lexical.DynamicVariable, local.DynamicVariable...) - if (variadic && len(parameters)-2 > len(args)) || (!variadic && len(parameters) != len(args)) { + if (variadic && len(parameters)-2 > len(arguments)) || (!variadic && len(parameters) != len(arguments)) { v := instance.New(class.Null) - for i := len(args) - 1; i >= 0; i-- { - v = instance.New(class.Cons, args[i], v) + for i := len(arguments) - 1; i >= 0; i-- { + v = instance.New(class.Cons, arguments[i], v) } return nil, instance.New(class.WrongNumberOfArguments, map[string]ilos.Instance{ "FORM": name, @@ -51,13 +51,13 @@ func lambda(local, global *env.Environment, lambdaList ilos.Instance, forms ...i if key == instance.New(class.Symbol, ":REST") || key == instance.New(class.Symbol, "&REST") { key := parameters[idx+1] value := instance.New(class.Null) - for i := len(args) - 1; i >= idx; i-- { - value = instance.New(class.Cons, args[i], value) + for i := len(arguments) - 1; i >= idx; i-- { + value = instance.New(class.Cons, arguments[i], value) } local.Variable.Define(key, value) break } - value := args[idx] + value := arguments[idx] local.Variable.Define(key, value) } ret := instance.New(class.Null) diff --git a/runtime/lambda_test.go b/runtime/lambda_test.go index 8705af2..391e84f 100644 --- a/runtime/lambda_test.go +++ b/runtime/lambda_test.go @@ -4,60 +4,60 @@ import ( "reflect" "testing" - env "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/environment" "github.com/ta2gch/iris/runtime/ilos" "github.com/ta2gch/iris/runtime/ilos/class" "github.com/ta2gch/iris/runtime/ilos/instance" ) func TestLambda(t *testing.T) { - local, global := env.New(), env.TopLevel + local, global := environment.New(), environment.TopLevel defmacro("LAMBDA", lambda) - type args struct { - local *env.Environment - global *env.Environment + type arguments struct { + local *environment.Environment + global *environment.Environment obj ilos.Instance } tests := []struct { name string - args args + arguments arguments want ilos.Instance wantErr bool }{ { name: "case1", - args: args{local, global, readFromString("((lambda (x)) 1)")}, + arguments: arguments{local, global, readFromString("((lambda (x)) 1)")}, want: instance.New(class.Null), wantErr: false, }, { name: "case2", - args: args{local, global, readFromString("((lambda (:rest xs) xs) 1 2)")}, + arguments: arguments{local, global, readFromString("((lambda (:rest xs) xs) 1 2)")}, want: readFromString("(1 2)"), wantErr: false, }, { name: "case3", - args: args{local, global, readFromString("((lambda (:rest xs) xs))")}, + arguments: arguments{local, global, readFromString("((lambda (:rest xs) xs))")}, want: readFromString("nil"), wantErr: false, }, { name: "case4", - args: args{local, global, readFromString("((lambda (x) x) 1 2)")}, + arguments: arguments{local, global, readFromString("((lambda (x) x) 1 2)")}, want: nil, wantErr: true, }, { name: "case5", - args: args{local, global, readFromString("((lambda (x :rest xs) x))")}, + arguments: arguments{local, global, readFromString("((lambda (x :rest xs) x))")}, want: nil, wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := Eval(tt.args.local, tt.args.global, tt.args.obj) + got, err := Eval(tt.arguments.local, tt.arguments.global, tt.arguments.obj) if (err != nil) != tt.wantErr { t.Errorf("Eval() error = %v, wantErr %v", err, tt.wantErr) return diff --git a/runtime/quote.go b/runtime/quote.go index 6b97efc..966c4e2 100644 --- a/runtime/quote.go +++ b/runtime/quote.go @@ -1,10 +1,10 @@ package runtime import ( - env "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/environment" "github.com/ta2gch/iris/runtime/ilos" ) -func quote(local, global *env.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { +func quote(local, global *environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { return obj, nil } diff --git a/runtime/tagbody.go b/runtime/tagbody.go index 4585028..327c33f 100644 --- a/runtime/tagbody.go +++ b/runtime/tagbody.go @@ -1,13 +1,13 @@ package runtime import ( - env "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/environment" "github.com/ta2gch/iris/runtime/ilos" "github.com/ta2gch/iris/runtime/ilos/class" "github.com/ta2gch/iris/runtime/ilos/instance" ) -func tagbody(local, global *env.Environment, body ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func tagbody(local, global *environment.Environment, body ...ilos.Instance) (ilos.Instance, ilos.Instance) { for idx, cadr := range body { cddr := instance.New(class.GeneralVector, body[idx+1:]) if !instance.Of(class.Cons, cadr) { @@ -49,7 +49,7 @@ func tagbody(local, global *env.Environment, body ...ilos.Instance) (ilos.Instan return instance.New(class.Null), nil } -func tagbodyGo(local, global *env.Environment, tag ilos.Instance) (ilos.Instance, ilos.Instance) { +func tagbodyGo(local, global *environment.Environment, tag ilos.Instance) (ilos.Instance, ilos.Instance) { if _, ok := local.TagbodyTag.Get(tag); !ok { return nil, instance.New(class.SimpleError, map[string]ilos.Instance{ "FORMAT-STRING": instance.New(class.String, "%v is not defined as the tag"), diff --git a/runtime/tagbody_test.go b/runtime/tagbody_test.go index 685babb..068db0f 100644 --- a/runtime/tagbody_test.go +++ b/runtime/tagbody_test.go @@ -4,46 +4,46 @@ import ( "reflect" "testing" - env "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/environment" "github.com/ta2gch/iris/runtime/ilos" "github.com/ta2gch/iris/runtime/ilos/class" "github.com/ta2gch/iris/runtime/ilos/instance" ) func TestTagbody(t *testing.T) { - local, global := env.New(), env.TopLevel + local, global := environment.New(), environment.TopLevel defmacro("TAGBODY", tagbody) defmacro("GO", tagbodyGo) defmacro("CATCH", catch) defmacro("THROW", throw) defmacro("QUOTE", quote) - type args struct { - local *env.Environment - global *env.Environment + type arguments struct { + local *environment.Environment + global *environment.Environment obj ilos.Instance } tests := []struct { name string - args args + arguments arguments want ilos.Instance wantErr bool }{ { name: "tagbody & go", - args: args{local, global, readFromString("(catch 'foo (tagbody (go bar) (throw 'foo 1) bar))")}, + arguments: arguments{local, global, readFromString("(catch 'foo (tagbody (go bar) (throw 'foo 1) bar))")}, want: instance.New(class.Null), wantErr: false, }, { name: "nested tagbody & go", - args: args{local, global, readFromString("(catch 'foo (tagbody (tagbody (go bar) (throw 'foo 1) bar (go foobar)) foobar))")}, + arguments: arguments{local, global, readFromString("(catch 'foo (tagbody (tagbody (go bar) (throw 'foo 1) bar (go foobar)) foobar))")}, want: instance.New(class.Null), wantErr: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := Eval(tt.args.local, tt.args.global, tt.args.obj) + got, err := Eval(tt.arguments.local, tt.arguments.global, tt.arguments.obj) if (err != nil) != tt.wantErr { t.Errorf("Eval() error = %v, wantErr %v", err, tt.wantErr) return From 80ae720208f785b11f4c26ff9bdeb408b3669e7c Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Fri, 11 Aug 2017 13:32:48 +0900 Subject: [PATCH 122/228] Added Special forms --- runtime/block_test.go | 22 ++-- runtime/catch_test.go | 6 +- runtime/environment/environment.go | 2 + runtime/eval.go | 160 ++++++++++++++++------------- runtime/eval_test.go | 35 +++---- runtime/lambda.go | 1 + runtime/lambda_test.go | 50 ++++----- runtime/tagbody_test.go | 34 +++--- runtime/util.go | 6 ++ 9 files changed, 170 insertions(+), 146 deletions(-) diff --git a/runtime/block_test.go b/runtime/block_test.go index 3c62ba5..a192325 100644 --- a/runtime/block_test.go +++ b/runtime/block_test.go @@ -10,25 +10,25 @@ import ( func TestBlock(t *testing.T) { local, global := environment.New(), environment.TopLevel - defmacro("BLOCK", block) - defmacro("RETURN-FROM", return_from) - defmacro("QUOTE", quote) + defspecial("BLOCK", block) + defspecial("RETURN-FROM", return_from) + defspecial("QUOTE", quote) type arguments struct { local *environment.Environment global *environment.Environment obj ilos.Instance } tests := []struct { - name string - arguments arguments - want ilos.Instance - wantErr bool + name string + arguments arguments + want ilos.Instance + wantErr bool }{ { - name: "block & return-from", - arguments: arguments{local, global, readFromString("(block 'foo 1 (return-from 'foo 1))")}, - want: readFromString("1"), - wantErr: false, + name: "block & return-from", + arguments: arguments{local, global, readFromString("(block 'foo 1 (return-from 'foo 1))")}, + want: readFromString("1"), + wantErr: false, }, } for _, tt := range tests { diff --git a/runtime/catch_test.go b/runtime/catch_test.go index 4d3d6d9..cc4dfe1 100644 --- a/runtime/catch_test.go +++ b/runtime/catch_test.go @@ -10,9 +10,9 @@ import ( func TestCatch(t *testing.T) { local, global := environment.New(), environment.TopLevel - defmacro("CATCH", catch) - defmacro("THROW", throw) - defmacro("QUOTE", quote) + defspecial("CATCH", catch) + defspecial("THROW", throw) + defspecial("QUOTE", quote) type arguments struct { local *environment.Environment global *environment.Environment diff --git a/runtime/environment/environment.go b/runtime/environment/environment.go index 1e99e55..0f252f8 100644 --- a/runtime/environment/environment.go +++ b/runtime/environment/environment.go @@ -7,6 +7,7 @@ type Environment struct { CatchTag stack Macro stack Function stack + Special stack Variable stack DynamicVariable stack // deep biding } @@ -19,6 +20,7 @@ func New() *Environment { env.CatchTag = newStack() env.Macro = newStack() env.Function = newStack() + env.Special = newStack() env.Variable = newStack() env.DynamicVariable = newStack() return env diff --git a/runtime/eval.go b/runtime/eval.go index c2574bf..6c47560 100644 --- a/runtime/eval.go +++ b/runtime/eval.go @@ -33,69 +33,51 @@ func evalArguments(local, global *environment.Environment, arguments ilos.Instan } -func evalLambda(local, global *environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { - // obj, function call form, must be a instance of Cons, NOT Null, and ends with nil - if !instance.Of(class.Cons, obj) || !UnsafeEndOfListIsNil(obj) { - return nil, instance.New(class.ParseError, map[string]ilos.Instance{ - "STRING": obj, - "EXPECTED-CLASS": class.Cons, - }) - } - // get function symbol - car := instance.UnsafeCar(obj) // Checked at the top of this function - - // get function arguments - cdr := instance.UnsafeCdr(obj) // Checked at the top of this function - - fun, err := Eval(local, global, car) - if err != nil { - return nil, err - } - - arguments, err := evalArguments(local, global, cdr) - if err != nil { - return nil, err - } - env := environment.New() - env.DynamicVariable = append(local.DynamicVariable, env.DynamicVariable...) - env.CatchTag = append(local.CatchTag, env.CatchTag...) - ret, err := fun.(instance.Applicable).Apply(env, global, arguments) - if err != nil { - return nil, err - } - return ret, nil -} - -func evalFunction(local, global *environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { - // obj, function call form, must be a instance of Cons, NOT Null, and ends with nil - if !instance.Of(class.Cons, obj) || !UnsafeEndOfListIsNil(obj) { - return nil, instance.New(class.ParseError, map[string]ilos.Instance{ - "STRING": obj, - "EXPECTED-CLASS": class.Cons, - }) - } - // get function symbol - car := instance.UnsafeCar(obj) // Checked at the top of this function - - // get function arguments - cdr := instance.UnsafeCdr(obj) // Checked at the top of this function - +func evalLambda(local, global *environment.Environment, car, cdr ilos.Instance) (ilos.Instance, ilos.Instance, bool) { // eval if lambda form if instance.Of(class.Cons, car) { caar := instance.UnsafeCar(car) // Checked at the top of this sentence if caar == instance.New(class.Symbol, "LAMBDA") { - ret, err := evalLambda(local, global, obj) - return ret, err + fun, err := Eval(local, global, car) + if err != nil { + return nil, err, true + } + + arguments, err := evalArguments(local, global, cdr) + if err != nil { + return nil, err, true + } + env := environment.New() + env.DynamicVariable = append(local.DynamicVariable, env.DynamicVariable...) + env.CatchTag = append(local.CatchTag, env.CatchTag...) + ret, err := fun.(instance.Applicable).Apply(env, global, arguments) + if err != nil { + return nil, err, true + } + return ret, nil, true } } - // if function is not a lambda special form, first element must be a symbol - if !instance.Of(class.Symbol, car) { - return nil, instance.New(class.DomainError, map[string]ilos.Instance{ - "OBJECT": car, - "EXPECTED-CLASS": class.Symbol, - }) + return nil, nil, false +} + +func evalSpecial(local, global *environment.Environment, car, cdr ilos.Instance) (ilos.Instance, ilos.Instance, bool) { + // get special instance has value of Function interface + var spl ilos.Instance + if s, ok := global.Special.Get(car); ok { + spl = s + } + if spl != nil { + ret, err := spl.(instance.Applicable).Apply(local, global, cdr) + if err != nil { + return nil, err, true + } + return ret, nil, true } - // get macro instance has value of Function interface + return nil, nil, false +} + +func evalMacro(local, global *environment.Environment, car, cdr ilos.Instance) (ilos.Instance, ilos.Instance, bool) { + // get special instance has value of Function interface var mac ilos.Instance if m, ok := local.Macro.Get(car); ok { mac = m @@ -105,20 +87,23 @@ func evalFunction(local, global *environment.Environment, obj ilos.Instance) (il } if mac != nil { env := environment.New() - env.BlockTag = append(local.BlockTag, env.BlockTag...) - env.TagbodyTag = append(local.TagbodyTag, env.TagbodyTag...) - env.CatchTag = append(local.CatchTag, env.CatchTag...) - env.Variable = append(local.Variable, env.Variable...) - env.Function = append(local.Function, env.Function...) - env.Macro = append(local.Macro, env.Macro...) env.DynamicVariable = append(local.DynamicVariable, env.DynamicVariable...) + env.CatchTag = append(local.DynamicVariable, env.CatchTag...) ret, err := mac.(instance.Applicable).Apply(env, global, cdr) if err != nil { - return nil, err + return nil, err, true } - return ret, nil + ret, err = Eval(local, global, ret) + if err != nil { + return nil, err, true + } + return ret, nil, true } - // get function instance has value of Function interface + return nil, nil, false +} + +func evalFunction(local, global *environment.Environment, car, cdr ilos.Instance) (ilos.Instance, ilos.Instance, bool) { + // get special instance has value of Function interface var fun ilos.Instance if f, ok := local.Function.Get(car); ok { fun = f @@ -127,19 +112,50 @@ func evalFunction(local, global *environment.Environment, obj ilos.Instance) (il fun = f } if fun != nil { + env := environment.New() + env.DynamicVariable = append(local.DynamicVariable, env.DynamicVariable...) + env.CatchTag = append(local.DynamicVariable, env.CatchTag...) arguments, err := evalArguments(local, global, cdr) if err != nil { - return nil, err + return nil, err, true } - env := environment.New() - env.CatchTag = append(local.CatchTag, env.CatchTag...) - env.DynamicVariable = append(local.DynamicVariable, env.DynamicVariable...) ret, err := fun.(instance.Applicable).Apply(env, global, arguments) if err != nil { - return nil, err + return nil, err, true } - return ret, nil + return ret, nil, true + } + return nil, nil, false +} + +func evalCons(local, global *environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { + // obj, function call form, must be a instance of Cons, NOT Null, and ends with nil + if !instance.Of(class.Cons, obj) || !UnsafeEndOfListIsNil(obj) { + return nil, instance.New(class.ParseError, map[string]ilos.Instance{ + "STRING": obj, + "EXPECTED-CLASS": class.Cons, + }) } + car := instance.UnsafeCar(obj) // Checked at the top of this function + cdr := instance.UnsafeCdr(obj) // Checked at the top of this function + + // eval if lambda form + if a, b, c := evalLambda(local, global, car, cdr); c { + return a, b + } + // get special instance has value of Function interface + if a, b, c := evalSpecial(local, global, car, cdr); c { + return a, b + } + // get macro instance has value of Function interface + if a, b, c := evalMacro(local, global, car, cdr); c { + return a, b + } + // get function instance has value of Function interface + if a, b, c := evalFunction(local, global, car, cdr); c { + return a, b + } + return nil, instance.New(class.UndefinedFunction, map[string]ilos.Instance{ "NAME": car, "NAMESPACE": instance.New(class.Symbol, "FUNCTION"), @@ -172,7 +188,7 @@ func Eval(local, global *environment.Environment, obj ilos.Instance) (ilos.Insta return ret, nil } if instance.Of(class.Cons, obj) { - ret, err := evalFunction(local, global, obj) + ret, err := evalCons(local, global, obj) if err != nil { return nil, err } diff --git a/runtime/eval_test.go b/runtime/eval_test.go index 8226293..7e05b32 100644 --- a/runtime/eval_test.go +++ b/runtime/eval_test.go @@ -18,8 +18,7 @@ func TestEval(t *testing.T) { }) defglobal("PI", instance.New(class.Float, 3.14)) defmacro("MINC", func(local *environment.Environment, global *environment.Environment, arg ilos.Instance) (ilos.Instance, ilos.Instance) { - ret, err := Eval(local, global, instance.New(class.Cons, instance.New(class.Symbol, "INC"), instance.New(class.Cons, arg, instance.New(class.Null)))) - return ret, err + return instance.New(class.Cons, instance.New(class.Symbol, "INC"), instance.New(class.Cons, arg, instance.New(class.Null))), nil }) type arguments struct { obj ilos.Instance @@ -27,28 +26,28 @@ func TestEval(t *testing.T) { global *environment.Environment } tests := []struct { - name string - arguments arguments - want ilos.Instance - wantErr bool + name string + arguments arguments + want ilos.Instance + wantErr bool }{ { - name: "local variable", - arguments: arguments{instance.New(class.Symbol, "PI"), local, global}, - want: instance.New(class.Float, 3.14), - wantErr: false, + name: "local variable", + arguments: arguments{instance.New(class.Symbol, "PI"), local, global}, + want: instance.New(class.Float, 3.14), + wantErr: false, }, { - name: "local function", - arguments: arguments{readFromString("(inc (inc 1))"), local, global}, - want: instance.New(class.Integer, 3), - wantErr: false, + name: "local function", + arguments: arguments{readFromString("(inc (inc 1))"), local, global}, + want: instance.New(class.Integer, 3), + wantErr: false, }, { - name: "local macro", - arguments: arguments{readFromString("(minc (minc 1))"), local, global}, - want: instance.New(class.Integer, 3), - wantErr: false, + name: "local macro", + arguments: arguments{readFromString("(minc (minc 1))"), local, global}, + want: instance.New(class.Integer, 3), + wantErr: false, }, } for _, tt := range tests { diff --git a/runtime/lambda.go b/runtime/lambda.go index 91397fc..ef3766d 100644 --- a/runtime/lambda.go +++ b/runtime/lambda.go @@ -34,6 +34,7 @@ func lambda(local, global *environment.Environment, lambdaList ilos.Instance, fo local.CatchTag = append(lexical.CatchTag, local.CatchTag...) local.Variable = append(lexical.Variable, local.Variable...) local.Function = append(lexical.Function, local.Function...) + local.Special = append(lexical.Special, local.Special...) local.Macro = append(lexical.Macro, local.Macro...) local.DynamicVariable = append(lexical.DynamicVariable, local.DynamicVariable...) if (variadic && len(parameters)-2 > len(arguments)) || (!variadic && len(parameters) != len(arguments)) { diff --git a/runtime/lambda_test.go b/runtime/lambda_test.go index 391e84f..6a52b92 100644 --- a/runtime/lambda_test.go +++ b/runtime/lambda_test.go @@ -12,47 +12,47 @@ import ( func TestLambda(t *testing.T) { local, global := environment.New(), environment.TopLevel - defmacro("LAMBDA", lambda) + defspecial("LAMBDA", lambda) type arguments struct { local *environment.Environment global *environment.Environment obj ilos.Instance } tests := []struct { - name string - arguments arguments - want ilos.Instance - wantErr bool + name string + arguments arguments + want ilos.Instance + wantErr bool }{ { - name: "case1", - arguments: arguments{local, global, readFromString("((lambda (x)) 1)")}, - want: instance.New(class.Null), - wantErr: false, + name: "case1", + arguments: arguments{local, global, readFromString("((lambda (x)) 1)")}, + want: instance.New(class.Null), + wantErr: false, }, { - name: "case2", - arguments: arguments{local, global, readFromString("((lambda (:rest xs) xs) 1 2)")}, - want: readFromString("(1 2)"), - wantErr: false, + name: "case2", + arguments: arguments{local, global, readFromString("((lambda (:rest xs) xs) 1 2)")}, + want: readFromString("(1 2)"), + wantErr: false, }, { - name: "case3", - arguments: arguments{local, global, readFromString("((lambda (:rest xs) xs))")}, - want: readFromString("nil"), - wantErr: false, + name: "case3", + arguments: arguments{local, global, readFromString("((lambda (:rest xs) xs))")}, + want: readFromString("nil"), + wantErr: false, }, { - name: "case4", - arguments: arguments{local, global, readFromString("((lambda (x) x) 1 2)")}, - want: nil, - wantErr: true, + name: "case4", + arguments: arguments{local, global, readFromString("((lambda (x) x) 1 2)")}, + want: nil, + wantErr: true, }, { - name: "case5", - arguments: arguments{local, global, readFromString("((lambda (x :rest xs) x))")}, - want: nil, - wantErr: true, + name: "case5", + arguments: arguments{local, global, readFromString("((lambda (x :rest xs) x))")}, + want: nil, + wantErr: true, }, } for _, tt := range tests { diff --git a/runtime/tagbody_test.go b/runtime/tagbody_test.go index 068db0f..f1ee5ca 100644 --- a/runtime/tagbody_test.go +++ b/runtime/tagbody_test.go @@ -12,33 +12,33 @@ import ( func TestTagbody(t *testing.T) { local, global := environment.New(), environment.TopLevel - defmacro("TAGBODY", tagbody) - defmacro("GO", tagbodyGo) - defmacro("CATCH", catch) - defmacro("THROW", throw) - defmacro("QUOTE", quote) + defspecial("TAGBODY", tagbody) + defspecial("GO", tagbodyGo) + defspecial("CATCH", catch) + defspecial("THROW", throw) + defspecial("QUOTE", quote) type arguments struct { local *environment.Environment global *environment.Environment obj ilos.Instance } tests := []struct { - name string - arguments arguments - want ilos.Instance - wantErr bool + name string + arguments arguments + want ilos.Instance + wantErr bool }{ { - name: "tagbody & go", - arguments: arguments{local, global, readFromString("(catch 'foo (tagbody (go bar) (throw 'foo 1) bar))")}, - want: instance.New(class.Null), - wantErr: false, + name: "tagbody & go", + arguments: arguments{local, global, readFromString("(catch 'foo (tagbody (go bar) (throw 'foo 1) bar))")}, + want: instance.New(class.Null), + wantErr: false, }, { - name: "nested tagbody & go", - arguments: arguments{local, global, readFromString("(catch 'foo (tagbody (tagbody (go bar) (throw 'foo 1) bar (go foobar)) foobar))")}, - want: instance.New(class.Null), - wantErr: false, + name: "nested tagbody & go", + arguments: arguments{local, global, readFromString("(catch 'foo (tagbody (tagbody (go bar) (throw 'foo 1) bar (go foobar)) foobar))")}, + want: instance.New(class.Null), + wantErr: false, }, } for _, tt := range tests { diff --git a/runtime/util.go b/runtime/util.go index 6164326..e716f9c 100644 --- a/runtime/util.go +++ b/runtime/util.go @@ -44,10 +44,16 @@ func readFromString(s string) ilos.Instance { return e } +func defspecial(name string, macro interface{}) { + symbol := instance.New(class.Symbol, name) + environment.TopLevel.Special.Define(symbol, instance.New(class.Function, symbol, macro)) +} + func defmacro(name string, macro interface{}) { symbol := instance.New(class.Symbol, name) environment.TopLevel.Macro.Define(symbol, instance.New(class.Function, symbol, macro)) } + func defun(name string, function interface{}) { symbol := instance.New(class.Symbol, name) environment.TopLevel.Function.Define(symbol, instance.New(class.Function, symbol, function)) From 1f6d16bb34aaa80c834d93944dff78413244f0a4 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Fri, 11 Aug 2017 14:14:17 +0900 Subject: [PATCH 123/228] Added License term --- reader/parser/parser.go | 9 +- reader/parser/parser_test.go | 172 ++++++++++++++------------- reader/tokenizer/tokenizer.go | 6 +- reader/tokenizer/tokenizer_test.go | 4 + runtime/block.go | 12 +- runtime/block_test.go | 4 + runtime/catch.go | 8 +- runtime/catch_test.go | 4 + runtime/environment/environment.go | 4 + runtime/environment/stack.go | 4 + runtime/eval.go | 10 +- runtime/eval_test.go | 4 + runtime/function.go | 4 + runtime/ilos/class/builtinclass.go | 4 + runtime/ilos/class/class.go | 4 + runtime/ilos/class/primitiveclass.go | 4 + runtime/ilos/ilos.go | 4 + runtime/ilos/instance/basic-array.go | 4 + runtime/ilos/instance/character.go | 4 + runtime/ilos/instance/function.go | 4 + runtime/ilos/instance/instance.go | 4 + runtime/ilos/instance/list.go | 4 + runtime/ilos/instance/number.go | 4 + runtime/ilos/instance/symbol.go | 4 + runtime/lambda.go | 4 + runtime/lambda_test.go | 4 + runtime/quote.go | 4 + runtime/tagbody.go | 6 +- runtime/tagbody_test.go | 4 + runtime/util.go | 8 +- 30 files changed, 219 insertions(+), 100 deletions(-) diff --git a/reader/parser/parser.go b/reader/parser/parser.go index a7fa4ad..767f76c 100644 --- a/reader/parser/parser.go +++ b/reader/parser/parser.go @@ -1,3 +1,7 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + package parser import ( @@ -6,11 +10,10 @@ import ( "strconv" "strings" - "github.com/ta2gch/iris/runtime/ilos" - "github.com/ta2gch/iris/runtime/ilos/instance" - "github.com/ta2gch/iris/reader/tokenizer" + "github.com/ta2gch/iris/runtime/ilos" "github.com/ta2gch/iris/runtime/ilos/class" + "github.com/ta2gch/iris/runtime/ilos/instance" ) var eop = instance.New(class.Symbol, "End Of Parentheses") diff --git a/reader/parser/parser_test.go b/reader/parser/parser_test.go index 06b0fd5..df9bcce 100644 --- a/reader/parser/parser_test.go +++ b/reader/parser/parser_test.go @@ -1,3 +1,7 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + package parser import ( @@ -14,139 +18,139 @@ func Test_parseAtom(t *testing.T) { tok string } tests := []struct { - name string - arguments arguments - want ilos.Instance - wantErr bool + name string + arguments arguments + want ilos.Instance + wantErr bool }{ // // Float // { - name: "default", - arguments: arguments{"3.14"}, - want: instance.New(class.Float, 3.14), - wantErr: false, + name: "default", + arguments: arguments{"3.14"}, + want: instance.New(class.Float, 3.14), + wantErr: false, }, { - name: "signed", - arguments: arguments{"-5.0"}, - want: instance.New(class.Float, -5.0), - wantErr: false, + name: "signed", + arguments: arguments{"-5.0"}, + want: instance.New(class.Float, -5.0), + wantErr: false, }, { - name: "exponential", - arguments: arguments{"-5.0E3"}, - want: instance.New(class.Float, -5.0*1000), - wantErr: false, + name: "exponential", + arguments: arguments{"-5.0E3"}, + want: instance.New(class.Float, -5.0*1000), + wantErr: false, }, { - name: "signed exponential", - arguments: arguments{"5.0E-3"}, - want: instance.New(class.Float, 5.0*1.0/1000.0), - wantErr: false, + name: "signed exponential", + arguments: arguments{"5.0E-3"}, + want: instance.New(class.Float, 5.0*1.0/1000.0), + wantErr: false, }, { - name: "without point", - arguments: arguments{"5E-3"}, - want: instance.New(class.Float, 5.0*1.0/1000.0), - wantErr: false, + name: "without point", + arguments: arguments{"5E-3"}, + want: instance.New(class.Float, 5.0*1.0/1000.0), + wantErr: false, }, { - name: "invalid case", - arguments: arguments{"3E-3.0"}, - want: nil, - wantErr: true, + name: "invalid case", + arguments: arguments{"3E-3.0"}, + want: nil, + wantErr: true, }, { - name: "without point", - arguments: arguments{"5E-"}, - want: nil, - wantErr: true, + name: "without point", + arguments: arguments{"5E-"}, + want: nil, + wantErr: true, }, // // Integer // { - name: "default", - arguments: arguments{"5"}, - want: instance.New(class.Integer, 5), - wantErr: false, + name: "default", + arguments: arguments{"5"}, + want: instance.New(class.Integer, 5), + wantErr: false, }, { - name: "signed", - arguments: arguments{"-5"}, - want: instance.New(class.Integer, -5), - wantErr: false, + name: "signed", + arguments: arguments{"-5"}, + want: instance.New(class.Integer, -5), + wantErr: false, }, { - name: "binary", - arguments: arguments{"#B00101"}, - want: instance.New(class.Integer, 5), - wantErr: false, + name: "binary", + arguments: arguments{"#B00101"}, + want: instance.New(class.Integer, 5), + wantErr: false, }, { - name: "signed binary", - arguments: arguments{"#b+00101"}, - want: instance.New(class.Integer, 5), - wantErr: false, + name: "signed binary", + arguments: arguments{"#b+00101"}, + want: instance.New(class.Integer, 5), + wantErr: false, }, { - name: "octal", - arguments: arguments{"#o00101"}, - want: instance.New(class.Integer, 65), - wantErr: false, + name: "octal", + arguments: arguments{"#o00101"}, + want: instance.New(class.Integer, 65), + wantErr: false, }, { - name: "signed octal", - arguments: arguments{"#O-00101"}, - want: instance.New(class.Integer, -65), - wantErr: false, + name: "signed octal", + arguments: arguments{"#O-00101"}, + want: instance.New(class.Integer, -65), + wantErr: false, }, { - name: "hexadecimal", - arguments: arguments{"#X00101"}, - want: instance.New(class.Integer, 257), - wantErr: false, + name: "hexadecimal", + arguments: arguments{"#X00101"}, + want: instance.New(class.Integer, 257), + wantErr: false, }, { - name: "signed hexadecimal", - arguments: arguments{"#x-00101"}, - want: instance.New(class.Integer, -257), - wantErr: false, + name: "signed hexadecimal", + arguments: arguments{"#x-00101"}, + want: instance.New(class.Integer, -257), + wantErr: false, }, { - name: "invalid binary", - arguments: arguments{"-#x00101"}, - want: nil, - wantErr: true, + name: "invalid binary", + arguments: arguments{"-#x00101"}, + want: nil, + wantErr: true, }, // // Character // { - name: "default", - arguments: arguments{"#\\a"}, - want: instance.New(class.Character, 'a'), - wantErr: false, + name: "default", + arguments: arguments{"#\\a"}, + want: instance.New(class.Character, 'a'), + wantErr: false, }, { - name: "newline", - arguments: arguments{"#\\newline"}, - want: instance.New(class.Character, '\n'), - wantErr: false, + name: "newline", + arguments: arguments{"#\\newline"}, + want: instance.New(class.Character, '\n'), + wantErr: false, }, { - name: "space", - arguments: arguments{"#\\space"}, - want: instance.New(class.Character, ' '), - wantErr: false, + name: "space", + arguments: arguments{"#\\space"}, + want: instance.New(class.Character, ' '), + wantErr: false, }, { - name: "invalid character name", - arguments: arguments{"#\\foo"}, - want: nil, - wantErr: true, + name: "invalid character name", + arguments: arguments{"#\\foo"}, + want: nil, + wantErr: true, }, } for _, tt := range tests { diff --git a/reader/tokenizer/tokenizer.go b/reader/tokenizer/tokenizer.go index 6fbe295..4b1dd04 100644 --- a/reader/tokenizer/tokenizer.go +++ b/reader/tokenizer/tokenizer.go @@ -1,3 +1,7 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + package tokenizer import ( @@ -45,7 +49,7 @@ func (t *Tokenizer) Next() (string, ilos.Instance) { if t.sc.Scan() { return t.sc.Text(), nil } - return "", instance.New(class.ParseError,instance.New(class.String,t.sc.Text()), class.Object) + return "", instance.New(class.ParseError, instance.New(class.String, t.sc.Text()), class.Object) } func splitter(data []byte, atEOF bool) (advance int, token []byte, err error) { diff --git a/reader/tokenizer/tokenizer_test.go b/reader/tokenizer/tokenizer_test.go index 687fdda..7aba9c3 100644 --- a/reader/tokenizer/tokenizer_test.go +++ b/reader/tokenizer/tokenizer_test.go @@ -1,3 +1,7 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + package tokenizer import ( diff --git a/runtime/block.go b/runtime/block.go index 4f5d6d1..3df359d 100644 --- a/runtime/block.go +++ b/runtime/block.go @@ -1,3 +1,7 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + package runtime import ( @@ -14,10 +18,10 @@ import ( // is the body form only a return-from textually contained in some form can exit the block. // The extend of name is dynamic. (islisp-v23.pdf, 43-44) // NOTE: -// According to this, the scope of name is dynamic. I guess it should be a static. +// According to// This, the scope of name is dynamic. I guess it should be a static. func block(local, global *environment.Environment, tag ilos.Instance, body ...ilos.Instance) (ilos.Instance, ilos.Instance) { var err ilos.Instance - tag, err = Eval(local, global, tag) // Checked at the top of this function + tag, err = Eval(local, global, tag) // Checked at the top of// This function if err != nil { return nil, err } @@ -33,9 +37,9 @@ func block(local, global *environment.Environment, tag ilos.Instance, body ...il sucess, fail = Eval(local, global, cadr) if fail != nil { if instance.Of(class.BlockTag, fail) { - tag1, _ := fail.GetSlotValue(instance.New(class.Symbol, "TAG"), class.Escape) // Checked at the head of this condition + tag1, _ := fail.GetSlotValue(instance.New(class.Symbol, "TAG"), class.Escape) // Checked at the head of// This condition if tag == tag1 { - obj, _ := fail.GetSlotValue(instance.New(class.Symbol, "OBJECT"), class.BlockTag) // Checked at the head of this condition + obj, _ := fail.GetSlotValue(instance.New(class.Symbol, "OBJECT"), class.BlockTag) // Checked at the head of// This condition return obj, nil } } diff --git a/runtime/block_test.go b/runtime/block_test.go index a192325..50b7b4c 100644 --- a/runtime/block_test.go +++ b/runtime/block_test.go @@ -1,3 +1,7 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + package runtime import ( diff --git a/runtime/catch.go b/runtime/catch.go index 5774254..8311d99 100644 --- a/runtime/catch.go +++ b/runtime/catch.go @@ -1,3 +1,7 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + package runtime import ( @@ -22,9 +26,9 @@ func catch(local, global *environment.Environment, tag ilos.Instance, body ...il sucess, fail = Eval(local, global, cadr) if fail != nil { if instance.Of(class.CatchTag, fail) { - tag1, _ := fail.GetSlotValue(instance.New(class.Symbol, "TAG"), class.Escape) // Checked at the head of this condition + tag1, _ := fail.GetSlotValue(instance.New(class.Symbol, "TAG"), class.Escape) // Checked at the head of// This condition if tag == tag1 { - obj, _ := fail.GetSlotValue(instance.New(class.Symbol, "OBJECT"), class.CatchTag) // Checked at the head of this condition + obj, _ := fail.GetSlotValue(instance.New(class.Symbol, "OBJECT"), class.CatchTag) // Checked at the head of// This condition return obj, nil } } diff --git a/runtime/catch_test.go b/runtime/catch_test.go index cc4dfe1..aec7bce 100644 --- a/runtime/catch_test.go +++ b/runtime/catch_test.go @@ -1,3 +1,7 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + package runtime import ( diff --git a/runtime/environment/environment.go b/runtime/environment/environment.go index 0f252f8..14f87be 100644 --- a/runtime/environment/environment.go +++ b/runtime/environment/environment.go @@ -1,3 +1,7 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + package environment // Environment struct is the struct for keeping functions and variables diff --git a/runtime/environment/stack.go b/runtime/environment/stack.go index f6b6764..e695478 100644 --- a/runtime/environment/stack.go +++ b/runtime/environment/stack.go @@ -1,3 +1,7 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + package environment import ( diff --git a/runtime/eval.go b/runtime/eval.go index 6c47560..353b05a 100644 --- a/runtime/eval.go +++ b/runtime/eval.go @@ -1,3 +1,7 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + package runtime import ( @@ -36,7 +40,7 @@ func evalArguments(local, global *environment.Environment, arguments ilos.Instan func evalLambda(local, global *environment.Environment, car, cdr ilos.Instance) (ilos.Instance, ilos.Instance, bool) { // eval if lambda form if instance.Of(class.Cons, car) { - caar := instance.UnsafeCar(car) // Checked at the top of this sentence + caar := instance.UnsafeCar(car) // Checked at the top of// This sentence if caar == instance.New(class.Symbol, "LAMBDA") { fun, err := Eval(local, global, car) if err != nil { @@ -136,8 +140,8 @@ func evalCons(local, global *environment.Environment, obj ilos.Instance) (ilos.I "EXPECTED-CLASS": class.Cons, }) } - car := instance.UnsafeCar(obj) // Checked at the top of this function - cdr := instance.UnsafeCdr(obj) // Checked at the top of this function + car := instance.UnsafeCar(obj) // Checked at the top of// This function + cdr := instance.UnsafeCdr(obj) // Checked at the top of// This function // eval if lambda form if a, b, c := evalLambda(local, global, car, cdr); c { diff --git a/runtime/eval_test.go b/runtime/eval_test.go index 7e05b32..d2b7026 100644 --- a/runtime/eval_test.go +++ b/runtime/eval_test.go @@ -1,3 +1,7 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + package runtime import ( diff --git a/runtime/function.go b/runtime/function.go index ec10cab..4a5f65e 100644 --- a/runtime/function.go +++ b/runtime/function.go @@ -1,3 +1,7 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + package runtime import ( diff --git a/runtime/ilos/class/builtinclass.go b/runtime/ilos/class/builtinclass.go index 10ba3c4..573cb48 100644 --- a/runtime/ilos/class/builtinclass.go +++ b/runtime/ilos/class/builtinclass.go @@ -1,3 +1,7 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + package class import "github.com/ta2gch/iris/runtime/ilos" diff --git a/runtime/ilos/class/class.go b/runtime/ilos/class/class.go index 069130e..7fd4e5d 100644 --- a/runtime/ilos/class/class.go +++ b/runtime/ilos/class/class.go @@ -1,3 +1,7 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + package class import "github.com/ta2gch/iris/runtime/ilos" diff --git a/runtime/ilos/class/primitiveclass.go b/runtime/ilos/class/primitiveclass.go index 7b435c5..7efe6a6 100644 --- a/runtime/ilos/class/primitiveclass.go +++ b/runtime/ilos/class/primitiveclass.go @@ -1,3 +1,7 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + package class import "github.com/ta2gch/iris/runtime/ilos" diff --git a/runtime/ilos/ilos.go b/runtime/ilos/ilos.go index 0e9c333..843145c 100644 --- a/runtime/ilos/ilos.go +++ b/runtime/ilos/ilos.go @@ -1,3 +1,7 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + package ilos type Class interface { diff --git a/runtime/ilos/instance/basic-array.go b/runtime/ilos/instance/basic-array.go index 87de6a4..81267bd 100644 --- a/runtime/ilos/instance/basic-array.go +++ b/runtime/ilos/instance/basic-array.go @@ -1,3 +1,7 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + package instance import ( diff --git a/runtime/ilos/instance/character.go b/runtime/ilos/instance/character.go index ffe5a10..5fb6251 100644 --- a/runtime/ilos/instance/character.go +++ b/runtime/ilos/instance/character.go @@ -1,3 +1,7 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + package instance import ( diff --git a/runtime/ilos/instance/function.go b/runtime/ilos/instance/function.go index b5b6e95..98f3245 100644 --- a/runtime/ilos/instance/function.go +++ b/runtime/ilos/instance/function.go @@ -1,3 +1,7 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + package instance import ( diff --git a/runtime/ilos/instance/instance.go b/runtime/ilos/instance/instance.go index d557cf5..d3b9ef8 100644 --- a/runtime/ilos/instance/instance.go +++ b/runtime/ilos/instance/instance.go @@ -1,3 +1,7 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + package instance import ( diff --git a/runtime/ilos/instance/list.go b/runtime/ilos/instance/list.go index 32f0a95..40ece6b 100644 --- a/runtime/ilos/instance/list.go +++ b/runtime/ilos/instance/list.go @@ -1,3 +1,7 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + package instance import ( diff --git a/runtime/ilos/instance/number.go b/runtime/ilos/instance/number.go index e187445..122002a 100644 --- a/runtime/ilos/instance/number.go +++ b/runtime/ilos/instance/number.go @@ -1,3 +1,7 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + package instance import ( diff --git a/runtime/ilos/instance/symbol.go b/runtime/ilos/instance/symbol.go index 73d8b60..2bc4983 100644 --- a/runtime/ilos/instance/symbol.go +++ b/runtime/ilos/instance/symbol.go @@ -1,3 +1,7 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + package instance import ( diff --git a/runtime/lambda.go b/runtime/lambda.go index ef3766d..6fc1b2c 100644 --- a/runtime/lambda.go +++ b/runtime/lambda.go @@ -1,3 +1,7 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + package runtime import ( diff --git a/runtime/lambda_test.go b/runtime/lambda_test.go index 6a52b92..38a2406 100644 --- a/runtime/lambda_test.go +++ b/runtime/lambda_test.go @@ -1,3 +1,7 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + package runtime import ( diff --git a/runtime/quote.go b/runtime/quote.go index 966c4e2..2c38994 100644 --- a/runtime/quote.go +++ b/runtime/quote.go @@ -1,3 +1,7 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + package runtime import ( diff --git a/runtime/tagbody.go b/runtime/tagbody.go index 327c33f..533dee0 100644 --- a/runtime/tagbody.go +++ b/runtime/tagbody.go @@ -1,3 +1,7 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + package runtime import ( @@ -20,7 +24,7 @@ func tagbody(local, global *environment.Environment, body ...ilos.Instance) (ilo if fail != nil { TAG: if instance.Of(class.TagbodyTag, fail) { - tag, _ := fail.GetSlotValue(instance.New(class.Symbol, "TAG"), class.Escape) // Checked at the top of this loop + tag, _ := fail.GetSlotValue(instance.New(class.Symbol, "TAG"), class.Escape) // Checked at the top of// This loop found := false for _, tag1 := range body { if tag == tag1 { diff --git a/runtime/tagbody_test.go b/runtime/tagbody_test.go index f1ee5ca..710f836 100644 --- a/runtime/tagbody_test.go +++ b/runtime/tagbody_test.go @@ -1,3 +1,7 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + package runtime import ( diff --git a/runtime/util.go b/runtime/util.go index e716f9c..bcfd4d0 100644 --- a/runtime/util.go +++ b/runtime/util.go @@ -1,3 +1,7 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + package runtime import ( @@ -18,7 +22,7 @@ import ( func UnsafeEndOfListIsNil(i ilos.Instance) bool { cdr := i for instance.Of(class.Cons, cdr) { - cdr = instance.UnsafeCdr(cdr) // Checked at the top of this loop + cdr = instance.UnsafeCdr(cdr) // Checked at the top of// This loop } if instance.Of(class.Null, cdr) { return true @@ -33,7 +37,7 @@ func UnsafeListLength(i ilos.Instance) int { cdr := i cnt := 0 for instance.Of(class.Cons, cdr) { - cdr = instance.UnsafeCdr(cdr) // Checked at the top of this loop + cdr = instance.UnsafeCdr(cdr) // Checked at the top of// This loop cnt++ } return cnt From daaa9bcc615df09377d6742c69ba5837cdcc0cd7 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Fri, 11 Aug 2017 14:37:25 +0900 Subject: [PATCH 124/228] Added new stack of environment in special forms --- runtime/eval.go | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/runtime/eval.go b/runtime/eval.go index 353b05a..911fbff 100644 --- a/runtime/eval.go +++ b/runtime/eval.go @@ -71,7 +71,16 @@ func evalSpecial(local, global *environment.Environment, car, cdr ilos.Instance) spl = s } if spl != nil { - ret, err := spl.(instance.Applicable).Apply(local, global, cdr) + env := environment.New() + env.BlockTag = append(local.BlockTag, env.BlockTag...) + env.TagbodyTag = append(local.TagbodyTag, env.TagbodyTag...) + env.CatchTag = append(local.CatchTag, env.CatchTag...) + env.Variable = append(local.Variable, env.Variable...) + env.Function = append(local.Function, env.Function...) + env.Special = append(local.Special, env.Special...) + env.Macro = append(local.Macro, env.Macro...) + env.DynamicVariable = append(local.DynamicVariable, env.DynamicVariable...) + ret, err := spl.(instance.Applicable).Apply(env, global, cdr) if err != nil { return nil, err, true } From bd9ee02af51e15fc26f95d52f9cf41c13db863ec Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Fri, 11 Aug 2017 14:50:00 +0900 Subject: [PATCH 125/228] Added test for error handling --- runtime/block.go | 3 ++- runtime/block_test.go | 14 +++++++++++++- runtime/catch.go | 3 ++- runtime/catch_test.go | 14 +++++++++++++- runtime/ilos/instance/function.go | 2 +- 5 files changed, 31 insertions(+), 5 deletions(-) diff --git a/runtime/block.go b/runtime/block.go index 3df359d..c288ef7 100644 --- a/runtime/block.go +++ b/runtime/block.go @@ -32,7 +32,8 @@ func block(local, global *environment.Environment, tag ilos.Instance, body ...il }) } local.BlockTag.Define(tag, nil) - var sucess, fail ilos.Instance + var fail ilos.Instance + sucess := instance.New(class.Null) for _, cadr := range body { sucess, fail = Eval(local, global, cadr) if fail != nil { diff --git a/runtime/block_test.go b/runtime/block_test.go index 50b7b4c..fe445a7 100644 --- a/runtime/block_test.go +++ b/runtime/block_test.go @@ -29,11 +29,23 @@ func TestBlock(t *testing.T) { wantErr bool }{ { - name: "block & return-from", + name: "case1", arguments: arguments{local, global, readFromString("(block 'foo 1 (return-from 'foo 1))")}, want: readFromString("1"), wantErr: false, }, + { + name: "case2", + arguments: arguments{local, global, readFromString("(block)")}, + want: nil, + wantErr: true, + }, + { + name: "case3", + arguments: arguments{local, global, readFromString("(block 'foo)")}, + want: readFromString("nil"), + wantErr: false, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/runtime/catch.go b/runtime/catch.go index 8311d99..fd4eecd 100644 --- a/runtime/catch.go +++ b/runtime/catch.go @@ -21,7 +21,8 @@ func catch(local, global *environment.Environment, tag ilos.Instance, body ...il return nil, instance.New(class.DomainError, tag, class.Object) } local.CatchTag.Define(tag, nil) - var sucess, fail ilos.Instance + var fail ilos.Instance + sucess := instance.New(class.Null) for _, cadr := range body { sucess, fail = Eval(local, global, cadr) if fail != nil { diff --git a/runtime/catch_test.go b/runtime/catch_test.go index aec7bce..de9ec9c 100644 --- a/runtime/catch_test.go +++ b/runtime/catch_test.go @@ -29,11 +29,23 @@ func TestCatch(t *testing.T) { wantErr bool }{ { - name: "catch & throw", + name: "case1", arguments: arguments{local, global, readFromString("(catch 'foo 1 (throw 'foo 1))")}, want: readFromString("1"), wantErr: false, }, + { + name: "case2", + arguments: arguments{local, global, readFromString("(catch)")}, + want: nil, + wantErr: true, + }, + { + name: "case3", + arguments: arguments{local, global, readFromString("(catch 'foo)")}, + want: readFromString("nil"), + wantErr: false, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/runtime/ilos/instance/function.go b/runtime/ilos/instance/function.go index 98f3245..e252dca 100644 --- a/runtime/ilos/instance/function.go +++ b/runtime/ilos/instance/function.go @@ -49,7 +49,7 @@ func (f Function) Apply(local, global *environment.Environment, arguments ilos.I argv = append(argv, reflect.ValueOf(cadr)) cdr = cddr } - if ft.NumIn() != len(argv) && (!ft.IsVariadic() || ft.NumIn()-2 > len(argv)) { + if ft.NumIn() != len(argv) && (!ft.IsVariadic() || ft.NumIn()-2 >= len(argv)) { return nil, New(class.WrongNumberOfArguments, map[string]ilos.Instance{ "FORM": f.name, "ARGUMENTS": arguments, From 10fd32076a1e87e2124a09c039548d18fa974091 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Fri, 11 Aug 2017 19:27:56 +0900 Subject: [PATCH 126/228] Added functions of section 12.4 --- runtime/eval.go | 4 +- runtime/function.go | 254 ++++++++++++++++++++++++++++++++++++++++- runtime/lambda.go | 16 +-- runtime/lambda_test.go | 2 +- runtime/util.go | 27 +---- 5 files changed, 266 insertions(+), 37 deletions(-) diff --git a/runtime/eval.go b/runtime/eval.go index 911fbff..d926b42 100644 --- a/runtime/eval.go +++ b/runtime/eval.go @@ -17,7 +17,7 @@ func evalArguments(local, global *environment.Environment, arguments ilos.Instan return instance.New(class.Null), nil } // arguments must be a instance of list and ends with nil - if !instance.Of(class.List, arguments) || !UnsafeEndOfListIsNil(arguments) { + if !IsProperList(arguments) { return nil, instance.New(class.ParseError, map[string]ilos.Instance{ "STRING": arguments, "EXPECTED-CLASS": class.List, @@ -143,7 +143,7 @@ func evalFunction(local, global *environment.Environment, car, cdr ilos.Instance func evalCons(local, global *environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { // obj, function call form, must be a instance of Cons, NOT Null, and ends with nil - if !instance.Of(class.Cons, obj) || !UnsafeEndOfListIsNil(obj) { + if !IsProperList(obj) || instance.Of(class.Null, obj) { return nil, instance.New(class.ParseError, map[string]ilos.Instance{ "STRING": obj, "EXPECTED-CLASS": class.Cons, diff --git a/runtime/function.go b/runtime/function.go index 4a5f65e..ad42c9b 100644 --- a/runtime/function.go +++ b/runtime/function.go @@ -11,7 +11,34 @@ import ( "github.com/ta2gch/iris/runtime/ilos/instance" ) -func function(local, global *environment.Environment, fun ilos.Instance) (ilos.Instance, ilos.Instance) { +// Functionp returns t if obj is a (normal or generic) function; +// otherwise, returns nil. obj may be any ISLISP object. +// +// Example: +// (functionp (function car)) => t +// +// Function bindings are entities established during execution of +// a prepared labels or flet forms or by a function-defining form. +// A function binding is an association between an identifier, function-name, +// and a function object that is denoted by function-name—if in operator +// position—or by (function function-name) elsewhere. +func Functionp(local, global *environment.Environment, fun ilos.Instance) (ilos.Instance, ilos.Instance) { + if instance.Of(class.Function, fun) { + return instance.New(class.Symbol, "T"), nil + } + return instance.New(class.Null), nil +} + +// Function returns the function object named by function-name. +// +// An error shall be signaled if no binding has been established for the identifier +// in the function namespace of current lexical environment (error-id. undefined-function). +// The consequences are undefined if the function-name names a macro or special form +// +// Example: +// (funcall (function -) 3) => -3 +// (apply #'- '(4 3)) => 1 +func Function(local, global *environment.Environment, fun ilos.Instance) (ilos.Instance, ilos.Instance) { // car must be a symbol if !instance.Of(class.Symbol, fun) { return nil, instance.New(class.DomainError, map[string]ilos.Instance{ @@ -30,3 +57,228 @@ func function(local, global *environment.Environment, fun ilos.Instance) (ilos.I "NAMESPACE": instance.New(class.Symbol, "FUNCTION"), }) } + +func checkLambdaList(lambdaList ilos.Instance) ilos.Instance { + cdr := lambdaList + ok := false + for instance.Of(class.Cons, cdr) { + cadr := instance.UnsafeCar(cdr) + cddr := instance.UnsafeCdr(cdr) + if !instance.Of(class.Symbol, cadr) { + break + } + if cadr == instance.New(class.Symbol, ":REST") || cadr == instance.New(class.Symbol, "&REST") { + if instance.Of(class.Cons, cddr) && instance.Of(class.Symbol, instance.UnsafeCar(cddr)) && instance.Of(class.Null, instance.UnsafeCdr(cddr)) { + ok = true + } + break + } + cdr = cddr + } + if !ok && instance.Of(class.Null, cdr) { + ok = true + } + if !ok { + return instance.New(class.ProgramError) + } + return nil +} + +// Lambda special form creates a function object. +// +// The scope of the identifiers of the lambda-list is the sequence of forms form*, +// collectively referred to as the body. +// +// When the prepared function is activated later (even if transported as object +// to some other activation) with some arguments, the body of the function is +// evaluated as if it was at the same textual position where the lambda special +// form is located, but in a context where the lambda variables are bound +// in the variable namespace with the values of the corresponding arguments. +// A &rest or :rest variable, if any, is bound to the list of the values of +// the remaining arguments. An error shall be signaled if the number of +// arguments received is incompatible with the specified lambda-list +// (error-id. arity-error). +// +// Once the lambda variables have been bound, the body is executed. +// If the body is empty, nil is returned otherwise the result of the evaluation of +// the last form of body is returned if the body was not left by a non-local exit. +// +// If the function receives a &rest or :rest parameter R, the list L1 to which that +// parameter is bound has indefinite extent. L1 is newly allocated unless the function +// was called with apply and R corresponds to the final argument, L2 , to that call +// to apply (or some subtail of L2), in which case it is implementation defined whether +// L1 shares structure with L2 . +// +// Example: +// ((lambda (x y) (+ (* x x) (* y y))) 3 4) => 25 +// ((lambda (x y &rest z) z) 3 4 5 6) => (5 6) +// ((lambda (x y :rest z) z) 3 4 5 6) => (5 6) +// (funcall (lambda (x y) (- y (* x y))) 7 3) => -18 +func Lambda(local, global *environment.Environment, lambdaList ilos.Instance, form ...ilos.Instance) (ilos.Instance, ilos.Instance) { + if err := checkLambdaList(lambdaList); err != nil { + return nil, err + } + return NewNamedFunction(local, global, instance.New(class.Symbol, "ANONYMOUS-FUNCTION"), lambdaList, form...), nil +} + +// Labels special form allow the definition of new identifiers in the function +// namespace for function objects. +// +// In a labels special form the scope of an identifier function-name is the whole +// labels special form (excluding nested scopes, if any); for the flet special form, +// the scope of an identifier is only the body-form*. Within these scopes, +// each function-name is bound to a function object whose behavior is equivalent +// to (lambda lambda-list form*), where free identifier references are resolved as follows: +// +// For a labels form, such free references are resolved in the lexical environment +// that was active immediately outside the labels form augmented by the function +// bindings for the given function-names (i.e., any reference to a function +// function-name refers to a binding created by the labels). +// +// For a flet form, free identifier references in the lambda-expression are resolved +// in the lexical environment that was active immediately outside the flet form +// (i.e., any reference to a function function-name are not visible). +// +// During activation, the prepared labels or flet establishes function bindings and +// then evaluates each body-form in the body sequentially; the value of the last one +// (or nil if there is none) is the value returned by the special form activation. +// +// No function-name may appear more than once in the function bindings. +// +// Example: +// (labels ((evenp (n) +// (if (= n 0) +// t +// (oddp (- n 1)))) +// (oddp (n) +// (if (= n 0) +// nil +// (evenp (- n 1))))) +// (evenp 88)) => t +func Labels(local, global *environment.Environment, functions ilos.Instance, bodyForm ...ilos.Instance) (ilos.Instance, ilos.Instance) { + cdr := functions + for instance.Of(class.Cons, cdr) { + cadr := instance.UnsafeCar(cdr) + functionName := instance.UnsafeCar(cadr) + lambdaList := instance.UnsafeCar(instance.UnsafeCdr(cadr)) + if err := checkLambdaList(lambdaList); err != nil { + return nil, err + } + + cddadr := instance.UnsafeCdr(instance.UnsafeCdr(cadr)) + form := []ilos.Instance{} + for instance.Of(class.Cons, cddadr) { + caddadr := instance.UnsafeCar(cddadr) + form = append(form, caddadr) + cddadr = instance.UnsafeCdr(cddadr) + } + local.Function.Define(functionName, NewNamedFunction(local, global, functionName, lambdaList, form...)) + cdr = instance.UnsafeCdr(cdr) + } + ret := instance.New(class.Null) + var err ilos.Instance + for _, form := range bodyForm { + ret, err = Eval(local, global, form) + if err != nil { + return nil, err + } + } + return ret, nil +} + +// Flet special form allow the definition of new identifiers in the function +// namespace for function objects (see Labels). +// +// Example: +// (flet ((f (x) (+ x 3))) +// (flet ((f (x) (+ x (f x)))) +// (f 7))) => 17 +func Flet(local, global *environment.Environment, functions ilos.Instance, bodyForm ...ilos.Instance) (ilos.Instance, ilos.Instance) { + cdr := functions + env := environment.New() + env.BlockTag = append(local.BlockTag, env.BlockTag...) + env.TagbodyTag = append(local.TagbodyTag, env.TagbodyTag...) + env.CatchTag = append(local.CatchTag, env.CatchTag...) + env.Variable = append(local.Variable, env.Variable...) + env.Function = append(local.Function, env.Function...) + env.Special = append(local.Special, env.Special...) + env.Macro = append(local.Macro, env.Macro...) + env.DynamicVariable = append(local.DynamicVariable, env.DynamicVariable...) + for instance.Of(class.Cons, cdr) { + cadr := instance.UnsafeCar(cdr) + functionName := instance.UnsafeCar(cadr) + lambdaList := instance.UnsafeCar(instance.UnsafeCdr(cadr)) + if err := checkLambdaList(lambdaList); err != nil { + return nil, err + } + + cddadr := instance.UnsafeCdr(instance.UnsafeCdr(cadr)) + form := []ilos.Instance{} + for instance.Of(class.Cons, cddadr) { + caddadr := instance.UnsafeCar(cddadr) + form = append(form, caddadr) + cddadr = instance.UnsafeCdr(cddadr) + } + env.Function.Define(functionName, NewNamedFunction(local, global, functionName, lambdaList, form...)) + cdr = instance.UnsafeCdr(cdr) + } + ret := instance.New(class.Null) + var err ilos.Instance + for _, form := range bodyForm { + ret, err = Eval(env, global, form) + if err != nil { + return nil, err + } + } + return ret, nil +} + +// Apply applies function to the arguments, obj*, followed by the elements of list, +// if any. It returns the value returned by function. +// +// An error shall be signaled if function is not a function (error-id. domain-error). +// Each obj may be any ISLISP object. An error shall be signaled +// if list is not a proper list (error-id. improper-argument-list). +// +// Example: +// (apply (if (< 1 2) (function max) (function min)) 1 2 (list 3 4)) => 4 +// (defun compose (f g) +// (lambda (:rest args) +// (funcall f (apply g args))))) => compose +// (funcall (compose (function sqrt) (function *)) 12 75) => 30 +func Apply(local, global *environment.Environment, function ilos.Instance, obj ...ilos.Instance) (ilos.Instance, ilos.Instance) { + list := instance.New(class.Null) + if instance.Of(class.List, obj[len(obj)-1]) { + list = obj[len(obj)-1] + if !IsProperList(list) { + return nil, instance.New(class.ProgramError) + } + obj = obj[:len(obj)-1] + } + for i := len(obj) - 1; i >= 0; i-- { + list = instance.New(class.Cons, obj[i], list) + } + if !instance.Of(class.Function, function) { + return nil, instance.New(class.DomainError, map[string]ilos.Instance{ + "OBJECT": function, + "EXPECTED-CLASS": class.Function, + }) + } + ret, err := function.(instance.Applicable).Apply(local, global, list) + return ret, err +} + +// Funcall activates the specified function function and returns the value that the function returns. +// The ith argument (2 ≤ i) of funcall becomes the (i − 1)th argument of the function. +// +// An error shall be signaled if function is not a function (error-id. domain-error). +// Each obj may be any ISLISP object. +// +// Example: +// (let ((x '(1 2 3))) +// (funcall (cond ((listp x) (function car)) +// (t (lambda (x) (cons x 1)))) x)) => 1 +func Funcall(local, global *environment.Environment, function ilos.Instance, obj ...ilos.Instance) (ilos.Instance, ilos.Instance) { + ret, err := Apply(local, global, function, obj...) + return ret, err +} diff --git a/runtime/lambda.go b/runtime/lambda.go index 6fc1b2c..31a4ae7 100644 --- a/runtime/lambda.go +++ b/runtime/lambda.go @@ -11,14 +11,7 @@ import ( "github.com/ta2gch/iris/runtime/ilos/instance" ) -func lambda(local, global *environment.Environment, lambdaList ilos.Instance, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { - // lambdaFunction-list must be a instance of list and ends with nil - if !instance.Of(class.List, lambdaList) || !UnsafeEndOfListIsNil(lambdaList) { // Checked at the head of test - return nil, instance.New(class.DomainError, map[string]ilos.Instance{ - "OBJECT": lambdaList, - "EXPECTED-CLASS": class.List, - }) - } +func NewNamedFunction(local, global *environment.Environment, functionName, lambdaList ilos.Instance, forms ...ilos.Instance) ilos.Instance { lexical := local cdr := lambdaList parameters := []ilos.Instance{} @@ -31,8 +24,7 @@ func lambda(local, global *environment.Environment, lambdaList ilos.Instance, fo parameters = append(parameters, cadr) cdr = instance.UnsafeCdr(cdr) } - name := instance.New(class.Symbol, "ANONYMOUS-FUNCTION") - return instance.New(class.Function, name, func(local, global *environment.Environment, arguments ...ilos.Instance) (ilos.Instance, ilos.Instance) { + return instance.New(class.Function, functionName, func(local, global *environment.Environment, arguments ...ilos.Instance) (ilos.Instance, ilos.Instance) { local.BlockTag = append(lexical.BlockTag, local.BlockTag...) local.TagbodyTag = append(lexical.TagbodyTag, local.TagbodyTag...) local.CatchTag = append(lexical.CatchTag, local.CatchTag...) @@ -47,7 +39,7 @@ func lambda(local, global *environment.Environment, lambdaList ilos.Instance, fo v = instance.New(class.Cons, arguments[i], v) } return nil, instance.New(class.WrongNumberOfArguments, map[string]ilos.Instance{ - "FORM": name, + "FORM": functionName, "ARGUMENTS": v, }) } @@ -74,5 +66,5 @@ func lambda(local, global *environment.Environment, lambdaList ilos.Instance, fo } } return ret, nil - }), nil + }) } diff --git a/runtime/lambda_test.go b/runtime/lambda_test.go index 38a2406..87ce321 100644 --- a/runtime/lambda_test.go +++ b/runtime/lambda_test.go @@ -16,7 +16,7 @@ import ( func TestLambda(t *testing.T) { local, global := environment.New(), environment.TopLevel - defspecial("LAMBDA", lambda) + defspecial("LAMBDA", Lambda) type arguments struct { local *environment.Environment global *environment.Environment diff --git a/runtime/util.go b/runtime/util.go index bcfd4d0..3fe7bc9 100644 --- a/runtime/util.go +++ b/runtime/util.go @@ -16,33 +16,18 @@ import ( "github.com/ta2gch/iris/runtime/ilos/instance" ) -// UnsafeEndOfListIsNil test a given instance ends with nil -// but doesn't work correctly if the given instance isn't a instance of list -// So you have to check the instance. -func UnsafeEndOfListIsNil(i ilos.Instance) bool { - cdr := i - for instance.Of(class.Cons, cdr) { - cdr = instance.UnsafeCdr(cdr) // Checked at the top of// This loop +// IsProperList tests given argument is proper list +// Proper list is the list terminated by nil. +func IsProperList(i ilos.Instance) bool { + if instance.Of(class.Cons, i) { + return IsProperList(instance.UnsafeCdr(i)) } - if instance.Of(class.Null, cdr) { + if instance.Of(class.Null, i) { return true } return false } -// UnsafeListLength return a length of list -// but doesn't work correctly if the given instance aren't a instance of list. -// So you have to check the instance. -func UnsafeListLength(i ilos.Instance) int { - cdr := i - cnt := 0 - for instance.Of(class.Cons, cdr) { - cdr = instance.UnsafeCdr(cdr) // Checked at the top of// This loop - cnt++ - } - return cnt -} - func readFromString(s string) ilos.Instance { e, _ := parser.Parse(tokenizer.New(strings.NewReader(s))) return e From ae94feee30c528c74824058d276501ee5b1d8353 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Fri, 11 Aug 2017 21:23:54 +0900 Subject: [PATCH 127/228] Exported ParseAtom --- reader/parser/parser.go | 4 ++-- reader/parser/parser_test.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/reader/parser/parser.go b/reader/parser/parser.go index 767f76c..1563303 100644 --- a/reader/parser/parser.go +++ b/reader/parser/parser.go @@ -19,7 +19,7 @@ import ( var eop = instance.New(class.Symbol, "End Of Parentheses") var bod = instance.New(class.Symbol, "Begin Of Dot") -func parseAtom(tok string) (ilos.Instance, ilos.Instance) { +func ParseAtom(tok string) (ilos.Instance, ilos.Instance) { // // integer // @@ -179,7 +179,7 @@ func Parse(t *tokenizer.Tokenizer) (ilos.Instance, ilos.Instance) { } return m, nil } - atom, err := parseAtom(tok) + atom, err := ParseAtom(tok) if err != nil { return nil, err } diff --git a/reader/parser/parser_test.go b/reader/parser/parser_test.go index df9bcce..a85439a 100644 --- a/reader/parser/parser_test.go +++ b/reader/parser/parser_test.go @@ -155,7 +155,7 @@ func Test_parseAtom(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := parseAtom(tt.arguments.tok) + got, err := ParseAtom(tt.arguments.tok) if (err != nil) != tt.wantErr { t.Errorf("parseAtom() error = %v, wantErr %v", err, tt.wantErr) return From 15496444d2d89cd4460ca4190dbdbe9aadff3b81 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Fri, 11 Aug 2017 21:25:03 +0900 Subject: [PATCH 128/228] Added boolean values --- runtime/block.go | 2 +- runtime/boolean.go | 31 ++++++++++++++++++ runtime/catch.go | 2 +- runtime/eval.go | 8 ++--- runtime/eval_test.go | 2 +- runtime/logical.go | 17 ++++++++++ runtime/namedfunc.go | 70 +++++++++++++++++++++++++++++++++++++++++ runtime/null.go | 16 ++++++++++ runtime/tagbody.go | 2 +- runtime/tagbody_test.go | 6 ++-- runtime/util.go | 6 ++-- 11 files changed, 146 insertions(+), 16 deletions(-) create mode 100644 runtime/boolean.go create mode 100644 runtime/logical.go create mode 100644 runtime/namedfunc.go create mode 100644 runtime/null.go diff --git a/runtime/block.go b/runtime/block.go index c288ef7..feb5b05 100644 --- a/runtime/block.go +++ b/runtime/block.go @@ -33,7 +33,7 @@ func block(local, global *environment.Environment, tag ilos.Instance, body ...il } local.BlockTag.Define(tag, nil) var fail ilos.Instance - sucess := instance.New(class.Null) + sucess := Nil for _, cadr := range body { sucess, fail = Eval(local, global, cadr) if fail != nil { diff --git a/runtime/boolean.go b/runtime/boolean.go new file mode 100644 index 0000000..1f4d86e --- /dev/null +++ b/runtime/boolean.go @@ -0,0 +1,31 @@ +package runtime + +import ( + "github.com/ta2gch/iris/runtime/ilos/class" + "github.com/ta2gch/iris/runtime/ilos/instance" +) + +// The values t and nil are called booleans. t denotes true, +// and nil is the only value denoting false. Predicates, +// also called boolean functions, are functions that return +// t when satisfied and nil otherwise. +// +// Any object other than nil is treated as true (not just t). +// When objects are treated as true or nil this way they are +// called quasi-booleans. +// +// t is an identifier naming the symbol t, and nil is +// an identifier naming the symbol nil (which is also the empty list). +// nil is the unique instance of the null class. +// +// Like boolean functions, the and and or special forms return truth values; +// however, these truth values are nil when the test is not +// satisfied and a non-nil value otherwise. +// The result of and and or are quasi-booleans. +// +// t is a named constant whose value is the symbol t itself. +// nil is a named constant whose value is the symbol nil itself. +var ( + Nil = instance.New(class.Null) + T = instance.New(class.Symbol, "T") +) diff --git a/runtime/catch.go b/runtime/catch.go index fd4eecd..d6f1ec7 100644 --- a/runtime/catch.go +++ b/runtime/catch.go @@ -22,7 +22,7 @@ func catch(local, global *environment.Environment, tag ilos.Instance, body ...il } local.CatchTag.Define(tag, nil) var fail ilos.Instance - sucess := instance.New(class.Null) + sucess := Nil for _, cadr := range body { sucess, fail = Eval(local, global, cadr) if fail != nil { diff --git a/runtime/eval.go b/runtime/eval.go index d926b42..cd7e189 100644 --- a/runtime/eval.go +++ b/runtime/eval.go @@ -14,10 +14,10 @@ import ( func evalArguments(local, global *environment.Environment, arguments ilos.Instance) (ilos.Instance, ilos.Instance) { // if arguments ends here if instance.Of(class.Null, arguments) { - return instance.New(class.Null), nil + return Nil, nil } // arguments must be a instance of list and ends with nil - if !IsProperList(arguments) { + if !isProperList(arguments) { return nil, instance.New(class.ParseError, map[string]ilos.Instance{ "STRING": arguments, "EXPECTED-CLASS": class.List, @@ -143,7 +143,7 @@ func evalFunction(local, global *environment.Environment, car, cdr ilos.Instance func evalCons(local, global *environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { // obj, function call form, must be a instance of Cons, NOT Null, and ends with nil - if !IsProperList(obj) || instance.Of(class.Null, obj) { + if !isProperList(obj) || instance.Of(class.Null, obj) { return nil, instance.New(class.ParseError, map[string]ilos.Instance{ "STRING": obj, "EXPECTED-CLASS": class.Cons, @@ -191,7 +191,7 @@ func evalVariable(local, global *environment.Environment, obj ilos.Instance) (il // Eval evaluates any classs func Eval(local, global *environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { if instance.Of(class.Null, obj) { - return instance.New(class.Null), nil + return Nil, nil } if instance.Of(class.Symbol, obj) { ret, err := evalVariable(local, global, obj) diff --git a/runtime/eval_test.go b/runtime/eval_test.go index d2b7026..6b9e154 100644 --- a/runtime/eval_test.go +++ b/runtime/eval_test.go @@ -22,7 +22,7 @@ func TestEval(t *testing.T) { }) defglobal("PI", instance.New(class.Float, 3.14)) defmacro("MINC", func(local *environment.Environment, global *environment.Environment, arg ilos.Instance) (ilos.Instance, ilos.Instance) { - return instance.New(class.Cons, instance.New(class.Symbol, "INC"), instance.New(class.Cons, arg, instance.New(class.Null))), nil + return instance.New(class.Cons, instance.New(class.Symbol, "INC"), instance.New(class.Cons, arg, Nil)), nil }) type arguments struct { obj ilos.Instance diff --git a/runtime/logical.go b/runtime/logical.go new file mode 100644 index 0000000..f1c72a7 --- /dev/null +++ b/runtime/logical.go @@ -0,0 +1,17 @@ +package runtime + +import ( + "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/ilos" + "github.com/ta2gch/iris/runtime/ilos/class" + "github.com/ta2gch/iris/runtime/ilos/instance" +) + +// Not is the logical “not” (or “¬”). It returns t if obj is nil +// and nil otherwise. obj may be any ISLISP object. +func Not(_, _ *environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { + if instance.Of(class.Null, obj) { + return T, nil + } + return Nil, nil +} diff --git a/runtime/namedfunc.go b/runtime/namedfunc.go new file mode 100644 index 0000000..39d1e06 --- /dev/null +++ b/runtime/namedfunc.go @@ -0,0 +1,70 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package runtime + +import ( + "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/ilos" + "github.com/ta2gch/iris/runtime/ilos/class" + "github.com/ta2gch/iris/runtime/ilos/instance" +) + +func newNamedFunction(local, global *environment.Environment, functionName, lambdaList ilos.Instance, forms ...ilos.Instance) ilos.Instance { + lexical := local + cdr := lambdaList + parameters := []ilos.Instance{} + variadic := false + for instance.Of(class.Cons, cdr) { + cadr := instance.UnsafeCar(cdr) + if cadr == instance.New(class.Symbol, ":REST") || cadr == instance.New(class.Symbol, "&REST") { + variadic = true + } + parameters = append(parameters, cadr) + cdr = instance.UnsafeCdr(cdr) + } + return instance.New(class.Function, functionName, func(local, global *environment.Environment, arguments ...ilos.Instance) (ilos.Instance, ilos.Instance) { + local.BlockTag = append(lexical.BlockTag, local.BlockTag...) + local.TagbodyTag = append(lexical.TagbodyTag, local.TagbodyTag...) + local.CatchTag = append(lexical.CatchTag, local.CatchTag...) + local.Variable = append(lexical.Variable, local.Variable...) + local.Function = append(lexical.Function, local.Function...) + local.Special = append(lexical.Special, local.Special...) + local.Macro = append(lexical.Macro, local.Macro...) + local.DynamicVariable = append(lexical.DynamicVariable, local.DynamicVariable...) + if (variadic && len(parameters)-2 > len(arguments)) || (!variadic && len(parameters) != len(arguments)) { + v := Nil + for i := len(arguments) - 1; i >= 0; i-- { + v = instance.New(class.Cons, arguments[i], v) + } + return nil, instance.New(class.WrongNumberOfArguments, map[string]ilos.Instance{ + "FORM": functionName, + "ARGUMENTS": v, + }) + } + for idx := range parameters { + key := parameters[idx] + if key == instance.New(class.Symbol, ":REST") || key == instance.New(class.Symbol, "&REST") { + key := parameters[idx+1] + value := Nil + for i := len(arguments) - 1; i >= idx; i-- { + value = instance.New(class.Cons, arguments[i], value) + } + local.Variable.Define(key, value) + break + } + value := arguments[idx] + local.Variable.Define(key, value) + } + ret := Nil + var err ilos.Instance + for _, form := range forms { + ret, err = Eval(local, global, form) + if err != nil { + return nil, err + } + } + return ret, nil + }) +} diff --git a/runtime/null.go b/runtime/null.go new file mode 100644 index 0000000..ffe7c0a --- /dev/null +++ b/runtime/null.go @@ -0,0 +1,16 @@ +package runtime + +import ( + "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/ilos" + "github.com/ta2gch/iris/runtime/ilos/class" + "github.com/ta2gch/iris/runtime/ilos/instance" +) + +// Null returns t if obj is nil; otherwise, returns nil obj may be any ISLISP object. +func Null(_, _ *environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { + if instance.Of(class.Null, obj) { + return T, nil + } + return Nil, nil +} diff --git a/runtime/tagbody.go b/runtime/tagbody.go index 533dee0..11d7a0e 100644 --- a/runtime/tagbody.go +++ b/runtime/tagbody.go @@ -50,7 +50,7 @@ func tagbody(local, global *environment.Environment, body ...ilos.Instance) (ilo } } } - return instance.New(class.Null), nil + return Nil, nil } func tagbodyGo(local, global *environment.Environment, tag ilos.Instance) (ilos.Instance, ilos.Instance) { diff --git a/runtime/tagbody_test.go b/runtime/tagbody_test.go index 710f836..b866089 100644 --- a/runtime/tagbody_test.go +++ b/runtime/tagbody_test.go @@ -10,8 +10,6 @@ import ( "github.com/ta2gch/iris/runtime/environment" "github.com/ta2gch/iris/runtime/ilos" - "github.com/ta2gch/iris/runtime/ilos/class" - "github.com/ta2gch/iris/runtime/ilos/instance" ) func TestTagbody(t *testing.T) { @@ -35,13 +33,13 @@ func TestTagbody(t *testing.T) { { name: "tagbody & go", arguments: arguments{local, global, readFromString("(catch 'foo (tagbody (go bar) (throw 'foo 1) bar))")}, - want: instance.New(class.Null), + want: Nil, wantErr: false, }, { name: "nested tagbody & go", arguments: arguments{local, global, readFromString("(catch 'foo (tagbody (tagbody (go bar) (throw 'foo 1) bar (go foobar)) foobar))")}, - want: instance.New(class.Null), + want: Nil, wantErr: false, }, } diff --git a/runtime/util.go b/runtime/util.go index 3fe7bc9..b7ac646 100644 --- a/runtime/util.go +++ b/runtime/util.go @@ -16,11 +16,9 @@ import ( "github.com/ta2gch/iris/runtime/ilos/instance" ) -// IsProperList tests given argument is proper list -// Proper list is the list terminated by nil. -func IsProperList(i ilos.Instance) bool { +func isProperList(i ilos.Instance) bool { if instance.Of(class.Cons, i) { - return IsProperList(instance.UnsafeCdr(i)) + return isProperList(instance.UnsafeCdr(i)) } if instance.Of(class.Null, i) { return true From 78fe09f60555ca9de7cb980d72279644bfadcdcd Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Fri, 11 Aug 2017 21:25:20 +0900 Subject: [PATCH 129/228] Remove examples --- runtime/function.go | 59 +++++++-------------------------------------- 1 file changed, 9 insertions(+), 50 deletions(-) diff --git a/runtime/function.go b/runtime/function.go index ad42c9b..22588d4 100644 --- a/runtime/function.go +++ b/runtime/function.go @@ -14,9 +14,6 @@ import ( // Functionp returns t if obj is a (normal or generic) function; // otherwise, returns nil. obj may be any ISLISP object. // -// Example: -// (functionp (function car)) => t -// // Function bindings are entities established during execution of // a prepared labels or flet forms or by a function-defining form. // A function binding is an association between an identifier, function-name, @@ -24,9 +21,9 @@ import ( // position—or by (function function-name) elsewhere. func Functionp(local, global *environment.Environment, fun ilos.Instance) (ilos.Instance, ilos.Instance) { if instance.Of(class.Function, fun) { - return instance.New(class.Symbol, "T"), nil + return T, nil } - return instance.New(class.Null), nil + return Nil, nil } // Function returns the function object named by function-name. @@ -34,10 +31,6 @@ func Functionp(local, global *environment.Environment, fun ilos.Instance) (ilos. // An error shall be signaled if no binding has been established for the identifier // in the function namespace of current lexical environment (error-id. undefined-function). // The consequences are undefined if the function-name names a macro or special form -// -// Example: -// (funcall (function -) 3) => -3 -// (apply #'- '(4 3)) => 1 func Function(local, global *environment.Environment, fun ilos.Instance) (ilos.Instance, ilos.Instance) { // car must be a symbol if !instance.Of(class.Symbol, fun) { @@ -108,17 +101,11 @@ func checkLambdaList(lambdaList ilos.Instance) ilos.Instance { // was called with apply and R corresponds to the final argument, L2 , to that call // to apply (or some subtail of L2), in which case it is implementation defined whether // L1 shares structure with L2 . -// -// Example: -// ((lambda (x y) (+ (* x x) (* y y))) 3 4) => 25 -// ((lambda (x y &rest z) z) 3 4 5 6) => (5 6) -// ((lambda (x y :rest z) z) 3 4 5 6) => (5 6) -// (funcall (lambda (x y) (- y (* x y))) 7 3) => -18 func Lambda(local, global *environment.Environment, lambdaList ilos.Instance, form ...ilos.Instance) (ilos.Instance, ilos.Instance) { if err := checkLambdaList(lambdaList); err != nil { return nil, err } - return NewNamedFunction(local, global, instance.New(class.Symbol, "ANONYMOUS-FUNCTION"), lambdaList, form...), nil + return newNamedFunction(local, global, instance.New(class.Symbol, "ANONYMOUS-FUNCTION"), lambdaList, form...), nil } // Labels special form allow the definition of new identifiers in the function @@ -144,17 +131,6 @@ func Lambda(local, global *environment.Environment, lambdaList ilos.Instance, fo // (or nil if there is none) is the value returned by the special form activation. // // No function-name may appear more than once in the function bindings. -// -// Example: -// (labels ((evenp (n) -// (if (= n 0) -// t -// (oddp (- n 1)))) -// (oddp (n) -// (if (= n 0) -// nil -// (evenp (- n 1))))) -// (evenp 88)) => t func Labels(local, global *environment.Environment, functions ilos.Instance, bodyForm ...ilos.Instance) (ilos.Instance, ilos.Instance) { cdr := functions for instance.Of(class.Cons, cdr) { @@ -172,10 +148,10 @@ func Labels(local, global *environment.Environment, functions ilos.Instance, bod form = append(form, caddadr) cddadr = instance.UnsafeCdr(cddadr) } - local.Function.Define(functionName, NewNamedFunction(local, global, functionName, lambdaList, form...)) + local.Function.Define(functionName, newNamedFunction(local, global, functionName, lambdaList, form...)) cdr = instance.UnsafeCdr(cdr) } - ret := instance.New(class.Null) + ret := Nil var err ilos.Instance for _, form := range bodyForm { ret, err = Eval(local, global, form) @@ -188,11 +164,6 @@ func Labels(local, global *environment.Environment, functions ilos.Instance, bod // Flet special form allow the definition of new identifiers in the function // namespace for function objects (see Labels). -// -// Example: -// (flet ((f (x) (+ x 3))) -// (flet ((f (x) (+ x (f x)))) -// (f 7))) => 17 func Flet(local, global *environment.Environment, functions ilos.Instance, bodyForm ...ilos.Instance) (ilos.Instance, ilos.Instance) { cdr := functions env := environment.New() @@ -219,10 +190,10 @@ func Flet(local, global *environment.Environment, functions ilos.Instance, bodyF form = append(form, caddadr) cddadr = instance.UnsafeCdr(cddadr) } - env.Function.Define(functionName, NewNamedFunction(local, global, functionName, lambdaList, form...)) + env.Function.Define(functionName, newNamedFunction(local, global, functionName, lambdaList, form...)) cdr = instance.UnsafeCdr(cdr) } - ret := instance.New(class.Null) + ret := Nil var err ilos.Instance for _, form := range bodyForm { ret, err = Eval(env, global, form) @@ -239,18 +210,11 @@ func Flet(local, global *environment.Environment, functions ilos.Instance, bodyF // An error shall be signaled if function is not a function (error-id. domain-error). // Each obj may be any ISLISP object. An error shall be signaled // if list is not a proper list (error-id. improper-argument-list). -// -// Example: -// (apply (if (< 1 2) (function max) (function min)) 1 2 (list 3 4)) => 4 -// (defun compose (f g) -// (lambda (:rest args) -// (funcall f (apply g args))))) => compose -// (funcall (compose (function sqrt) (function *)) 12 75) => 30 func Apply(local, global *environment.Environment, function ilos.Instance, obj ...ilos.Instance) (ilos.Instance, ilos.Instance) { - list := instance.New(class.Null) + list := Nil if instance.Of(class.List, obj[len(obj)-1]) { list = obj[len(obj)-1] - if !IsProperList(list) { + if !isProperList(list) { return nil, instance.New(class.ProgramError) } obj = obj[:len(obj)-1] @@ -273,11 +237,6 @@ func Apply(local, global *environment.Environment, function ilos.Instance, obj . // // An error shall be signaled if function is not a function (error-id. domain-error). // Each obj may be any ISLISP object. -// -// Example: -// (let ((x '(1 2 3))) -// (funcall (cond ((listp x) (function car)) -// (t (lambda (x) (cons x 1)))) x)) => 1 func Funcall(local, global *environment.Environment, function ilos.Instance, obj ...ilos.Instance) (ilos.Instance, ilos.Instance) { ret, err := Apply(local, global, function, obj...) return ret, err From 90cb5478ad66fe82fe8c5ee1d8c057b0b2ec6f0f Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Fri, 11 Aug 2017 21:25:43 +0900 Subject: [PATCH 130/228] Delete lambda.go --- runtime/lambda.go | 70 --------------------------------------- runtime/lambda_test.go | 75 ------------------------------------------ 2 files changed, 145 deletions(-) delete mode 100644 runtime/lambda.go delete mode 100644 runtime/lambda_test.go diff --git a/runtime/lambda.go b/runtime/lambda.go deleted file mode 100644 index 31a4ae7..0000000 --- a/runtime/lambda.go +++ /dev/null @@ -1,70 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at http://mozilla.org/MPL/2.0/. - -package runtime - -import ( - "github.com/ta2gch/iris/runtime/environment" - "github.com/ta2gch/iris/runtime/ilos" - "github.com/ta2gch/iris/runtime/ilos/class" - "github.com/ta2gch/iris/runtime/ilos/instance" -) - -func NewNamedFunction(local, global *environment.Environment, functionName, lambdaList ilos.Instance, forms ...ilos.Instance) ilos.Instance { - lexical := local - cdr := lambdaList - parameters := []ilos.Instance{} - variadic := false - for instance.Of(class.Cons, cdr) { - cadr := instance.UnsafeCar(cdr) - if cadr == instance.New(class.Symbol, ":REST") || cadr == instance.New(class.Symbol, "&REST") { - variadic = true - } - parameters = append(parameters, cadr) - cdr = instance.UnsafeCdr(cdr) - } - return instance.New(class.Function, functionName, func(local, global *environment.Environment, arguments ...ilos.Instance) (ilos.Instance, ilos.Instance) { - local.BlockTag = append(lexical.BlockTag, local.BlockTag...) - local.TagbodyTag = append(lexical.TagbodyTag, local.TagbodyTag...) - local.CatchTag = append(lexical.CatchTag, local.CatchTag...) - local.Variable = append(lexical.Variable, local.Variable...) - local.Function = append(lexical.Function, local.Function...) - local.Special = append(lexical.Special, local.Special...) - local.Macro = append(lexical.Macro, local.Macro...) - local.DynamicVariable = append(lexical.DynamicVariable, local.DynamicVariable...) - if (variadic && len(parameters)-2 > len(arguments)) || (!variadic && len(parameters) != len(arguments)) { - v := instance.New(class.Null) - for i := len(arguments) - 1; i >= 0; i-- { - v = instance.New(class.Cons, arguments[i], v) - } - return nil, instance.New(class.WrongNumberOfArguments, map[string]ilos.Instance{ - "FORM": functionName, - "ARGUMENTS": v, - }) - } - for idx := range parameters { - key := parameters[idx] - if key == instance.New(class.Symbol, ":REST") || key == instance.New(class.Symbol, "&REST") { - key := parameters[idx+1] - value := instance.New(class.Null) - for i := len(arguments) - 1; i >= idx; i-- { - value = instance.New(class.Cons, arguments[i], value) - } - local.Variable.Define(key, value) - break - } - value := arguments[idx] - local.Variable.Define(key, value) - } - ret := instance.New(class.Null) - var err ilos.Instance - for _, form := range forms { - ret, err = Eval(local, global, form) - if err != nil { - return nil, err - } - } - return ret, nil - }) -} diff --git a/runtime/lambda_test.go b/runtime/lambda_test.go deleted file mode 100644 index 87ce321..0000000 --- a/runtime/lambda_test.go +++ /dev/null @@ -1,75 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at http://mozilla.org/MPL/2.0/. - -package runtime - -import ( - "reflect" - "testing" - - "github.com/ta2gch/iris/runtime/environment" - "github.com/ta2gch/iris/runtime/ilos" - "github.com/ta2gch/iris/runtime/ilos/class" - "github.com/ta2gch/iris/runtime/ilos/instance" -) - -func TestLambda(t *testing.T) { - local, global := environment.New(), environment.TopLevel - defspecial("LAMBDA", Lambda) - type arguments struct { - local *environment.Environment - global *environment.Environment - obj ilos.Instance - } - tests := []struct { - name string - arguments arguments - want ilos.Instance - wantErr bool - }{ - { - name: "case1", - arguments: arguments{local, global, readFromString("((lambda (x)) 1)")}, - want: instance.New(class.Null), - wantErr: false, - }, - { - name: "case2", - arguments: arguments{local, global, readFromString("((lambda (:rest xs) xs) 1 2)")}, - want: readFromString("(1 2)"), - wantErr: false, - }, - { - name: "case3", - arguments: arguments{local, global, readFromString("((lambda (:rest xs) xs))")}, - want: readFromString("nil"), - wantErr: false, - }, - { - name: "case4", - arguments: arguments{local, global, readFromString("((lambda (x) x) 1 2)")}, - want: nil, - wantErr: true, - }, - { - name: "case5", - arguments: arguments{local, global, readFromString("((lambda (x :rest xs) x))")}, - want: nil, - wantErr: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, err := Eval(tt.arguments.local, tt.arguments.global, tt.arguments.obj) - if (err != nil) != tt.wantErr { - t.Errorf("Eval() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !reflect.DeepEqual(got, tt.want) { - t.Errorf("Eval() = %v, want %v", got, tt.want) - t.Errorf("Eval() = %v, want %v", got, tt.want) - } - }) - } -} From 7c3c968cef6bbce91cae079ae66477e140565d7f Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Fri, 11 Aug 2017 21:28:11 +0900 Subject: [PATCH 131/228] Added Lincese term --- runtime/boolean.go | 4 ++ runtime/logical.go | 4 ++ runtime/null.go | 4 ++ runtime/number.go | 93 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 105 insertions(+) create mode 100644 runtime/number.go diff --git a/runtime/boolean.go b/runtime/boolean.go index 1f4d86e..107b11e 100644 --- a/runtime/boolean.go +++ b/runtime/boolean.go @@ -1,3 +1,7 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + package runtime import ( diff --git a/runtime/logical.go b/runtime/logical.go index f1c72a7..af14825 100644 --- a/runtime/logical.go +++ b/runtime/logical.go @@ -1,3 +1,7 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + package runtime import ( diff --git a/runtime/null.go b/runtime/null.go index ffe7c0a..aed970f 100644 --- a/runtime/null.go +++ b/runtime/null.go @@ -1,3 +1,7 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + package runtime import ( diff --git a/runtime/number.go b/runtime/number.go new file mode 100644 index 0000000..1b5ca88 --- /dev/null +++ b/runtime/number.go @@ -0,0 +1,93 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package runtime + +import ( + "github.com/ta2gch/iris/reader/parser" + "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/ilos" + "github.com/ta2gch/iris/runtime/ilos/class" + "github.com/ta2gch/iris/runtime/ilos/instance" +) + +// Numberp returns t if obj is a number (instance of class number); otherwise, +// returns nil. The obj may be any ISLISP object. +func Numberp(_, _ *environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { + if instance.Of(class.Number, obj) { + return T, nil + } + return Nil, nil +} + +// ParseNumber scans (as if by read) and if the resulting lexeme +// is the textual representation of a number, the number it represents is returned. +// +// An error shall be signaled if string is not a string (error-id. domain-error). +// An error shall be signaled if string is not the textual representation +// of a number (error-id. cannot-parse-number). +func ParseNumber(_, _ *environment.Environment, str ilos.Instance) (ilos.Instance, ilos.Instance) { + if !instance.Of(class.String, str) { + return nil, instance.New(class.DomainError, map[string]ilos.Instance{ + "OBJECT": str, + "EXPECTED-CLASS": class.String, + }) + } + ret, err := parser.ParseAtom(string(str.(instance.String))) + if err != nil || !instance.Of(class.Number, ret) { + return nil, instance.New(class.ParseError, map[string]ilos.Instance{ + "STRING": str, + "EXPECTED-CLASS": class.Number, + }) + } + return ret, err +} + +// EqualNumber returns t if x1 has the same mathematical value as x2 ; +// otherwise, returns nil. An error shall be signaled if either x1 or x2 is not a number +// (error-id. domain-error). +// +// Note: = differs from eql because = compares only the mathematical values of its arguments, +// whereas eql also compares the representations +func EqualNumber(_, _ *environment.Environment, x1, x2 ilos.Instance) (ilos.Instance, ilos.Instance) { + if instance.Of(class.Number, x1) { + return nil, instance.New(class.DomainError, map[string]ilos.Instance{ + "OBJECT": x1, + "EXPECTED-CLASS": class.String, + }) + } + if instance.Of(class.Number, x2) { + return nil, instance.New(class.DomainError, map[string]ilos.Instance{ + "OBJECT": x2, + "EXPECTED-CLASS": class.String, + }) + } + ret := false + switch { + case instance.Of(class.Integer, x1) && instance.Of(class.Integer, x2): + ret = x1 == x2 + case instance.Of(class.Integer, x1) && instance.Of(class.Float, x2): + ret = float64(x1.(instance.Integer)) == float64(x2.(instance.Float)) + case instance.Of(class.Float, x1) && instance.Of(class.Integer, x2): + ret = float64(x1.(instance.Float)) == float64(x2.(instance.Integer)) + case instance.Of(class.Float, x1) && instance.Of(class.Float, x2): + ret = x1 == x2 + } + if ret { + return T, nil + } + return Nil, nil +} + +// NotEqualNumber returns t if x1 and x2 have mathematically distinct values; +// otherwise, returns nil. An error shall be signaled if either x1 or x2 is not +// a number (error-id. domain-error). +func NotEqualNumber(_, _ *environment.Environment, x1, x2 ilos.Instance) (ilos.Instance, ilos.Instance) { + ret, err := EqualNumber(nil, nil, x1, x2) + if err != nil { + return ret, err + } + ret, err = Not(nil, nil, ret) + return ret, err +} From 33d83cfbc34c689d79ee6d61811967af2ccdbfb8 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Fri, 11 Aug 2017 21:37:05 +0900 Subject: [PATCH 132/228] Replace to Nil --- runtime/block_test.go | 2 +- runtime/catch_test.go | 2 +- runtime/eval.go | 6 +++--- runtime/function.go | 2 +- runtime/logical.go | 4 +--- runtime/null.go | 4 +--- runtime/util.go | 2 +- 7 files changed, 9 insertions(+), 13 deletions(-) diff --git a/runtime/block_test.go b/runtime/block_test.go index fe445a7..5cdb3b8 100644 --- a/runtime/block_test.go +++ b/runtime/block_test.go @@ -43,7 +43,7 @@ func TestBlock(t *testing.T) { { name: "case3", arguments: arguments{local, global, readFromString("(block 'foo)")}, - want: readFromString("nil"), + want: Nil, wantErr: false, }, } diff --git a/runtime/catch_test.go b/runtime/catch_test.go index de9ec9c..1534770 100644 --- a/runtime/catch_test.go +++ b/runtime/catch_test.go @@ -43,7 +43,7 @@ func TestCatch(t *testing.T) { { name: "case3", arguments: arguments{local, global, readFromString("(catch 'foo)")}, - want: readFromString("nil"), + want: Nil, wantErr: false, }, } diff --git a/runtime/eval.go b/runtime/eval.go index cd7e189..f73d061 100644 --- a/runtime/eval.go +++ b/runtime/eval.go @@ -13,7 +13,7 @@ import ( func evalArguments(local, global *environment.Environment, arguments ilos.Instance) (ilos.Instance, ilos.Instance) { // if arguments ends here - if instance.Of(class.Null, arguments) { + if arguments == Nil { return Nil, nil } // arguments must be a instance of list and ends with nil @@ -143,7 +143,7 @@ func evalFunction(local, global *environment.Environment, car, cdr ilos.Instance func evalCons(local, global *environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { // obj, function call form, must be a instance of Cons, NOT Null, and ends with nil - if !isProperList(obj) || instance.Of(class.Null, obj) { + if !isProperList(obj) || obj == Nil { return nil, instance.New(class.ParseError, map[string]ilos.Instance{ "STRING": obj, "EXPECTED-CLASS": class.Cons, @@ -190,7 +190,7 @@ func evalVariable(local, global *environment.Environment, obj ilos.Instance) (il // Eval evaluates any classs func Eval(local, global *environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { - if instance.Of(class.Null, obj) { + if obj == Nil { return Nil, nil } if instance.Of(class.Symbol, obj) { diff --git a/runtime/function.go b/runtime/function.go index 22588d4..0d23be5 100644 --- a/runtime/function.go +++ b/runtime/function.go @@ -68,7 +68,7 @@ func checkLambdaList(lambdaList ilos.Instance) ilos.Instance { } cdr = cddr } - if !ok && instance.Of(class.Null, cdr) { + if !ok && cdr == Nil { ok = true } if !ok { diff --git a/runtime/logical.go b/runtime/logical.go index af14825..a4cd572 100644 --- a/runtime/logical.go +++ b/runtime/logical.go @@ -7,14 +7,12 @@ package runtime import ( "github.com/ta2gch/iris/runtime/environment" "github.com/ta2gch/iris/runtime/ilos" - "github.com/ta2gch/iris/runtime/ilos/class" - "github.com/ta2gch/iris/runtime/ilos/instance" ) // Not is the logical “not” (or “¬”). It returns t if obj is nil // and nil otherwise. obj may be any ISLISP object. func Not(_, _ *environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { - if instance.Of(class.Null, obj) { + if obj == Nil { return T, nil } return Nil, nil diff --git a/runtime/null.go b/runtime/null.go index aed970f..31ee297 100644 --- a/runtime/null.go +++ b/runtime/null.go @@ -7,13 +7,11 @@ package runtime import ( "github.com/ta2gch/iris/runtime/environment" "github.com/ta2gch/iris/runtime/ilos" - "github.com/ta2gch/iris/runtime/ilos/class" - "github.com/ta2gch/iris/runtime/ilos/instance" ) // Null returns t if obj is nil; otherwise, returns nil obj may be any ISLISP object. func Null(_, _ *environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { - if instance.Of(class.Null, obj) { + if obj == Nil { return T, nil } return Nil, nil diff --git a/runtime/util.go b/runtime/util.go index b7ac646..5132aef 100644 --- a/runtime/util.go +++ b/runtime/util.go @@ -20,7 +20,7 @@ func isProperList(i ilos.Instance) bool { if instance.Of(class.Cons, i) { return isProperList(instance.UnsafeCdr(i)) } - if instance.Of(class.Null, i) { + if i == Nil { return true } return false From 70f6b37a4e33fc4a6880bc672b441ff5dbbb085b Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Fri, 11 Aug 2017 21:45:44 +0900 Subject: [PATCH 133/228] Remove unused functions --- runtime/ilos/ilos.go | 28 ---------------------------- 1 file changed, 28 deletions(-) diff --git a/runtime/ilos/ilos.go b/runtime/ilos/ilos.go index 843145c..238be51 100644 --- a/runtime/ilos/ilos.go +++ b/runtime/ilos/ilos.go @@ -19,31 +19,3 @@ type Instance interface { SetSlotValue(Instance, Instance, Class) bool String() string } - -func ChildOf(c, p Class) bool { - var sub func(c, p Class) bool - sub = func(c, p Class) bool { - if c == p { - return true - } - for _, d := range c.Parents() { - if sub(d, p) { - return true - } - } - return false - } - for _, d := range c.Parents() { - if sub(d, p) { - return true - } - } - return false -} - -func InstanceOf(i Instance, p Class) bool { - if i.Class() == p { - return true - } - return ChildOf(i.Class(), p) -} From 3d538e0c841f9f439f075e1f5abc4cc71a2af297 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Fri, 11 Aug 2017 22:02:12 +0900 Subject: [PATCH 134/228] Remove WrongNumberOfArguments --- runtime/ilos/class/class.go | 1 - runtime/ilos/instance/function.go | 5 +---- runtime/namedfunc.go | 5 +---- 3 files changed, 2 insertions(+), 9 deletions(-) diff --git a/runtime/ilos/class/class.go b/runtime/ilos/class/class.go index 7fd4e5d..f4c5421 100644 --- a/runtime/ilos/class/class.go +++ b/runtime/ilos/class/class.go @@ -69,7 +69,6 @@ var StandardObject = &builtinclass{[]ilos.Class{Object}, []string{}, ""} // Implementation defined -var WrongNumberOfArguments = &builtinclass{[]ilos.Class{Error}, []string{"FORM", "ARGUMENTS"}, ""} var Escape = &builtinclass{[]ilos.Class{Object}, []string{"TAG"}, ""} var CatchTag = &builtinclass{[]ilos.Class{Escape}, []string{"OBJECT"}, ""} var TagbodyTag = &builtinclass{[]ilos.Class{Escape}, []string{}, ""} diff --git a/runtime/ilos/instance/function.go b/runtime/ilos/instance/function.go index e252dca..d16d353 100644 --- a/runtime/ilos/instance/function.go +++ b/runtime/ilos/instance/function.go @@ -50,10 +50,7 @@ func (f Function) Apply(local, global *environment.Environment, arguments ilos.I cdr = cddr } if ft.NumIn() != len(argv) && (!ft.IsVariadic() || ft.NumIn()-2 >= len(argv)) { - return nil, New(class.WrongNumberOfArguments, map[string]ilos.Instance{ - "FORM": f.name, - "ARGUMENTS": arguments, - }) + return nil, New(class.ProgramError) } rets := fv.Call(argv) a, _ := rets[0].Interface().(ilos.Instance) diff --git a/runtime/namedfunc.go b/runtime/namedfunc.go index 39d1e06..032d621 100644 --- a/runtime/namedfunc.go +++ b/runtime/namedfunc.go @@ -38,10 +38,7 @@ func newNamedFunction(local, global *environment.Environment, functionName, lamb for i := len(arguments) - 1; i >= 0; i-- { v = instance.New(class.Cons, arguments[i], v) } - return nil, instance.New(class.WrongNumberOfArguments, map[string]ilos.Instance{ - "FORM": functionName, - "ARGUMENTS": v, - }) + return nil, instance.New(class.ProgramError) } for idx := range parameters { key := parameters[idx] From f1cef74a69e62a29273526747de5481388f9bf71 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Fri, 11 Aug 2017 22:17:27 +0900 Subject: [PATCH 135/228] Added comments of reason to use Unsafe* --- runtime/function.go | 50 +++++++++++++++++++++---------- runtime/ilos/instance/function.go | 4 +-- runtime/ilos/instance/list.go | 4 +-- runtime/namedfunc.go | 4 +-- runtime/util.go | 2 +- 5 files changed, 41 insertions(+), 23 deletions(-) diff --git a/runtime/function.go b/runtime/function.go index 0d23be5..e064b6c 100644 --- a/runtime/function.go +++ b/runtime/function.go @@ -134,22 +134,31 @@ func Lambda(local, global *environment.Environment, lambdaList ilos.Instance, fo func Labels(local, global *environment.Environment, functions ilos.Instance, bodyForm ...ilos.Instance) (ilos.Instance, ilos.Instance) { cdr := functions for instance.Of(class.Cons, cdr) { - cadr := instance.UnsafeCar(cdr) - functionName := instance.UnsafeCar(cadr) - lambdaList := instance.UnsafeCar(instance.UnsafeCdr(cadr)) + cadr := instance.UnsafeCar(cdr) // Checked at the top of this loop + if !instance.Of(class.Cons, cadr) { // #1 + return nil, instance.New(class.ProgramError) + } + functionName := instance.UnsafeCar(cadr) // Checked at #1 + cdadr := instance.UnsafeCdr(cadr) + if !instance.Of(class.Cons, cdadr) { // #2 + return nil, instance.New(class.ProgramError) + } + lambdaList := instance.UnsafeCar(cdadr) // Checked at #2 if err := checkLambdaList(lambdaList); err != nil { return nil, err } - - cddadr := instance.UnsafeCdr(instance.UnsafeCdr(cadr)) + cddadr := instance.UnsafeCdr(cdadr) // Checked at #2 + if !isProperList(cddadr) { + return nil, instance.New(class.ProgramError) + } form := []ilos.Instance{} for instance.Of(class.Cons, cddadr) { - caddadr := instance.UnsafeCar(cddadr) + caddadr := instance.UnsafeCar(cddadr) // Checked at the top of this loop form = append(form, caddadr) - cddadr = instance.UnsafeCdr(cddadr) + cddadr = instance.UnsafeCdr(cddadr) // Checked at the top of this loop } local.Function.Define(functionName, newNamedFunction(local, global, functionName, lambdaList, form...)) - cdr = instance.UnsafeCdr(cdr) + cdr = instance.UnsafeCdr(cdr) // Checked at #1 } ret := Nil var err ilos.Instance @@ -176,22 +185,31 @@ func Flet(local, global *environment.Environment, functions ilos.Instance, bodyF env.Macro = append(local.Macro, env.Macro...) env.DynamicVariable = append(local.DynamicVariable, env.DynamicVariable...) for instance.Of(class.Cons, cdr) { - cadr := instance.UnsafeCar(cdr) - functionName := instance.UnsafeCar(cadr) - lambdaList := instance.UnsafeCar(instance.UnsafeCdr(cadr)) + cadr := instance.UnsafeCar(cdr) // Checked at the top of this loop + if !instance.Of(class.Cons, cadr) { // #1 + return nil, instance.New(class.ProgramError) + } + functionName := instance.UnsafeCar(cadr) // Checked at #1 + cdadr := instance.UnsafeCdr(cadr) + if !instance.Of(class.Cons, cdadr) { // #2 + return nil, instance.New(class.ProgramError) + } + lambdaList := instance.UnsafeCar(cdadr) // Checked at #2 if err := checkLambdaList(lambdaList); err != nil { return nil, err } - - cddadr := instance.UnsafeCdr(instance.UnsafeCdr(cadr)) + cddadr := instance.UnsafeCdr(cdadr) // Checked at #2 + if !isProperList(cddadr) { + return nil, instance.New(class.ProgramError) + } form := []ilos.Instance{} for instance.Of(class.Cons, cddadr) { - caddadr := instance.UnsafeCar(cddadr) + caddadr := instance.UnsafeCar(cddadr) // Checked at the top of this loop form = append(form, caddadr) - cddadr = instance.UnsafeCdr(cddadr) + cddadr = instance.UnsafeCdr(cddadr) // Checked at the top of this loop } env.Function.Define(functionName, newNamedFunction(local, global, functionName, lambdaList, form...)) - cdr = instance.UnsafeCdr(cdr) + cdr = instance.UnsafeCdr(cdr) // Checked at #1 } ret := Nil var err ilos.Instance diff --git a/runtime/ilos/instance/function.go b/runtime/ilos/instance/function.go index d16d353..f4d6077 100644 --- a/runtime/ilos/instance/function.go +++ b/runtime/ilos/instance/function.go @@ -44,8 +44,8 @@ func (f Function) Apply(local, global *environment.Environment, arguments ilos.I cdr := arguments argv := []reflect.Value{reflect.ValueOf(local), reflect.ValueOf(global)} for Of(class.Cons, cdr) { - cadr := UnsafeCar(cdr) - cddr := UnsafeCdr(cdr) + cadr := UnsafeCar(cdr) // Checked at the top of this loop + cddr := UnsafeCdr(cdr) // Checked at the top of this loop argv = append(argv, reflect.ValueOf(cadr)) cdr = cddr } diff --git a/runtime/ilos/instance/list.go b/runtime/ilos/instance/list.go index 40ece6b..55c7479 100644 --- a/runtime/ilos/instance/list.go +++ b/runtime/ilos/instance/list.go @@ -54,8 +54,8 @@ func (i *Cons) String() string { str := "(" + fmt.Sprint(i.car) cdr := i.cdr for Of(class.Cons, cdr) { - str += fmt.Sprintf(" %v", UnsafeCar(cdr)) - cdr = UnsafeCdr(cdr) + str += fmt.Sprintf(" %v", UnsafeCar(cdr)) // Checked at the top of this loop + cdr = UnsafeCdr(cdr) // Checked at the top of this loop } if Of(class.Null, cdr) { str += ")" diff --git a/runtime/namedfunc.go b/runtime/namedfunc.go index 032d621..38c5dfd 100644 --- a/runtime/namedfunc.go +++ b/runtime/namedfunc.go @@ -17,12 +17,12 @@ func newNamedFunction(local, global *environment.Environment, functionName, lamb parameters := []ilos.Instance{} variadic := false for instance.Of(class.Cons, cdr) { - cadr := instance.UnsafeCar(cdr) + cadr := instance.UnsafeCar(cdr) // Checked at the top of this loop if cadr == instance.New(class.Symbol, ":REST") || cadr == instance.New(class.Symbol, "&REST") { variadic = true } parameters = append(parameters, cadr) - cdr = instance.UnsafeCdr(cdr) + cdr = instance.UnsafeCdr(cdr) // Checked at the top of this loop } return instance.New(class.Function, functionName, func(local, global *environment.Environment, arguments ...ilos.Instance) (ilos.Instance, ilos.Instance) { local.BlockTag = append(lexical.BlockTag, local.BlockTag...) diff --git a/runtime/util.go b/runtime/util.go index 5132aef..fd0fb8a 100644 --- a/runtime/util.go +++ b/runtime/util.go @@ -18,7 +18,7 @@ import ( func isProperList(i ilos.Instance) bool { if instance.Of(class.Cons, i) { - return isProperList(instance.UnsafeCdr(i)) + return isProperList(instance.UnsafeCdr(i)) // Checked at the top of this statements } if i == Nil { return true From 447c85c54c9c09f339d9e3a15d63a06987c495aa Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Fri, 11 Aug 2017 22:33:20 +0900 Subject: [PATCH 136/228] Renamed filenames --- runtime/block.go | 79 ------- runtime/block_test.go | 63 ------ runtime/{boolean.go => boolean_values.go} | 0 runtime/catch.go | 68 ------ runtime/catch_test.go | 63 ------ runtime/{quote.go => constants.go} | 0 runtime/{function.go => functions.go} | 0 .../{logical.go => logical_connectives.go} | 0 runtime/non-local_exits.go | 206 ++++++++++++++++++ runtime/{null.go => null_class.go} | 0 runtime/{number.go => number_class.go} | 0 runtime/tagbody.go | 64 ------ runtime/tagbody_test.go | 59 ----- 13 files changed, 206 insertions(+), 396 deletions(-) delete mode 100644 runtime/block.go delete mode 100644 runtime/block_test.go rename runtime/{boolean.go => boolean_values.go} (100%) delete mode 100644 runtime/catch.go delete mode 100644 runtime/catch_test.go rename runtime/{quote.go => constants.go} (100%) rename runtime/{function.go => functions.go} (100%) rename runtime/{logical.go => logical_connectives.go} (100%) create mode 100644 runtime/non-local_exits.go rename runtime/{null.go => null_class.go} (100%) rename runtime/{number.go => number_class.go} (100%) delete mode 100644 runtime/tagbody.go delete mode 100644 runtime/tagbody_test.go diff --git a/runtime/block.go b/runtime/block.go deleted file mode 100644 index feb5b05..0000000 --- a/runtime/block.go +++ /dev/null @@ -1,79 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at http://mozilla.org/MPL/2.0/. - -package runtime - -import ( - "github.com/ta2gch/iris/runtime/environment" - "github.com/ta2gch/iris/runtime/ilos" - "github.com/ta2gch/iris/runtime/ilos/class" - "github.com/ta2gch/iris/runtime/ilos/instance" -) - -// DEFINISION: -// The block special form executes each form sequentially from left to right. -// If the last form exits normally, whatever it returns is returned by the block form. -// The name in a block form is not evaluated; it must be an identifier. The scope of name -// is the body form only a return-from textually contained in some form can exit the block. -// The extend of name is dynamic. (islisp-v23.pdf, 43-44) -// NOTE: -// According to// This, the scope of name is dynamic. I guess it should be a static. -func block(local, global *environment.Environment, tag ilos.Instance, body ...ilos.Instance) (ilos.Instance, ilos.Instance) { - var err ilos.Instance - tag, err = Eval(local, global, tag) // Checked at the top of// This function - if err != nil { - return nil, err - } - if instance.Of(class.Number, tag) || instance.Of(class.Character, tag) { - return nil, instance.New(class.DomainError, map[string]ilos.Instance{ - "OBJECT": tag, - "EXPECTED-CLASS": class.Object, - }) - } - local.BlockTag.Define(tag, nil) - var fail ilos.Instance - sucess := Nil - for _, cadr := range body { - sucess, fail = Eval(local, global, cadr) - if fail != nil { - if instance.Of(class.BlockTag, fail) { - tag1, _ := fail.GetSlotValue(instance.New(class.Symbol, "TAG"), class.Escape) // Checked at the head of// This condition - if tag == tag1 { - obj, _ := fail.GetSlotValue(instance.New(class.Symbol, "OBJECT"), class.BlockTag) // Checked at the head of// This condition - return obj, nil - } - } - return nil, fail - } - } - return sucess, nil -} - -func return_from(local, global *environment.Environment, tag, object ilos.Instance) (ilos.Instance, ilos.Instance) { - var err ilos.Instance - tag, err = Eval(local, global, tag) - if err != nil { - return nil, err - } - if instance.Of(class.Number, tag) || instance.Of(class.Character, tag) { - return nil, instance.New(class.DomainError, map[string]ilos.Instance{ - "OBJECT": tag, - "EXPECTED-CLASS": class.Object, - }) - } - object, err = Eval(local, global, object) - if err != nil { - return nil, err - } - if _, ok := local.BlockTag.Get(tag); !ok { - return nil, instance.New(class.SimpleError, map[string]ilos.Instance{ - "FORMAT-STRING": instance.New(class.String, "%v is not defined as the tag"), - "FORMAT-ARGUMENTS": tag, - }) - } - return nil, instance.New(class.BlockTag, map[string]ilos.Instance{ - "TAG": tag, - "OBJECT": object, - }) -} diff --git a/runtime/block_test.go b/runtime/block_test.go deleted file mode 100644 index 5cdb3b8..0000000 --- a/runtime/block_test.go +++ /dev/null @@ -1,63 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at http://mozilla.org/MPL/2.0/. - -package runtime - -import ( - "reflect" - "testing" - - "github.com/ta2gch/iris/runtime/environment" - "github.com/ta2gch/iris/runtime/ilos" -) - -func TestBlock(t *testing.T) { - local, global := environment.New(), environment.TopLevel - defspecial("BLOCK", block) - defspecial("RETURN-FROM", return_from) - defspecial("QUOTE", quote) - type arguments struct { - local *environment.Environment - global *environment.Environment - obj ilos.Instance - } - tests := []struct { - name string - arguments arguments - want ilos.Instance - wantErr bool - }{ - { - name: "case1", - arguments: arguments{local, global, readFromString("(block 'foo 1 (return-from 'foo 1))")}, - want: readFromString("1"), - wantErr: false, - }, - { - name: "case2", - arguments: arguments{local, global, readFromString("(block)")}, - want: nil, - wantErr: true, - }, - { - name: "case3", - arguments: arguments{local, global, readFromString("(block 'foo)")}, - want: Nil, - wantErr: false, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, err := Eval(tt.arguments.local, tt.arguments.global, tt.arguments.obj) - if (err != nil) != tt.wantErr { - t.Errorf("Eval() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !reflect.DeepEqual(got, tt.want) { - t.Errorf("Eval() = %v, want %v", got, tt.want) - t.Errorf("Eval() = %v, want %v", got, tt.want) - } - }) - } -} diff --git a/runtime/boolean.go b/runtime/boolean_values.go similarity index 100% rename from runtime/boolean.go rename to runtime/boolean_values.go diff --git a/runtime/catch.go b/runtime/catch.go deleted file mode 100644 index d6f1ec7..0000000 --- a/runtime/catch.go +++ /dev/null @@ -1,68 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at http://mozilla.org/MPL/2.0/. - -package runtime - -import ( - "github.com/ta2gch/iris/runtime/environment" - "github.com/ta2gch/iris/runtime/ilos" - "github.com/ta2gch/iris/runtime/ilos/class" - "github.com/ta2gch/iris/runtime/ilos/instance" -) - -func catch(local, global *environment.Environment, tag ilos.Instance, body ...ilos.Instance) (ilos.Instance, ilos.Instance) { - var err ilos.Instance - tag, err = Eval(local, global, tag) - if err != nil { - return nil, err - } - if instance.Of(class.Number, tag) || instance.Of(class.Character, tag) { - return nil, instance.New(class.DomainError, tag, class.Object) - } - local.CatchTag.Define(tag, nil) - var fail ilos.Instance - sucess := Nil - for _, cadr := range body { - sucess, fail = Eval(local, global, cadr) - if fail != nil { - if instance.Of(class.CatchTag, fail) { - tag1, _ := fail.GetSlotValue(instance.New(class.Symbol, "TAG"), class.Escape) // Checked at the head of// This condition - if tag == tag1 { - obj, _ := fail.GetSlotValue(instance.New(class.Symbol, "OBJECT"), class.CatchTag) // Checked at the head of// This condition - return obj, nil - } - } - return nil, fail - } - } - return sucess, nil -} - -func throw(local, global *environment.Environment, tag, object ilos.Instance) (ilos.Instance, ilos.Instance) { - var err ilos.Instance - tag, err = Eval(local, global, tag) - if err != nil { - return nil, err - } - if instance.Of(class.Number, tag) || instance.Of(class.Character, tag) { - return nil, instance.New(class.DomainError, map[string]ilos.Instance{ - "OBJECT": tag, - "EXPECTED-CLASS": class.Object, - }) - } - object, err = Eval(local, global, object) - if err != nil { - return nil, err - } - if _, ok := local.CatchTag.Get(tag); !ok { - return nil, instance.New(class.SimpleError, map[string]ilos.Instance{ - "FORMAT-STRING": instance.New(class.String, "%v is not defined as the tag"), - "FORMAT-ARGUMENTS": tag, - }) - } - return nil, instance.New(class.CatchTag, map[string]ilos.Instance{ - "TAG": tag, - "OBJECT": object, - }) -} diff --git a/runtime/catch_test.go b/runtime/catch_test.go deleted file mode 100644 index 1534770..0000000 --- a/runtime/catch_test.go +++ /dev/null @@ -1,63 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at http://mozilla.org/MPL/2.0/. - -package runtime - -import ( - "reflect" - "testing" - - "github.com/ta2gch/iris/runtime/environment" - "github.com/ta2gch/iris/runtime/ilos" -) - -func TestCatch(t *testing.T) { - local, global := environment.New(), environment.TopLevel - defspecial("CATCH", catch) - defspecial("THROW", throw) - defspecial("QUOTE", quote) - type arguments struct { - local *environment.Environment - global *environment.Environment - obj ilos.Instance - } - tests := []struct { - name string - arguments arguments - want ilos.Instance - wantErr bool - }{ - { - name: "case1", - arguments: arguments{local, global, readFromString("(catch 'foo 1 (throw 'foo 1))")}, - want: readFromString("1"), - wantErr: false, - }, - { - name: "case2", - arguments: arguments{local, global, readFromString("(catch)")}, - want: nil, - wantErr: true, - }, - { - name: "case3", - arguments: arguments{local, global, readFromString("(catch 'foo)")}, - want: Nil, - wantErr: false, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, err := Eval(tt.arguments.local, tt.arguments.global, tt.arguments.obj) - if (err != nil) != tt.wantErr { - t.Errorf("Eval() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !reflect.DeepEqual(got, tt.want) { - t.Errorf("Eval() = %v, want %v", got, tt.want) - t.Errorf("Eval() = %v, want %v", got, tt.want) - } - }) - } -} diff --git a/runtime/quote.go b/runtime/constants.go similarity index 100% rename from runtime/quote.go rename to runtime/constants.go diff --git a/runtime/function.go b/runtime/functions.go similarity index 100% rename from runtime/function.go rename to runtime/functions.go diff --git a/runtime/logical.go b/runtime/logical_connectives.go similarity index 100% rename from runtime/logical.go rename to runtime/logical_connectives.go diff --git a/runtime/non-local_exits.go b/runtime/non-local_exits.go new file mode 100644 index 0000000..29d481c --- /dev/null +++ b/runtime/non-local_exits.go @@ -0,0 +1,206 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package runtime + +import ( + "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/ilos" + "github.com/ta2gch/iris/runtime/ilos/class" + "github.com/ta2gch/iris/runtime/ilos/instance" +) + +/* +ISLISP defines three ways in which to perform non-local exits: + Destination Kind Established by Invoked by Operation Performed + block name block return-from lexical exit + tagbody tag tagbody go lexical transfer of control + catch tag atch throw dynamic exit + +A non-local exit, is an operation that forces transfer of control and possibly +data from an invoking special form to a previously established point in a program, +called the destination of the exit. + +A lexical exit is a non-local exit from a return-from form to a block form +which contains it both lexically and dynamically, forcing the block to return +an object specified in the return-from form. + +A dynamic exit is a non-local exit from a throw form to a catch form +which contains it dynamically (but not necessarily lexically), +forcing the catch to return an object specified in the throw form. + +A lexical transfer of control is a non-local exit from a go form to a tagged point +in a tagbody form which contains it both lexically and dynamically. + +When a non-local exit is initiated, any potential destination that was established +more recently than the destination to which control is being transferred +is immediately considered invalid. +*/ + +func Block(local, global *environment.Environment, tag ilos.Instance, body ...ilos.Instance) (ilos.Instance, ilos.Instance) { + var err ilos.Instance + tag, err = Eval(local, global, tag) // Checked at the top of// This function + if err != nil { + return nil, err + } + if instance.Of(class.Number, tag) || instance.Of(class.Character, tag) { + return nil, instance.New(class.DomainError, map[string]ilos.Instance{ + "OBJECT": tag, + "EXPECTED-CLASS": class.Object, + }) + } + local.BlockTag.Define(tag, nil) + var fail ilos.Instance + sucess := Nil + for _, cadr := range body { + sucess, fail = Eval(local, global, cadr) + if fail != nil { + if instance.Of(class.BlockTag, fail) { + tag1, _ := fail.GetSlotValue(instance.New(class.Symbol, "TAG"), class.Escape) // Checked at the head of// This condition + if tag == tag1 { + obj, _ := fail.GetSlotValue(instance.New(class.Symbol, "OBJECT"), class.BlockTag) // Checked at the head of// This condition + return obj, nil + } + } + return nil, fail + } + } + return sucess, nil +} + +func ReturnFrom(local, global *environment.Environment, tag, object ilos.Instance) (ilos.Instance, ilos.Instance) { + var err ilos.Instance + tag, err = Eval(local, global, tag) + if err != nil { + return nil, err + } + if instance.Of(class.Number, tag) || instance.Of(class.Character, tag) { + return nil, instance.New(class.DomainError, map[string]ilos.Instance{ + "OBJECT": tag, + "EXPECTED-CLASS": class.Object, + }) + } + object, err = Eval(local, global, object) + if err != nil { + return nil, err + } + if _, ok := local.BlockTag.Get(tag); !ok { + return nil, instance.New(class.SimpleError, map[string]ilos.Instance{ + "FORMAT-STRING": instance.New(class.String, "%v is not defined as the tag"), + "FORMAT-ARGUMENTS": tag, + }) + } + return nil, instance.New(class.BlockTag, map[string]ilos.Instance{ + "TAG": tag, + "OBJECT": object, + }) +} + +func Catch(local, global *environment.Environment, tag ilos.Instance, body ...ilos.Instance) (ilos.Instance, ilos.Instance) { + var err ilos.Instance + tag, err = Eval(local, global, tag) + if err != nil { + return nil, err + } + if instance.Of(class.Number, tag) || instance.Of(class.Character, tag) { + return nil, instance.New(class.DomainError, tag, class.Object) + } + local.CatchTag.Define(tag, nil) + var fail ilos.Instance + sucess := Nil + for _, cadr := range body { + sucess, fail = Eval(local, global, cadr) + if fail != nil { + if instance.Of(class.CatchTag, fail) { + tag1, _ := fail.GetSlotValue(instance.New(class.Symbol, "TAG"), class.Escape) // Checked at the head of// This condition + if tag == tag1 { + obj, _ := fail.GetSlotValue(instance.New(class.Symbol, "OBJECT"), class.CatchTag) // Checked at the head of// This condition + return obj, nil + } + } + return nil, fail + } + } + return sucess, nil +} + +func Throw(local, global *environment.Environment, tag, object ilos.Instance) (ilos.Instance, ilos.Instance) { + var err ilos.Instance + tag, err = Eval(local, global, tag) + if err != nil { + return nil, err + } + if instance.Of(class.Number, tag) || instance.Of(class.Character, tag) { + return nil, instance.New(class.DomainError, map[string]ilos.Instance{ + "OBJECT": tag, + "EXPECTED-CLASS": class.Object, + }) + } + object, err = Eval(local, global, object) + if err != nil { + return nil, err + } + if _, ok := local.CatchTag.Get(tag); !ok { + return nil, instance.New(class.SimpleError, map[string]ilos.Instance{ + "FORMAT-STRING": instance.New(class.String, "%v is not defined as the tag"), + "FORMAT-ARGUMENTS": tag, + }) + } + return nil, instance.New(class.CatchTag, map[string]ilos.Instance{ + "TAG": tag, + "OBJECT": object, + }) +} + +func Tagbody(local, global *environment.Environment, body ...ilos.Instance) (ilos.Instance, ilos.Instance) { + for idx, cadr := range body { + cddr := instance.New(class.GeneralVector, body[idx+1:]) + if !instance.Of(class.Cons, cadr) { + local.TagbodyTag.Define(cadr, cddr) + } + } + for _, cadr := range body { + if instance.Of(class.Cons, cadr) { + _, fail := Eval(local, global, cadr) + if fail != nil { + TAG: + if instance.Of(class.TagbodyTag, fail) { + tag, _ := fail.GetSlotValue(instance.New(class.Symbol, "TAG"), class.Escape) // Checked at the top of// This loop + found := false + for _, tag1 := range body { + if tag == tag1 { + found = true + break + } + } + if found { + forms, _ := local.TagbodyTag.Get(tag) // Checked in the function, tagbodyGo + for _, form := range forms.(instance.GeneralVector) { + if instance.Of(class.Cons, form) { + _, fail = Eval(local, global, form) + if fail != nil { + goto TAG + } + } + } + break + } + + } + return nil, fail + } + } + } + return Nil, nil +} + +func Go(local, global *environment.Environment, tag ilos.Instance) (ilos.Instance, ilos.Instance) { + if _, ok := local.TagbodyTag.Get(tag); !ok { + return nil, instance.New(class.SimpleError, map[string]ilos.Instance{ + "FORMAT-STRING": instance.New(class.String, "%v is not defined as the tag"), + "FORMAT-ARGUMENTS": tag, + }) + } + return nil, instance.New(class.TagbodyTag, map[string]ilos.Instance{"TAG": tag}) +} diff --git a/runtime/null.go b/runtime/null_class.go similarity index 100% rename from runtime/null.go rename to runtime/null_class.go diff --git a/runtime/number.go b/runtime/number_class.go similarity index 100% rename from runtime/number.go rename to runtime/number_class.go diff --git a/runtime/tagbody.go b/runtime/tagbody.go deleted file mode 100644 index 11d7a0e..0000000 --- a/runtime/tagbody.go +++ /dev/null @@ -1,64 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at http://mozilla.org/MPL/2.0/. - -package runtime - -import ( - "github.com/ta2gch/iris/runtime/environment" - "github.com/ta2gch/iris/runtime/ilos" - "github.com/ta2gch/iris/runtime/ilos/class" - "github.com/ta2gch/iris/runtime/ilos/instance" -) - -func tagbody(local, global *environment.Environment, body ...ilos.Instance) (ilos.Instance, ilos.Instance) { - for idx, cadr := range body { - cddr := instance.New(class.GeneralVector, body[idx+1:]) - if !instance.Of(class.Cons, cadr) { - local.TagbodyTag.Define(cadr, cddr) - } - } - for _, cadr := range body { - if instance.Of(class.Cons, cadr) { - _, fail := Eval(local, global, cadr) - if fail != nil { - TAG: - if instance.Of(class.TagbodyTag, fail) { - tag, _ := fail.GetSlotValue(instance.New(class.Symbol, "TAG"), class.Escape) // Checked at the top of// This loop - found := false - for _, tag1 := range body { - if tag == tag1 { - found = true - break - } - } - if found { - forms, _ := local.TagbodyTag.Get(tag) // Checked in the function, tagbodyGo - for _, form := range forms.(instance.GeneralVector) { - if instance.Of(class.Cons, form) { - _, fail = Eval(local, global, form) - if fail != nil { - goto TAG - } - } - } - break - } - - } - return nil, fail - } - } - } - return Nil, nil -} - -func tagbodyGo(local, global *environment.Environment, tag ilos.Instance) (ilos.Instance, ilos.Instance) { - if _, ok := local.TagbodyTag.Get(tag); !ok { - return nil, instance.New(class.SimpleError, map[string]ilos.Instance{ - "FORMAT-STRING": instance.New(class.String, "%v is not defined as the tag"), - "FORMAT-ARGUMENTS": tag, - }) - } - return nil, instance.New(class.TagbodyTag, map[string]ilos.Instance{"TAG": tag}) -} diff --git a/runtime/tagbody_test.go b/runtime/tagbody_test.go deleted file mode 100644 index b866089..0000000 --- a/runtime/tagbody_test.go +++ /dev/null @@ -1,59 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at http://mozilla.org/MPL/2.0/. - -package runtime - -import ( - "reflect" - "testing" - - "github.com/ta2gch/iris/runtime/environment" - "github.com/ta2gch/iris/runtime/ilos" -) - -func TestTagbody(t *testing.T) { - local, global := environment.New(), environment.TopLevel - defspecial("TAGBODY", tagbody) - defspecial("GO", tagbodyGo) - defspecial("CATCH", catch) - defspecial("THROW", throw) - defspecial("QUOTE", quote) - type arguments struct { - local *environment.Environment - global *environment.Environment - obj ilos.Instance - } - tests := []struct { - name string - arguments arguments - want ilos.Instance - wantErr bool - }{ - { - name: "tagbody & go", - arguments: arguments{local, global, readFromString("(catch 'foo (tagbody (go bar) (throw 'foo 1) bar))")}, - want: Nil, - wantErr: false, - }, - { - name: "nested tagbody & go", - arguments: arguments{local, global, readFromString("(catch 'foo (tagbody (tagbody (go bar) (throw 'foo 1) bar (go foobar)) foobar))")}, - want: Nil, - wantErr: false, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, err := Eval(tt.arguments.local, tt.arguments.global, tt.arguments.obj) - if (err != nil) != tt.wantErr { - t.Errorf("Eval() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !reflect.DeepEqual(got, tt.want) { - t.Errorf("Eval() = %v, want %v", got, tt.want) - t.Errorf("Eval() = %v, want %v", got, tt.want) - } - }) - } -} From 1f0d0f95d95b19bbfb9680b6d85e3f00a978ae7c Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Fri, 11 Aug 2017 23:47:51 +0900 Subject: [PATCH 137/228] Added jekyll site --- docs/_config.yml | 8 ++ docs/_layouts/default.html | 12 +++ docs/_layouts/post.html | 9 +++ docs/_posts/2017-08-11-welcome-to-jedie.md | 22 ++++++ docs/css/site.css | 91 ++++++++++++++++++++++ docs/index.html | 60 +++----------- 6 files changed, 154 insertions(+), 48 deletions(-) create mode 100644 docs/_config.yml create mode 100644 docs/_layouts/default.html create mode 100644 docs/_layouts/post.html create mode 100644 docs/_posts/2017-08-11-welcome-to-jedie.md create mode 100644 docs/css/site.css diff --git a/docs/_config.yml b/docs/_config.yml new file mode 100644 index 0000000..9803faf --- /dev/null +++ b/docs/_config.yml @@ -0,0 +1,8 @@ +name: iris +description: iris is a interpreter of ISLisp on golang +gems: + - jemoji + - jekyll-mentions + - jekyll-redirect-from + - jekyll-sitemap + - jekyll-feed \ No newline at end of file diff --git a/docs/_layouts/default.html b/docs/_layouts/default.html new file mode 100644 index 0000000..9db1432 --- /dev/null +++ b/docs/_layouts/default.html @@ -0,0 +1,12 @@ + + + + + + {{ site.title }} + {% feed_meta %} + + +{{ content }} + + diff --git a/docs/_layouts/post.html b/docs/_layouts/post.html new file mode 100644 index 0000000..04e3586 --- /dev/null +++ b/docs/_layouts/post.html @@ -0,0 +1,9 @@ +--- +layout: default +--- +

{{ page.title }}

+

{{ page.date | date_to_string }}

+ +
+{{ content }} +
diff --git a/docs/_posts/2017-08-11-welcome-to-jedie.md b/docs/_posts/2017-08-11-welcome-to-jedie.md new file mode 100644 index 0000000..9c00af3 --- /dev/null +++ b/docs/_posts/2017-08-11-welcome-to-jedie.md @@ -0,0 +1,22 @@ +--- +layout: post +title: "Welcome to Jedie!" +date: 2013-11-22 21:42:47 +--- + +You'll find this post in your `_posts` directory - edit this post and re-build (or run with the `-w` switch) to see your changes! +To add new posts, simply add a file in the `_posts` directory that follows the convention: YYYY-MM-DD-name-of-post.ext. + +Jekyll also offers powerful support for code snippets: + + package main + + import "fmt" + + func main() { + fmt.Println("こんにちわ世界") + } + +Check out the [Jedie][jedie-gh] for more info. + +[jedie-gh]: https://github.com/mattn/jedie diff --git a/docs/css/site.css b/docs/css/site.css new file mode 100644 index 0000000..834cabe --- /dev/null +++ b/docs/css/site.css @@ -0,0 +1,91 @@ +body { + font-family: Sans; +} + +h1 { + color: darkgreen; +} + +.highlight { + background-color: #efefef; + padding: 7px 7px 7px 10px; + border: 1px solid #ddd; + -moz-box-shadow: 3px 3px rgba(0,0,0,0.1); + -webkit-box-shadow: 3px 3px rgba(0,0,0,0.1); + box-shadow: 3px 3px rgba(0,0,0,0.1); + margin: 20px 0 20px 0; + overflow: hidden; +} + +code { + font-family:'Bitstream Vera Sans Mono','Courier', monospace; +} + +.highlight .c { color: #586E75 } /* Comment */ +.highlight .err { color: #93A1A1 } /* Error */ +.highlight .g { color: #93A1A1 } /* Generic */ +.highlight .k { color: #859900 } /* Keyword */ +.highlight .l { color: #93A1A1 } /* Literal */ +.highlight .n { color: #93A1A1 } /* Name */ +.highlight .o { color: #859900 } /* Operator */ +.highlight .x { color: #CB4B16 } /* Other */ +.highlight .p { color: #93A1A1 } /* Punctuation */ +.highlight .cm { color: #586E75 } /* Comment.Multiline */ +.highlight .cp { color: #859900 } /* Comment.Preproc */ +.highlight .c1 { color: #586E75 } /* Comment.Single */ +.highlight .cs { color: #859900 } /* Comment.Special */ +.highlight .gd { color: #2AA198 } /* Generic.Deleted */ +.highlight .ge { color: #93A1A1; font-style: italic } /* Generic.Emph */ +.highlight .gr { color: #DC322F } /* Generic.Error */ +.highlight .gh { color: #CB4B16 } /* Generic.Heading */ +.highlight .gi { color: #859900 } /* Generic.Inserted */ +.highlight .go { color: #93A1A1 } /* Generic.Output */ +.highlight .gp { color: #93A1A1 } /* Generic.Prompt */ +.highlight .gs { color: #93A1A1; font-weight: bold } /* Generic.Strong */ +.highlight .gu { color: #CB4B16 } /* Generic.Subheading */ +.highlight .gt { color: #93A1A1 } /* Generic.Traceback */ +.highlight .kc { color: #CB4B16 } /* Keyword.Constant */ +.highlight .kd { color: #268BD2 } /* Keyword.Declaration */ +.highlight .kn { color: #859900 } /* Keyword.Namespace */ +.highlight .kp { color: #859900 } /* Keyword.Pseudo */ +.highlight .kr { color: #268BD2 } /* Keyword.Reserved */ +.highlight .kt { color: #DC322F } /* Keyword.Type */ +.highlight .ld { color: #93A1A1 } /* Literal.Date */ +.highlight .m { color: #2AA198 } /* Literal.Number */ +.highlight .s { color: #2AA198 } /* Literal.String */ +.highlight .na { color: #93A1A1 } /* Name.Attribute */ +.highlight .nb { color: #B58900 } /* Name.Builtin */ +.highlight .nc { color: #268BD2 } /* Name.Class */ +.highlight .no { color: #CB4B16 } /* Name.Constant */ +.highlight .nd { color: #268BD2 } /* Name.Decorator */ +.highlight .ni { color: #CB4B16 } /* Name.Entity */ +.highlight .ne { color: #CB4B16 } /* Name.Exception */ +.highlight .nf { color: #268BD2 } /* Name.Function */ +.highlight .nl { color: #93A1A1 } /* Name.Label */ +.highlight .nn { color: #93A1A1 } /* Name.Namespace */ +.highlight .nx { color: #555 } /* Name.Other */ +.highlight .py { color: #93A1A1 } /* Name.Property */ +.highlight .nt { color: #268BD2 } /* Name.Tag */ +.highlight .nv { color: #268BD2 } /* Name.Variable */ +.highlight .ow { color: #859900 } /* Operator.Word */ +.highlight .w { color: #93A1A1 } /* Text.Whitespace */ +.highlight .mf { color: #2AA198 } /* Literal.Number.Float */ +.highlight .mh { color: #2AA198 } /* Literal.Number.Hex */ +.highlight .mi { color: #2AA198 } /* Literal.Number.Integer */ +.highlight .mo { color: #2AA198 } /* Literal.Number.Oct */ +.highlight .sb { color: #586E75 } /* Literal.String.Backtick */ +.highlight .sc { color: #2AA198 } /* Literal.String.Char */ +.highlight .sd { color: #93A1A1 } /* Literal.String.Doc */ +.highlight .s2 { color: #2AA198 } /* Literal.String.Double */ +.highlight .se { color: #CB4B16 } /* Literal.String.Escape */ +.highlight .sh { color: #93A1A1 } /* Literal.String.Heredoc */ +.highlight .si { color: #2AA198 } /* Literal.String.Interpol */ +.highlight .sx { color: #2AA198 } /* Literal.String.Other */ +.highlight .sr { color: #DC322F } /* Literal.String.Regex */ +.highlight .s1 { color: #2AA198 } /* Literal.String.Single */ +.highlight .ss { color: #2AA198 } /* Literal.String.Symbol */ +.highlight .bp { color: #268BD2 } /* Name.Builtin.Pseudo */ +.highlight .vc { color: #268BD2 } /* Name.Variable.Class */ +.highlight .vg { color: #268BD2 } /* Name.Variable.Global */ +.highlight .vi { color: #268BD2 } /* Name.Variable.Instance */ +.highlight .il { color: #2AA198 } /* Literal.Number.Integer.Long */ \ No newline at end of file diff --git a/docs/index.html b/docs/index.html index c62b646..56f9996 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1,48 +1,12 @@ - - - - - - - Iris - - - - - - -
- -
-

- Iris is a interpreter of ISLisp on Go/JavaScript. -

-
-
-
- -
-
-
-

Copyright © 2017 TANIGUCHI Masaya All Rights Reserved.

-
-
- - \ No newline at end of file +--- +layout: default +title: Welcome +--- +
+

Blog Posts

+
    + {% for post in site.posts %} +
  • {{ post.date | date_to_string }} » {{ post.title }}
  • + {% endfor %} +
+
From 1964a11e5dddd6e1e019fb746a6c8d146fbdb78b Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Sat, 12 Aug 2017 10:17:59 +0900 Subject: [PATCH 138/228] wip --- docs/.gitignore | 1 + docs/_config.yml | 11 ++- docs/_includes/footer.html | 3 + docs/_includes/head.html | 11 +++ docs/_includes/header.html | 3 + docs/_layouts/default.html | 13 ++-- docs/_layouts/page.html | 6 ++ docs/_layouts/post.html | 4 +- docs/_pages/01_about.md | 33 ++++++++ docs/_posts/2017-08-11-welcome-to-jedie.md | 22 ------ docs/_sass/_base.scss | 0 docs/_sass/_code.scss | 0 docs/css/main.scss | 1 + docs/css/site.css | 91 ---------------------- docs/index.html | 10 +-- 15 files changed, 77 insertions(+), 132 deletions(-) create mode 100644 docs/.gitignore create mode 100644 docs/_includes/footer.html create mode 100644 docs/_includes/head.html create mode 100644 docs/_includes/header.html create mode 100644 docs/_layouts/page.html create mode 100644 docs/_pages/01_about.md delete mode 100644 docs/_posts/2017-08-11-welcome-to-jedie.md create mode 100644 docs/_sass/_base.scss create mode 100644 docs/_sass/_code.scss create mode 100644 docs/css/main.scss delete mode 100644 docs/css/site.css diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 0000000..c08f9ad --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1 @@ +_site \ No newline at end of file diff --git a/docs/_config.yml b/docs/_config.yml index 9803faf..ebcd1cd 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -1,5 +1,14 @@ name: iris -description: iris is a interpreter of ISLisp on golang +email: ta2gch@moffice.space +description: iris is a interpreter of ISLisp. +baseurl: "iris" +url: "https://ta2gch.github.io" +twitter_username: ta2gch +github_username: ta2gch +# Build Settings +sass: + sass_dir: _sass +include: ['_pages'] gems: - jemoji - jekyll-mentions diff --git a/docs/_includes/footer.html b/docs/_includes/footer.html new file mode 100644 index 0000000..69ca609 --- /dev/null +++ b/docs/_includes/footer.html @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/docs/_includes/head.html b/docs/_includes/head.html new file mode 100644 index 0000000..2cad684 --- /dev/null +++ b/docs/_includes/head.html @@ -0,0 +1,11 @@ + + + + + + {% if page.title %}{{ page.title }}{% else %}{{ site.title }}{% endif %} + + + + {% feed_meta %} + \ No newline at end of file diff --git a/docs/_includes/header.html b/docs/_includes/header.html new file mode 100644 index 0000000..4b2cfd3 --- /dev/null +++ b/docs/_includes/header.html @@ -0,0 +1,3 @@ +
+

{{ site.title }}

+
\ No newline at end of file diff --git a/docs/_layouts/default.html b/docs/_layouts/default.html index 9db1432..33ddc0d 100644 --- a/docs/_layouts/default.html +++ b/docs/_layouts/default.html @@ -1,12 +1,11 @@ - - - - {{ site.title }} - {% feed_meta %} - +{% include head.html %} -{{ content }} + {% include header.html %} +
+ {{ content }} +
+ {% include footer.html %} diff --git a/docs/_layouts/page.html b/docs/_layouts/page.html new file mode 100644 index 0000000..2982d8f --- /dev/null +++ b/docs/_layouts/page.html @@ -0,0 +1,6 @@ +--- +layout: default +--- +

{{ page.title }}

+ +{{ content }} diff --git a/docs/_layouts/post.html b/docs/_layouts/post.html index 04e3586..e57fec2 100644 --- a/docs/_layouts/post.html +++ b/docs/_layouts/post.html @@ -2,8 +2,6 @@ layout: default ---

{{ page.title }}

-

{{ page.date | date_to_string }}

+ -
{{ content }} -
diff --git a/docs/_pages/01_about.md b/docs/_pages/01_about.md new file mode 100644 index 0000000..1e37b66 --- /dev/null +++ b/docs/_pages/01_about.md @@ -0,0 +1,33 @@ +--- +layout: page +title: About +permalink: /about/ +--- + +# iris + +Iris is a interpreter of ISLisp implemented with golang + +[![Build Status](https://travis-ci.org/ta2gch/iris.svg?branch=master)](https://travis-ci.org/ta2gch/iris) + +## Introduction + +ISLisp is a member of LISP family and standardized by ISO in 2007. +As you know, Common Lisp is standardized by ANSI in 1994. +Iris is a interpreter of ISLisp implemented with golang. + +## Development + +### Test + +Iris is tested on TravisCI with this command. + +``` +$ go test ./... +``` + +## License +This software is licensed under the Mozilla Public License v2.0 + +## Copyright +Copyright (c) 2017 TANIGUCHI Masaya \ No newline at end of file diff --git a/docs/_posts/2017-08-11-welcome-to-jedie.md b/docs/_posts/2017-08-11-welcome-to-jedie.md deleted file mode 100644 index 9c00af3..0000000 --- a/docs/_posts/2017-08-11-welcome-to-jedie.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -layout: post -title: "Welcome to Jedie!" -date: 2013-11-22 21:42:47 ---- - -You'll find this post in your `_posts` directory - edit this post and re-build (or run with the `-w` switch) to see your changes! -To add new posts, simply add a file in the `_posts` directory that follows the convention: YYYY-MM-DD-name-of-post.ext. - -Jekyll also offers powerful support for code snippets: - - package main - - import "fmt" - - func main() { - fmt.Println("こんにちわ世界") - } - -Check out the [Jedie][jedie-gh] for more info. - -[jedie-gh]: https://github.com/mattn/jedie diff --git a/docs/_sass/_base.scss b/docs/_sass/_base.scss new file mode 100644 index 0000000..e69de29 diff --git a/docs/_sass/_code.scss b/docs/_sass/_code.scss new file mode 100644 index 0000000..e69de29 diff --git a/docs/css/main.scss b/docs/css/main.scss new file mode 100644 index 0000000..4b736a3 --- /dev/null +++ b/docs/css/main.scss @@ -0,0 +1 @@ +@import "base", "code" \ No newline at end of file diff --git a/docs/css/site.css b/docs/css/site.css deleted file mode 100644 index 834cabe..0000000 --- a/docs/css/site.css +++ /dev/null @@ -1,91 +0,0 @@ -body { - font-family: Sans; -} - -h1 { - color: darkgreen; -} - -.highlight { - background-color: #efefef; - padding: 7px 7px 7px 10px; - border: 1px solid #ddd; - -moz-box-shadow: 3px 3px rgba(0,0,0,0.1); - -webkit-box-shadow: 3px 3px rgba(0,0,0,0.1); - box-shadow: 3px 3px rgba(0,0,0,0.1); - margin: 20px 0 20px 0; - overflow: hidden; -} - -code { - font-family:'Bitstream Vera Sans Mono','Courier', monospace; -} - -.highlight .c { color: #586E75 } /* Comment */ -.highlight .err { color: #93A1A1 } /* Error */ -.highlight .g { color: #93A1A1 } /* Generic */ -.highlight .k { color: #859900 } /* Keyword */ -.highlight .l { color: #93A1A1 } /* Literal */ -.highlight .n { color: #93A1A1 } /* Name */ -.highlight .o { color: #859900 } /* Operator */ -.highlight .x { color: #CB4B16 } /* Other */ -.highlight .p { color: #93A1A1 } /* Punctuation */ -.highlight .cm { color: #586E75 } /* Comment.Multiline */ -.highlight .cp { color: #859900 } /* Comment.Preproc */ -.highlight .c1 { color: #586E75 } /* Comment.Single */ -.highlight .cs { color: #859900 } /* Comment.Special */ -.highlight .gd { color: #2AA198 } /* Generic.Deleted */ -.highlight .ge { color: #93A1A1; font-style: italic } /* Generic.Emph */ -.highlight .gr { color: #DC322F } /* Generic.Error */ -.highlight .gh { color: #CB4B16 } /* Generic.Heading */ -.highlight .gi { color: #859900 } /* Generic.Inserted */ -.highlight .go { color: #93A1A1 } /* Generic.Output */ -.highlight .gp { color: #93A1A1 } /* Generic.Prompt */ -.highlight .gs { color: #93A1A1; font-weight: bold } /* Generic.Strong */ -.highlight .gu { color: #CB4B16 } /* Generic.Subheading */ -.highlight .gt { color: #93A1A1 } /* Generic.Traceback */ -.highlight .kc { color: #CB4B16 } /* Keyword.Constant */ -.highlight .kd { color: #268BD2 } /* Keyword.Declaration */ -.highlight .kn { color: #859900 } /* Keyword.Namespace */ -.highlight .kp { color: #859900 } /* Keyword.Pseudo */ -.highlight .kr { color: #268BD2 } /* Keyword.Reserved */ -.highlight .kt { color: #DC322F } /* Keyword.Type */ -.highlight .ld { color: #93A1A1 } /* Literal.Date */ -.highlight .m { color: #2AA198 } /* Literal.Number */ -.highlight .s { color: #2AA198 } /* Literal.String */ -.highlight .na { color: #93A1A1 } /* Name.Attribute */ -.highlight .nb { color: #B58900 } /* Name.Builtin */ -.highlight .nc { color: #268BD2 } /* Name.Class */ -.highlight .no { color: #CB4B16 } /* Name.Constant */ -.highlight .nd { color: #268BD2 } /* Name.Decorator */ -.highlight .ni { color: #CB4B16 } /* Name.Entity */ -.highlight .ne { color: #CB4B16 } /* Name.Exception */ -.highlight .nf { color: #268BD2 } /* Name.Function */ -.highlight .nl { color: #93A1A1 } /* Name.Label */ -.highlight .nn { color: #93A1A1 } /* Name.Namespace */ -.highlight .nx { color: #555 } /* Name.Other */ -.highlight .py { color: #93A1A1 } /* Name.Property */ -.highlight .nt { color: #268BD2 } /* Name.Tag */ -.highlight .nv { color: #268BD2 } /* Name.Variable */ -.highlight .ow { color: #859900 } /* Operator.Word */ -.highlight .w { color: #93A1A1 } /* Text.Whitespace */ -.highlight .mf { color: #2AA198 } /* Literal.Number.Float */ -.highlight .mh { color: #2AA198 } /* Literal.Number.Hex */ -.highlight .mi { color: #2AA198 } /* Literal.Number.Integer */ -.highlight .mo { color: #2AA198 } /* Literal.Number.Oct */ -.highlight .sb { color: #586E75 } /* Literal.String.Backtick */ -.highlight .sc { color: #2AA198 } /* Literal.String.Char */ -.highlight .sd { color: #93A1A1 } /* Literal.String.Doc */ -.highlight .s2 { color: #2AA198 } /* Literal.String.Double */ -.highlight .se { color: #CB4B16 } /* Literal.String.Escape */ -.highlight .sh { color: #93A1A1 } /* Literal.String.Heredoc */ -.highlight .si { color: #2AA198 } /* Literal.String.Interpol */ -.highlight .sx { color: #2AA198 } /* Literal.String.Other */ -.highlight .sr { color: #DC322F } /* Literal.String.Regex */ -.highlight .s1 { color: #2AA198 } /* Literal.String.Single */ -.highlight .ss { color: #2AA198 } /* Literal.String.Symbol */ -.highlight .bp { color: #268BD2 } /* Name.Builtin.Pseudo */ -.highlight .vc { color: #268BD2 } /* Name.Variable.Class */ -.highlight .vg { color: #268BD2 } /* Name.Variable.Global */ -.highlight .vi { color: #268BD2 } /* Name.Variable.Instance */ -.highlight .il { color: #2AA198 } /* Literal.Number.Integer.Long */ \ No newline at end of file diff --git a/docs/index.html b/docs/index.html index 56f9996..a7cc77d 100644 --- a/docs/index.html +++ b/docs/index.html @@ -2,11 +2,5 @@ layout: default title: Welcome --- -
-

Blog Posts

-
    - {% for post in site.posts %} -
  • {{ post.date | date_to_string }} » {{ post.title }}
  • - {% endfor %} -
-
+ +

iris

From 6a7054b1e324c32638e4e5f3c64fc82d8a6cf288 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Sat, 12 Aug 2017 14:17:09 +0900 Subject: [PATCH 139/228] Added functions of section 19.1 --- runtime/number_class.go | 427 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 421 insertions(+), 6 deletions(-) diff --git a/runtime/number_class.go b/runtime/number_class.go index 1b5ca88..5521a30 100644 --- a/runtime/number_class.go +++ b/runtime/number_class.go @@ -5,6 +5,8 @@ package runtime import ( + "math" + "github.com/ta2gch/iris/reader/parser" "github.com/ta2gch/iris/runtime/environment" "github.com/ta2gch/iris/runtime/ilos" @@ -12,6 +14,20 @@ import ( "github.com/ta2gch/iris/runtime/ilos/instance" ) +func convFloat64(x ilos.Instance) (float64, bool, ilos.Instance) { + switch { + case instance.Of(class.Integer, x): + return float64(x.(instance.Integer)), false, nil + case instance.Of(class.Float, x): + return float64(x.(instance.Float)), true, nil + default: + return 0.0, false, instance.New(class.DomainError, map[string]ilos.Instance{ + "OBJECT": x, + "EXPECTED-CLASS": class.Number, + }) + } +} + // Numberp returns t if obj is a number (instance of class number); otherwise, // returns nil. The obj may be any ISLISP object. func Numberp(_, _ *environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { @@ -51,16 +67,16 @@ func ParseNumber(_, _ *environment.Environment, str ilos.Instance) (ilos.Instanc // Note: = differs from eql because = compares only the mathematical values of its arguments, // whereas eql also compares the representations func EqualNumber(_, _ *environment.Environment, x1, x2 ilos.Instance) (ilos.Instance, ilos.Instance) { - if instance.Of(class.Number, x1) { + if !instance.Of(class.Number, x1) { return nil, instance.New(class.DomainError, map[string]ilos.Instance{ "OBJECT": x1, - "EXPECTED-CLASS": class.String, + "EXPECTED-CLASS": class.Number, }) } - if instance.Of(class.Number, x2) { + if !instance.Of(class.Number, x2) { return nil, instance.New(class.DomainError, map[string]ilos.Instance{ "OBJECT": x2, - "EXPECTED-CLASS": class.String, + "EXPECTED-CLASS": class.Number, }) } ret := false @@ -88,6 +104,405 @@ func NotEqualNumber(_, _ *environment.Environment, x1, x2 ilos.Instance) (ilos.I if err != nil { return ret, err } - ret, err = Not(nil, nil, ret) - return ret, err + return Not(nil, nil, ret) +} + +// GreaterThan returns t if x1 is greater than x2 +func GreaterThan(_, _ *environment.Environment, x1, x2 ilos.Instance) (ilos.Instance, ilos.Instance) { + if !instance.Of(class.Number, x1) { + return nil, instance.New(class.DomainError, map[string]ilos.Instance{ + "OBJECT": x1, + "EXPECTED-CLASS": class.Number, + }) + } + if !instance.Of(class.Number, x2) { + return nil, instance.New(class.DomainError, map[string]ilos.Instance{ + "OBJECT": x2, + "EXPECTED-CLASS": class.Number, + }) + } + ret := false + switch { + case instance.Of(class.Integer, x1) && instance.Of(class.Integer, x2): + ret = float64(x1.(instance.Integer)) > float64(x2.(instance.Integer)) + case instance.Of(class.Integer, x1) && instance.Of(class.Float, x2): + ret = float64(x1.(instance.Integer)) > float64(x2.(instance.Float)) + case instance.Of(class.Float, x1) && instance.Of(class.Integer, x2): + ret = float64(x1.(instance.Float)) > float64(x2.(instance.Integer)) + case instance.Of(class.Float, x1) && instance.Of(class.Float, x2): + ret = float64(x1.(instance.Float)) > float64(x2.(instance.Float)) + } + if ret { + return T, nil + } + return Nil, nil +} + +// GreaterThanOrEqual returns t if x1 is greater than or = x2 +func GreaterThanOrEqual(_, _ *environment.Environment, x1, x2 ilos.Instance) (ilos.Instance, ilos.Instance) { + gt, err := GreaterThan(nil, nil, x1, x2) + if err != nil { + return nil, err + } + eq, err := EqualNumber(nil, nil, x1, x2) + if err != nil { + return nil, err + } + if gt == Nil && eq == Nil { + return Nil, nil + } + return T, nil +} + +// LessThan returns t if x1 is less than x2 +func LessThan(_, _ *environment.Environment, x1, x2 ilos.Instance) (ilos.Instance, ilos.Instance) { + ge, err := GreaterThanOrEqual(nil, nil, x1, x2) + if err != nil { + return nil, err + } + return Not(nil, nil, ge) +} + +// LessThanOrEqulal returns t if x1 is less than or = x2 +func LessThanOrEqulal(_, _ *environment.Environment, x1, x2 ilos.Instance) (ilos.Instance, ilos.Instance) { + gt, err := GreaterThan(nil, nil, x1, x2) + if err != nil { + return nil, err + } + return Not(nil, nil, gt) +} + +// Add returns the sum, respectively, of their arguments. If all arguments are integers, +// the result is an integer. If any argument is a float, the result is a float. When given no arguments, +// + returns 0. An error shall be signaled if any x is not a number (error-id. domain-error). +func Add(_, _ *environment.Environment, x ...ilos.Instance) (ilos.Instance, ilos.Instance) { + flt := false + sum := 0.0 + for _, a := range x { + f, b, err := convFloat64(a) + if err != nil { + return nil, err + } + flt = flt || b + sum += f + } + if flt { + return instance.New(class.Float, sum), nil + } + return instance.New(class.Integer, int(sum)), nil +} + +// Multiply returns the product, respectively, of their arguments. If all arguments are integers, +// the result is an integer. If any argument is a float, the result is a float. When given no arguments, +// Multiply returns 1. An error shall be signaled if any x is not a number (error-id. domain-error). +func Multiply(_, _ *environment.Environment, x ...ilos.Instance) (ilos.Instance, ilos.Instance) { + flt := false + pdt := 1.0 + for _, a := range x { + f, b, err := convFloat64(a) + if err != nil { + return nil, err + } + pdt *= f + flt = flt || b + } + if flt { + return instance.New(class.Float, pdt), nil + } + return instance.New(class.Integer, int(pdt)), nil +} + +// Substruct returns its additive inverse. An error shall be signaled +// if x is not a number (error-id. domain-error). +// +// If an implementation supports a -0.0 that is distinct from 0.0, then (- 0.0) +// returns -0.0; in implementations where -0.0 and 0.0 are not distinct, (- 0.0) returns 0.0. +// Given more than one argument, x1 … xn , - returns their successive differences, +// x1 −x2 − … −xn. An error shall be signaled if any x is not a number (error-id. domain-error). +func Substruct(_, _ *environment.Environment, x ilos.Instance, xs ...ilos.Instance) (ilos.Instance, ilos.Instance) { + if len(xs) == 0 { + ret, err := Substruct(nil, nil, instance.New(class.Integer, 0), x) + return ret, err + } + sub, flt, err := convFloat64(x) + if err != nil { + return nil, err + } + for _, a := range xs { + f, b, err := convFloat64(a) + if err != nil { + return nil, err + } + sub -= f + flt = flt || b + } + if flt { + return instance.New(class.Float, sub), nil + } + return instance.New(class.Integer, int(sub)), nil +} + +// Quotient returns the quotient of those numbers. The result is an integer if dividend and divisor are integers and divisor evenly divides dividend , otherwise it will be a float. +// +// Given more than two arguments, quotient operates iteratively on each of the divisor1 … divisorn as in dividend /divisor1 / … /divisorn. The type of the result follows from the two-argument case because the three-or-more-argument quotient can be defined as follows: +// An error shall be signaled if dividend is not a number (error-id. domain-error). An error shall be signaled if any divisor is not a number (error-id. domain-error). An error shall be signaled if any divisor is zero (error-id. division-by-zero). +func Quotient(_, _ *environment.Environment, dividend, divisor1 ilos.Instance, divisor ...ilos.Instance) (ilos.Instance, ilos.Instance) { + divisor = append([]ilos.Instance{divisor1}, divisor...) + quotient, flt, err := convFloat64(dividend) + if err != nil { + return nil, err + } + for _, a := range divisor { + f, b, err := convFloat64(a) + if err != nil { + return nil, err + } + if f == 0.0 { + return nil, instance.New(class.DivisionByZero) + } + if !flt && !b && int(quotient)%int(f) != 0 { + flt = true + } + quotient /= f + } + if flt { + return instance.New(class.Float, quotient), nil + } + return instance.New(class.Integer, int(quotient)), nil +} + +// Reciprocal returns the reciprocal of its argument x ; that is, 1/x . +// An error shall be signaled if x is zero (error-id. division-by-zero). +func Reciprocal(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { + return Quotient(nil, nil, instance.New(class.Integer, 1), x) +} + +// Max returns the greatest (closest to positive infinity) of its arguments. The comparison is done by >. +// An error shall be signaled if any x is not a number (error-id. domain-error). +func Max(_, _ *environment.Environment, x ilos.Instance, xs ...ilos.Instance) (ilos.Instance, ilos.Instance) { + max := x + for _, y := range xs { + ret, err := GreaterThan(nil, nil, y, max) + if err != nil { + return nil, err + } + if ret == T { + max = y + } + } + return max, nil +} + +// Min returns the least (closest to negative infinity) of its arguments. The comparison is done by <. +// An error shall be signaled if any x is not a number (error-id. domain-error). +func Min(_, _ *environment.Environment, x ilos.Instance, xs ...ilos.Instance) (ilos.Instance, ilos.Instance) { + min := x + for _, y := range xs { + ret, err := LessThan(nil, nil, y, min) + if err != nil { + return nil, err + } + if ret == T { + min = y + } + } + return min, nil +} + +// Abs returns the absolute value of its argument. +// An error shall be signaled if x is not a number (error-id. domain-error). +func Abs(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { + ret, err := LessThan(nil, nil, x, instance.New(class.Integer, 0)) + if err != nil { + return nil, err + } + if ret == T { + return Substruct(nil, nil, x) + } + return x, nil +} + +// Exp returns e raised to the power x , where e is the base of the natural logarithm. +// An error shall be signaled if x is not a number (error-id. domain-error). +func Exp(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { + f, _, err := convFloat64(x) + if err != nil { + return nil, err + } + return instance.New(class.Float, math.Exp(f)), nil +} + +// Log returns the natural logarithm of x. +// An error shall be signaled if x is not a positive number (error-id. domain-error). +func Log(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { + f, _, err := convFloat64(x) + if err != nil { + return nil, err + } + if f <= 0.0 { + return nil, instance.New(class.DomainError, map[string]ilos.Instance{ + "OBJECT": x, + "EXPECTED-CLASS": class.Number, + }) + } + return instance.New(class.Float, math.Log(f)), nil +} + +// Expt returns x1 raised to the power x2. The result will be +// an integer if x1 is an integer and x2 is a non-negative integer. +// An error shall be signaled if x1 is zero and x2 is negative, +// or if x1 is zero and x2 is a zero float, or if x1 is negative +// and x2 is not an integer. +func Expt(_, _ *environment.Environment, x1, x2 ilos.Instance) (ilos.Instance, ilos.Instance) { + a, af, err := convFloat64(x1) + if err != nil { + return nil, err + } + b, bf, err := convFloat64(x2) + if err != nil { + return nil, err + } + if !af && !bf && b >= 0 { + return instance.New(class.Integer, int(math.Pow(a, b))), nil + } + if (a == 0 && b < 0) || (a == 0 && bf && b == 0) || (a < 0 && bf) { + return nil, instance.New(class.ArithmeticError, map[string]ilos.Instance{ + "OPERATION": instance.New(class.Symbol, "EXPT"), + "OPERANDS": instance.New(class.Cons, x1, instance.New(class.Cons, x2, Nil)), + }) + } + return instance.New(class.Float, math.Pow(a, b)), nil +} + +// Sqrt returns the non-negative square root of x. An error shall be signaled +// if x is not a non-negative number (error-id. domain-error). +func Sqrt(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { + a, _, err := convFloat64(x) + if err != nil { + return nil, err + } + if a < 0.0 { + return nil, instance.New(class.DomainError, map[string]ilos.Instance{ + "OBJECT": x, + "EXPECTED-CLASS": class.Number, + }) + } + return instance.New(class.Float, math.Sqrt(a)), nil +} + +// PI is an approximation of π. +var PI = instance.New(class.Float, 3.141592653589793) + +// Sin returns the sine of x . x must be given in radians. +// An error shall be signaled if x is not a number (error-id. domain-error). +func Sin(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { + a, _, err := convFloat64(x) + if err != nil { + return nil, err + } + return instance.New(class.Float, math.Sin(a)), nil +} + +// Cos returns the cosine of x . x must be given in radians. +// An error shall be signaled if x is not a number (error-id. domain-error). +func Cos(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { + a, _, err := convFloat64(x) + if err != nil { + return nil, err + } + return instance.New(class.Float, math.Cos(a)), nil +} + +// Tan returns the tangent of x . x must be given in radians. +// An error shall be signaled if x is not a number (error-id. domain-error). +func Tan(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { + a, _, err := convFloat64(x) + if err != nil { + return nil, err + } + return instance.New(class.Float, math.Tan(a)), nil +} + +// Atan returns the arc tangent of x. +// The result is a (real) number that lies between −π/2 and π/2 (both exclusive). +// An error shall be signaled if x is not a number (error-id. domain-error). +func Atan(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { + a, _, err := convFloat64(x) + if err != nil { + return nil, err + } + return instance.New(class.Float, math.Atan(a)), nil +} + +// Atan2 returns the phase of its representation in polar coordinates. +// If x1 is zero and x2 is negative, the result is positive. +// If x1 and x2 are both zero, the result is implementation defined. +// +// An error shall be signaled if x is not a number (error-id. domain-error). +// The value of atan2 is always between −π (exclusive) and π (inclusive) when minus zero +// is not supported; when minus zero is supported, the range includes −π. +// +// The signs of x1 (indicated as y) and x2 (indicated as x) are used to derive quadrant information. +func Atan2(_, _ *environment.Environment, x1, x2 ilos.Instance) (ilos.Instance, ilos.Instance) { + a, _, err := convFloat64(x1) + if err != nil { + return nil, err + } + b, _, err := convFloat64(x2) + if err != nil { + return nil, err + } + if a == 0 && b == 0 { + return nil, instance.New(class.ArithmeticError, map[string]ilos.Instance{ + "OPERATION": instance.New(class.Symbol, "ATAN2"), + "OPERANDS": instance.New(class.Cons, x1, instance.New(class.Cons, x2, Nil)), + }) + } + return instance.New(class.Float, math.Atan2(a, b)), nil +} + +// Sinh returns the hyperbolic sine of x . x must be given in radians. +// An error shall be signaled if x is not a number (error-id. domain-error). +func Sinh(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { + a, _, err := convFloat64(x) + if err != nil { + return nil, err + } + return instance.New(class.Float, math.Sinh(a)), nil +} + +// Cosh returns the hyperbolic cosine of x . x must be given in radians. +// An error shall be signaled if x is not a number (error-id. domain-error). +func Cosh(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { + a, _, err := convFloat64(x) + if err != nil { + return nil, err + } + return instance.New(class.Float, math.Cosh(a)), nil +} + +// Tanh returns the hyperbolic tangent of x . x must be given in radians. +// An error shall be signaled if x is not a number (error-id. domain-error). +func Tanh(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { + a, _, err := convFloat64(x) + if err != nil { + return nil, err + } + return instance.New(class.Float, math.Tanh(a)), nil +} + +// Atanh returns the hyperbolic arc tangent of x. +// An error shall be signaled if x is not a number with absolute value less than 1 (error-id. domain-error). +func Atanh(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { + a, _, err := convFloat64(x) + if err != nil { + return nil, err + } + if math.Abs(a) >= 1 { + return nil, instance.New(class.DomainError, map[string]ilos.Instance{ + "OBJECT": x, + "EXPECTED-CLASS": class.Number, + }) + } + return instance.New(class.Float, math.Atanh(a)), nil } From f7216b10d3d7885251dcde00fd70cbf956f6bae3 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Sat, 12 Aug 2017 14:46:25 +0900 Subject: [PATCH 140/228] Added functions of section 19.2 --- runtime/float_class.go | 84 +++++++++++++++++++++++++++++++++++++++++ runtime/number_class.go | 14 ------- runtime/util.go | 14 +++++++ 3 files changed, 98 insertions(+), 14 deletions(-) create mode 100644 runtime/float_class.go diff --git a/runtime/float_class.go b/runtime/float_class.go new file mode 100644 index 0000000..38b01f5 --- /dev/null +++ b/runtime/float_class.go @@ -0,0 +1,84 @@ +package runtime + +import ( + "math" + + "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/ilos" + "github.com/ta2gch/iris/runtime/ilos/class" + "github.com/ta2gch/iris/runtime/ilos/instance" +) + +// The value of MostPositiveFloat is the implementation-dependent +// floating-point number closest to positive infinity. +// +// The value of MostNegativeFloat is the implementation-dependent +// floating-point number closest to negative infinity. +var ( + MostPositiveFloat = instance.New(class.Float, math.MaxFloat64) + MostNegativeFloat = instance.New(class.Float, -math.MaxFloat64) +) + +// Floatp returns t if obj is a float (instance of class float); +// otherwise, returns nil. The obj may be any ISLISP object. +func Floatp(_, _ *environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { + if instance.Of(class.Float, obj) { + return T, nil + } + return Nil, nil +} + +// Float returns x itself if it is an instance of the class float +// and returns a floating-point approximation of x otherwise. +// An error shall be signaled if x is not a number (error-id. domain-error). +func Float(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { + f, _, err := convFloat64(x) + if err != nil { + return nil, err + } + return instance.New(class.Float, f), nil +} + +// Floor returns the greatest integer less than or equal to x . +// That is, x is truncated towards negative infinity. An error +// shall be signaled if x is not a number (error-id. domain-error). +func Floor(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { + f, _, err := convFloat64(x) + if err != nil { + return nil, err + } + return instance.New(class.Integer, int(math.Floor(f))), nil +} + +// Ceiling Returns the smallest integer that is not smaller than x. +// That is, x is truncated towards positive infinity. An error +// shall be signaled if x is not a number (error-id. domain-error). +func Ceiling(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { + f, _, err := convFloat64(x) + if err != nil { + return nil, err + } + return instance.New(class.Integer, int(math.Ceil(f))), nil +} + +// Truncate returns the integer between 0 and x (inclusive) that is nearest to x. +// That is, x is truncated towards zero. An error shall be signaled +// if x is not a number (error-id. domain-error). +func Truncate(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { + f, _, err := convFloat64(x) + if err != nil { + return nil, err + } + return instance.New(class.Integer, int(math.Trunc(f))), nil +} + +// Round returns the integer nearest to x. +// If x is exactly halfway between two integers, the even one is chosen. +// An error shall be signaled if x is not a number (error-id. domain-error). +func Round(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { + f, _, err := convFloat64(x) + if err != nil { + return nil, err + } + return instance.New(class.Integer, int(math.Floor(f+.5))), nil +} diff --git a/runtime/number_class.go b/runtime/number_class.go index 5521a30..814f320 100644 --- a/runtime/number_class.go +++ b/runtime/number_class.go @@ -14,20 +14,6 @@ import ( "github.com/ta2gch/iris/runtime/ilos/instance" ) -func convFloat64(x ilos.Instance) (float64, bool, ilos.Instance) { - switch { - case instance.Of(class.Integer, x): - return float64(x.(instance.Integer)), false, nil - case instance.Of(class.Float, x): - return float64(x.(instance.Float)), true, nil - default: - return 0.0, false, instance.New(class.DomainError, map[string]ilos.Instance{ - "OBJECT": x, - "EXPECTED-CLASS": class.Number, - }) - } -} - // Numberp returns t if obj is a number (instance of class number); otherwise, // returns nil. The obj may be any ISLISP object. func Numberp(_, _ *environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { diff --git a/runtime/util.go b/runtime/util.go index fd0fb8a..b482817 100644 --- a/runtime/util.go +++ b/runtime/util.go @@ -26,6 +26,20 @@ func isProperList(i ilos.Instance) bool { return false } +func convFloat64(x ilos.Instance) (float64, bool, ilos.Instance) { + switch { + case instance.Of(class.Integer, x): + return float64(x.(instance.Integer)), false, nil + case instance.Of(class.Float, x): + return float64(x.(instance.Float)), true, nil + default: + return 0.0, false, instance.New(class.DomainError, map[string]ilos.Instance{ + "OBJECT": x, + "EXPECTED-CLASS": class.Number, + }) + } +} + func readFromString(s string) ilos.Instance { e, _ := parser.Parse(tokenizer.New(strings.NewReader(s))) return e From 5d5907e9dc8803010be8c557e3d817262cdb9f24 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Sat, 12 Aug 2017 14:46:57 +0900 Subject: [PATCH 141/228] Changed comment --- runtime/float_class.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/float_class.go b/runtime/float_class.go index 38b01f5..2012a49 100644 --- a/runtime/float_class.go +++ b/runtime/float_class.go @@ -73,7 +73,7 @@ func Truncate(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, il } // Round returns the integer nearest to x. -// If x is exactly halfway between two integers, the even one is chosen. +// If x is exactly halfway between two integers, the even one is chosen. // An error shall be signaled if x is not a number (error-id. domain-error). func Round(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { f, _, err := convFloat64(x) From e56cefa3ae03848d5c57f87ab8a4d2a630cbc098 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Sat, 12 Aug 2017 15:18:48 +0900 Subject: [PATCH 142/228] Added functions of section 19.3 --- runtime/integer_class.go | 137 +++++++++++++++++++++++++++++++++++++++ runtime/number_class.go | 9 ++- 2 files changed, 145 insertions(+), 1 deletion(-) create mode 100644 runtime/integer_class.go diff --git a/runtime/integer_class.go b/runtime/integer_class.go new file mode 100644 index 0000000..d637d37 --- /dev/null +++ b/runtime/integer_class.go @@ -0,0 +1,137 @@ +package runtime + +import ( + "math" + + "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/ilos" + "github.com/ta2gch/iris/runtime/ilos/class" + "github.com/ta2gch/iris/runtime/ilos/instance" +) + +func convInt(z ilos.Instance) (int, ilos.Instance) { + if instance.Of(class.Integer, z) { + return 0, instance.New(class.DomainError, map[string]ilos.Instance{ + "OBJECT": z, + "EXPECTED-CLASS": class.Integer, + }) + } + return int(z.(instance.Integer)), nil +} + +// Integerp returns t if obj is an integer (instance of class integer); +// otherwise, returns nil. obj may be any ISLISP object. +func Integerp(_, _ *environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { + if instance.Of(class.Integer, obj) { + return T, nil + } + return Nil, nil +} + +// Div returns the greatest integer less than or equal to the quotient of z1 and z2. +// An error shall be signaled if z2 is zero (error-id. division-by-zero). +func Div(_, _ *environment.Environment, z1, z2 ilos.Instance) (ilos.Instance, ilos.Instance) { + a, err := convInt(z1) + if err != nil { + return nil, err + } + b, err := convInt(z2) + if err != nil { + return nil, err + } + if b == 0 { + return nil, instance.New(class.DivisionByZero, map[string]ilos.Instance{ + "OPERATION": instance.New(class.Symbol, "DIV"), + "OPERANDS": instance.New(class.Cons, z1, instance.New(class.Cons, z2, Nil)), + }) + } + return instance.New(class.Integer, a/b), nil +} + +// Mod returns the remainder of the integer division of z1 by z2. +// The sign of the result is the sign of z2. The result lies +// between 0 (inclusive) and z2 (exclusive), and the difference of z1 +// and this result is divisible by z2 without remainder. +// +// An error shall be signaled if either z1 or z2 is not an integer (error-id. domain-error). +func Mod(_, _ *environment.Environment, z1, z2 ilos.Instance) (ilos.Instance, ilos.Instance) { + a, err := convInt(z1) + if err != nil { + return nil, err + } + b, err := convInt(z2) + if err != nil { + return nil, err + } + if b == 0 { + return nil, instance.New(class.DivisionByZero, map[string]ilos.Instance{ + "OPERATION": instance.New(class.Symbol, "MOD"), + "OPERANDS": instance.New(class.Cons, z1, instance.New(class.Cons, z2, Nil)), + }) + } + return instance.New(class.Integer, a%b), nil +} + +// Gcd returns the greatest common divisor of its integer arguments. +// The result is a non-negative integer. For nonzero arguments +// the greatest common divisor is the largest integer z such that +// z1 and z2 are integral multiples of z. +// +// An error shall be signaled if either z1 or z2 is not an integer +// (error-id. domain-error). +func Gcd(_, _ *environment.Environment, z1, z2 ilos.Instance) (ilos.Instance, ilos.Instance) { + gcd := func(x, y int) int { + for y != 0 { + x, y = y, x%y + } + return x + } + a, err := convInt(z1) + if err != nil { + return nil, err + } + b, err := convInt(z2) + if err != nil { + return nil, err + } + return instance.New(class.Integer, gcd(a, b)), nil +} + +// Lcm returns the least common multiple of its integer arguments. +// +// An error shall be signaled if either z1 or z2 is not an integer +// (error-id. domain-error). +func Lcm(_, _ *environment.Environment, z1, z2 ilos.Instance) (ilos.Instance, ilos.Instance) { + gcd := func(x, y int) int { + for y != 0 { + x, y = y, x%y + } + return x + } + a, err := convInt(z1) + if err != nil { + return nil, err + } + b, err := convInt(z2) + if err != nil { + return nil, err + } + return instance.New(class.Integer, a*b/gcd(a, b)), nil +} + +// Isqrt Returns the greatest integer less than or equal to +// the exact positive square root of z . An error shall be signaled +// if z is not a non-negative integer (error-id. domain-error). +func Isqrt(_, _ *environment.Environment, z ilos.Instance) (ilos.Instance, ilos.Instance) { + a, err := convInt(z) + if err != nil { + return nil, err + } + if a < 0 { + return nil, instance.New(class.DomainError, map[string]ilos.Instance{ + "OBJECT": z, + "EXPECTED-CLASS": class.Number, + }) + } + return instance.New(class.Integer, int(math.Sqrt(float64(a)))), nil +} diff --git a/runtime/number_class.go b/runtime/number_class.go index 814f320..b0f910d 100644 --- a/runtime/number_class.go +++ b/runtime/number_class.go @@ -244,7 +244,14 @@ func Quotient(_, _ *environment.Environment, dividend, divisor1 ilos.Instance, d return nil, err } if f == 0.0 { - return nil, instance.New(class.DivisionByZero) + arguments := Nil + for i := len(divisor) - 1; i >= 0; i-- { + arguments = instance.New(class.Cons, divisor[i], arguments) + } + return nil, instance.New(class.DivisionByZero, map[string]ilos.Instance{ + "OPERATION": instance.New(class.Symbol, "QUOTIENT"), + "OPERANDS": arguments, + }) } if !flt && !b && int(quotient)%int(f) != 0 { flt = true From f0dee253b16c0497f81e519307314d49f3106128 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Sat, 12 Aug 2017 15:24:35 +0900 Subject: [PATCH 143/228] Added License term --- runtime/float_class.go | 4 ++++ runtime/integer_class.go | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/runtime/float_class.go b/runtime/float_class.go index 2012a49..7d0a81d 100644 --- a/runtime/float_class.go +++ b/runtime/float_class.go @@ -1,3 +1,7 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + package runtime import ( diff --git a/runtime/integer_class.go b/runtime/integer_class.go index d637d37..011f9b9 100644 --- a/runtime/integer_class.go +++ b/runtime/integer_class.go @@ -1,3 +1,7 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + package runtime import ( From eab27f4d0ce56b55238137d05e1678670eeae4cb Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Sat, 12 Aug 2017 15:32:07 +0900 Subject: [PATCH 144/228] Added functions of section 13.4 --- runtime/logical_connectives.go | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/runtime/logical_connectives.go b/runtime/logical_connectives.go index a4cd572..a1dbece 100644 --- a/runtime/logical_connectives.go +++ b/runtime/logical_connectives.go @@ -17,3 +17,32 @@ func Not(_, _ *environment.Environment, obj ilos.Instance) (ilos.Instance, ilos. } return Nil, nil } + +// And is the sequential logical “and” (or “∧”). forms are evaluated +// from left to right until either one of them evaluates to nil or else +// none are left. If one of them evaluates to nil, then nil is returned +// from the and; otherwise, the value of the last evaluated form is returned. +func And(_, _ *environment.Environment, form ...ilos.Instance) (ilos.Instance, ilos.Instance) { + for _, f := range form { + if f == Nil { + return Nil, nil + } + } + if len(form) == 0 { + return T, nil + } + return form[len(form)-1], nil +} + +// Or is the sequential logical "or" (or "∨"). forms are evaluated +// from left to right until either one of them evaluates to a non-nil value +// or else none are left. If one of them evaluates to a non-nil value, +// then this non-nil value is returned, otherwise nil is returned. +func Or(_, _ *environment.Environment, form ...ilos.Instance) (ilos.Instance, ilos.Instance) { + for _, f := range form { + if f != Nil { + return f, nil + } + } + return Nil, nil +} From abebc8ccc88b60b0fabc2eeb3bfcf0f0d617d3bf Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Sat, 12 Aug 2017 18:27:09 +0900 Subject: [PATCH 145/228] (WIP) Add functions of section 14.2 --- runtime/variables.go | 119 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 runtime/variables.go diff --git a/runtime/variables.go b/runtime/variables.go new file mode 100644 index 0000000..159511a --- /dev/null +++ b/runtime/variables.go @@ -0,0 +1,119 @@ +package runtime + +import ( + "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/ilos" + "github.com/ta2gch/iris/runtime/ilos/class" + "github.com/ta2gch/iris/runtime/ilos/instance" +) + +// Setq represents an assignment to the variable denoted by the identifier. In consequence, +// the identifier may designate a different object than before, the value of form. +// +// The result of the evaluation of form is returned. This result is used to +// modify the variable binding denoted by the identifier var (if it is mutable). +// setq can be used only for modifying bindings, and not for establishing a variable. +// The setq special form must be contained in the scope of var , established by defglobal, +// let, let*, for, or a lambda expression. +func Setq(local, global *environment.Environment, var1, form ilos.Instance) (ilos.Instance, ilos.Instance) { + ret, err := Eval(local, global, form) + if err != nil { + return nil, err + } + if local.Variable.Set(var1, ret) { + return ret, nil + } + if global.Variable.Set(var1, ret) { + return ret, nil + } + return nil, instance.New(class.UndefinedVariable, map[string]ilos.Instance{ + "NAME": var1, + "NAMESPACE": instance.New(class.Symbol, "VARIABLE"), + }) +} + +// TODO: Setf + +// Let is used to define a scope for a group of identifiers +// for a sequence of forms body-form* (collectively referred to as the body). +// The list of pairs (var form)* is called the let variable list. +// The scope of the identifier var is the body. +// +// The forms are evaluated sequentially from left to right; +// then each variable denoted by the identifier var is initialized to the corresponding value. +// Using these bindings along with the already existing bindings of visible +// identifiers the body-forms are evaluated. The returned value of let is the result +// of the evaluation of the last body-form of its body (or nil if there is none). +// +// No var may appear more than once in let variable list. +func Let(local, global *environment.Environment, varForm ilos.Instance, bodyForm ...ilos.Instance) (ilos.Instance, ilos.Instance) { + cdr := varForm + vfs := map[ilos.Instance]ilos.Instance{} + for instance.Of(class.Cons, cdr) { + uCar, uCdr := instance.UnsafeCar, instance.UnsafeCdr + cadr, cddr := uCar(cdr), uCdr(cdr) // Checked at the top of this loop + if !(instance.Of(class.Cons, cadr) && instance.Of(class.Cons, uCdr(cadr)) && uCdr(uCdr(cadr)) == Nil) { + return nil, instance.New(class.ProgramError) + } + v := uCar(cadr) // Checked before statement + f, err := Eval(local, global, uCar(uCdr(cadr))) + if err != nil { + return nil, err + } + vfs[v] = f + cdr = cddr + } + for v, f := range vfs { + local.Variable.Define(v, f) + } + var err ilos.Instance + ret := Nil + for _, form := range bodyForm { + ret, err = Eval(local, global, form) + if err != nil { + return nil, err + } + } + return ret, nil +} + +// LetStar form is used to define a scope for a group of identifiers for a sequence +// of forms body-form* (collectively referred to as the body). +// The first subform (the let* variable list) is a list of pairs (var form). +// The scope of an identifier var is the body along with all form +// forms following the pair (var form) in the let* variable list. +// +// For each pair (var form) the following is done: form is evaluated in the context +// of the bindings in effect at that point in the evaluation. The result of +// the evaluation is bound to its associated variable named by the identifier var . +// These variable bindings enlarge the set of current valid identifiers perhaps +// shadowing previous variable bindings (in case some var was defined outside), +// and in this enlarged or modified environment the body-forms are executed. +// The returned value of let* is the result of the evaluation of the last form +// of its body (or nil if there is none). +func LetStar(local, global *environment.Environment, varForm ilos.Instance, bodyForm ...ilos.Instance) (ilos.Instance, ilos.Instance) { + cdr := varForm + for instance.Of(class.Cons, cdr) { + uCar, uCdr := instance.UnsafeCar, instance.UnsafeCdr + cadr, cddr := uCar(cdr), uCdr(cdr) // Checked at the top of this loop + if !(instance.Of(class.Cons, cadr) && instance.Of(class.Cons, uCdr(cadr)) && uCdr(uCdr(cadr)) == Nil) { + return nil, instance.New(class.ProgramError) + } + v := uCar(cadr) // Checked before statement + f, err := Eval(local, global, uCar(uCdr(cadr))) + if err != nil { + return nil, err + } + local.Variable.Define(v, f) + cdr = cddr + } + var err ilos.Instance + ret := Nil + for _, form := range bodyForm { + ret, err = Eval(local, global, form) + if err != nil { + return nil, err + } + } + return ret, nil +} From da1a99f1dea694c387cc6c207c4ef3bce088728d Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Sat, 12 Aug 2017 19:14:29 +0900 Subject: [PATCH 146/228] Added License term --- runtime/variables.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/runtime/variables.go b/runtime/variables.go index 159511a..65deb4b 100644 --- a/runtime/variables.go +++ b/runtime/variables.go @@ -1,3 +1,7 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + package runtime import ( From a9d799fe98b8bf86d2b9db0738646516a0390315 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Sat, 12 Aug 2017 20:26:00 +0900 Subject: [PATCH 147/228] Added functions of section 21.1 --- runtime/cons.go | 86 +++++++++++++++++++++++++++++++++++ runtime/ilos/instance/list.go | 10 ++++ 2 files changed, 96 insertions(+) create mode 100644 runtime/cons.go diff --git a/runtime/cons.go b/runtime/cons.go new file mode 100644 index 0000000..1702cdc --- /dev/null +++ b/runtime/cons.go @@ -0,0 +1,86 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package runtime + +import ( + "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/ilos" + "github.com/ta2gch/iris/runtime/ilos/class" + "github.com/ta2gch/iris/runtime/ilos/instance" +) + +// Consp returns t if obj is a cons (instance of class cons); +// otherwise, returns nil. obj may be any ISLISP object. +func Consp(_, _ *environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { + if instance.Of(class.Cons, obj) { + return T, nil + } + return Nil, nil +} + +// Cons builds a cons from two objects, with obj1 +// as its car (or `left') part and with obj2 as its cdr (or `right') part. +// An error shall be signaled if the requested cons cannot +// be allocated (error-id. cannot-create-cons). Both obj1 +// and obj2 may be any ISLISP object. +func Cons(_, _ *environment.Environment, obj1, obj2 ilos.Instance) (ilos.Instance, ilos.Instance) { + return instance.New(class.Cons, obj1, obj2), nil +} + +// Car returns the left component of the cons. +// An error shall be signaled if cons is not a cons (error-id. domain-error). +func Car(_, _ *environment.Environment, cons ilos.Instance) (ilos.Instance, ilos.Instance) { + if !instance.Of(class.Cons, cons) { + return nil, instance.New(class.DomainError, map[string]ilos.Instance{ + "OBJECT": cons, + "EXPECTED-CLASS": class.Cons, + }) + } + return instance.UnsafeCar(cons), nil // Checked at the top of this function +} + +// Cdr returns the right component of the cons. +// An error shall be signaled if cons is not a cons (error-id. domain-error). +func Cdr(_, _ *environment.Environment, cons ilos.Instance) (ilos.Instance, ilos.Instance) { + if !instance.Of(class.Cons, cons) { + return nil, instance.New(class.DomainError, map[string]ilos.Instance{ + "OBJECT": cons, + "EXPECTED-CLASS": class.Cons, + }) + } + return instance.UnsafeCdr(cons), nil // Checked at the top of this function +} + +// TODO: setf car + +// SetCar updates the left component of cons with obj. The returned value is obj . +// An error shall be signaled if cons is not a cons (error-id. domain-error). +// obj may be any ISLISP object. +func SetCar(_, _ *environment.Environment, obj, cons ilos.Instance) (ilos.Instance, ilos.Instance) { + if !instance.Of(class.Cons, cons) { + return nil, instance.New(class.DomainError, map[string]ilos.Instance{ + "OBJECT": cons, + "EXPECTED-CLASS": class.Cons, + }) + } + instance.UnsafeSetCar(obj, cons) + return obj, nil +} + +// TODO: setf cdr + +// SetCdr updates the right component of cons with obj. The returned value is obj . +// An error shall be signaled if cons is not a cons (error-id. domain-error). +// obj may be any ISLISP object. +func SetCdr(_, _ *environment.Environment, obj, cons ilos.Instance) (ilos.Instance, ilos.Instance) { + if !instance.Of(class.Cons, cons) { + return nil, instance.New(class.DomainError, map[string]ilos.Instance{ + "OBJECT": cons, + "EXPECTED-CLASS": class.Cons, + }) + } + instance.UnsafeSetCdr(obj, cons) + return obj, nil +} diff --git a/runtime/ilos/instance/list.go b/runtime/ilos/instance/list.go index 55c7479..e728f90 100644 --- a/runtime/ilos/instance/list.go +++ b/runtime/ilos/instance/list.go @@ -73,6 +73,16 @@ func UnsafeCdr(i ilos.Instance) ilos.Instance { return i.(*Cons).cdr } +func UnsafeSetCar(o, i ilos.Instance) ilos.Instance { + i.(*Cons).car = o + return o +} + +func UnsafeSetCdr(o, i ilos.Instance) ilos.Instance { + i.(*Cons).cdr = o + return o +} + // // Null // From 58d43039d35c5c8cca95e79a8928f827995c5699 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Sat, 12 Aug 2017 21:08:28 +0900 Subject: [PATCH 148/228] Signals if variable has already been defined --- runtime/environment/stack.go | 7 +++++-- runtime/functions.go | 8 ++++++-- runtime/namedfunc.go | 8 ++++++-- runtime/non-local_exits.go | 12 +++++++++--- runtime/variables.go | 8 ++++++-- 5 files changed, 32 insertions(+), 11 deletions(-) diff --git a/runtime/environment/stack.go b/runtime/environment/stack.go index e695478..eaa0f4f 100644 --- a/runtime/environment/stack.go +++ b/runtime/environment/stack.go @@ -33,6 +33,9 @@ func (s stack) Set(key, value ilos.Instance) bool { return false } -func (s stack) Define(key, value ilos.Instance) { - s[0][key] = value +func (s stack) Define(key, value ilos.Instance) bool { + if _, ok := s[0][key]; ok { + s[0][key] = value + } + return false } diff --git a/runtime/functions.go b/runtime/functions.go index e064b6c..7b010d3 100644 --- a/runtime/functions.go +++ b/runtime/functions.go @@ -157,7 +157,9 @@ func Labels(local, global *environment.Environment, functions ilos.Instance, bod form = append(form, caddadr) cddadr = instance.UnsafeCdr(cddadr) // Checked at the top of this loop } - local.Function.Define(functionName, newNamedFunction(local, global, functionName, lambdaList, form...)) + if local.Function.Define(functionName, newNamedFunction(local, global, functionName, lambdaList, form...)) { + return nil, instance.New(class.ProgramError) + } cdr = instance.UnsafeCdr(cdr) // Checked at #1 } ret := Nil @@ -208,7 +210,9 @@ func Flet(local, global *environment.Environment, functions ilos.Instance, bodyF form = append(form, caddadr) cddadr = instance.UnsafeCdr(cddadr) // Checked at the top of this loop } - env.Function.Define(functionName, newNamedFunction(local, global, functionName, lambdaList, form...)) + if env.Function.Define(functionName, newNamedFunction(local, global, functionName, lambdaList, form...)) { + return nil, instance.New(class.ProgramError) + } cdr = instance.UnsafeCdr(cdr) // Checked at #1 } ret := Nil diff --git a/runtime/namedfunc.go b/runtime/namedfunc.go index 38c5dfd..9615dc3 100644 --- a/runtime/namedfunc.go +++ b/runtime/namedfunc.go @@ -48,11 +48,15 @@ func newNamedFunction(local, global *environment.Environment, functionName, lamb for i := len(arguments) - 1; i >= idx; i-- { value = instance.New(class.Cons, arguments[i], value) } - local.Variable.Define(key, value) + if local.Variable.Define(key, value) { + return nil, instance.New(class.ProgramError) + } break } value := arguments[idx] - local.Variable.Define(key, value) + if local.Variable.Define(key, value) { + return nil, instance.New(class.ProgramError) + } } ret := Nil var err ilos.Instance diff --git a/runtime/non-local_exits.go b/runtime/non-local_exits.go index 29d481c..d0431c0 100644 --- a/runtime/non-local_exits.go +++ b/runtime/non-local_exits.go @@ -50,7 +50,9 @@ func Block(local, global *environment.Environment, tag ilos.Instance, body ...il "EXPECTED-CLASS": class.Object, }) } - local.BlockTag.Define(tag, nil) + if local.BlockTag.Define(tag, nil) { + return nil, instance.New(class.ProgramError) + } var fail ilos.Instance sucess := Nil for _, cadr := range body { @@ -106,7 +108,9 @@ func Catch(local, global *environment.Environment, tag ilos.Instance, body ...il if instance.Of(class.Number, tag) || instance.Of(class.Character, tag) { return nil, instance.New(class.DomainError, tag, class.Object) } - local.CatchTag.Define(tag, nil) + if local.CatchTag.Define(tag, nil) { + return nil, instance.New(class.ProgramError) + } var fail ilos.Instance sucess := Nil for _, cadr := range body { @@ -157,7 +161,9 @@ func Tagbody(local, global *environment.Environment, body ...ilos.Instance) (ilo for idx, cadr := range body { cddr := instance.New(class.GeneralVector, body[idx+1:]) if !instance.Of(class.Cons, cadr) { - local.TagbodyTag.Define(cadr, cddr) + if local.TagbodyTag.Define(cadr, cddr) { + return nil, instance.New(class.ProgramError) + } } } for _, cadr := range body { diff --git a/runtime/variables.go b/runtime/variables.go index 65deb4b..61664d9 100644 --- a/runtime/variables.go +++ b/runtime/variables.go @@ -68,7 +68,9 @@ func Let(local, global *environment.Environment, varForm ilos.Instance, bodyForm cdr = cddr } for v, f := range vfs { - local.Variable.Define(v, f) + if local.Variable.Define(v, f) { + return nil, instance.New(class.ProgramError) + } } var err ilos.Instance ret := Nil @@ -108,7 +110,9 @@ func LetStar(local, global *environment.Environment, varForm ilos.Instance, body if err != nil { return nil, err } - local.Variable.Define(v, f) + if local.Variable.Define(v, f) { + return nil, instance.New(class.ProgramError) + } cdr = cddr } var err ilos.Instance From 8fdf22734a2778525bc4bdf6da487bd81f2329d6 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Sat, 12 Aug 2017 21:29:34 +0900 Subject: [PATCH 149/228] Added TODOs --- runtime/character_class.go | 7 +++++++ runtime/conditional_expressions.go | 7 +++++++ runtime/defining_operators.go | 7 +++++++ runtime/dynamic_variables.go | 7 +++++++ runtime/equality.go | 7 +++++++ runtime/iteration.go | 7 +++++++ runtime/list_operations.go | 7 +++++++ runtime/sequencing_forms.go | 7 +++++++ runtime/string_class.go | 7 +++++++ runtime/symbol_properties.go | 7 +++++++ runtime/vectors.go | 7 +++++++ 11 files changed, 77 insertions(+) create mode 100644 runtime/character_class.go create mode 100644 runtime/conditional_expressions.go create mode 100644 runtime/defining_operators.go create mode 100644 runtime/dynamic_variables.go create mode 100644 runtime/equality.go create mode 100644 runtime/iteration.go create mode 100644 runtime/list_operations.go create mode 100644 runtime/sequencing_forms.go create mode 100644 runtime/string_class.go create mode 100644 runtime/symbol_properties.go create mode 100644 runtime/vectors.go diff --git a/runtime/character_class.go b/runtime/character_class.go new file mode 100644 index 0000000..6bcc9dd --- /dev/null +++ b/runtime/character_class.go @@ -0,0 +1,7 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package runtime + +//TODO: characterp, char=, char/=, char<, char>, char<=, char>= diff --git a/runtime/conditional_expressions.go b/runtime/conditional_expressions.go new file mode 100644 index 0000000..c865c2a --- /dev/null +++ b/runtime/conditional_expressions.go @@ -0,0 +1,7 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package runtime + +// TODO: if, cond, case, case-using diff --git a/runtime/defining_operators.go b/runtime/defining_operators.go new file mode 100644 index 0000000..00d95a8 --- /dev/null +++ b/runtime/defining_operators.go @@ -0,0 +1,7 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package runtime + +// TODO: defconstant, defglobal, defdynamic, defun diff --git a/runtime/dynamic_variables.go b/runtime/dynamic_variables.go new file mode 100644 index 0000000..1a14773 --- /dev/null +++ b/runtime/dynamic_variables.go @@ -0,0 +1,7 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package runtime + +// TODO: dynamic, setf dynamic, set-dynamic, dynamic-let diff --git a/runtime/equality.go b/runtime/equality.go new file mode 100644 index 0000000..f172c63 --- /dev/null +++ b/runtime/equality.go @@ -0,0 +1,7 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package runtime + +// TODO: eq, eql, equal diff --git a/runtime/iteration.go b/runtime/iteration.go new file mode 100644 index 0000000..e0aad44 --- /dev/null +++ b/runtime/iteration.go @@ -0,0 +1,7 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package runtime + +// TODO: while, for diff --git a/runtime/list_operations.go b/runtime/list_operations.go new file mode 100644 index 0000000..bd4e6df --- /dev/null +++ b/runtime/list_operations.go @@ -0,0 +1,7 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package runtime + +// TODO: listp, craete-list, list, reverse, nreverse, append, member, mapcar, mapc, mapcan, maplist, mapcon, assoc diff --git a/runtime/sequencing_forms.go b/runtime/sequencing_forms.go new file mode 100644 index 0000000..2c338c7 --- /dev/null +++ b/runtime/sequencing_forms.go @@ -0,0 +1,7 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package runtime + +// TODO: progn diff --git a/runtime/string_class.go b/runtime/string_class.go new file mode 100644 index 0000000..07899c1 --- /dev/null +++ b/runtime/string_class.go @@ -0,0 +1,7 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package runtime + +// TODO: stringp, create-string, string=, string/=, string<, string>, string>=, string <=, char-index, string-append diff --git a/runtime/symbol_properties.go b/runtime/symbol_properties.go new file mode 100644 index 0000000..e2d9bbd --- /dev/null +++ b/runtime/symbol_properties.go @@ -0,0 +1,7 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package runtime + +// TODO: property, setf property, set-property, remove-property diff --git a/runtime/vectors.go b/runtime/vectors.go new file mode 100644 index 0000000..53f588a --- /dev/null +++ b/runtime/vectors.go @@ -0,0 +1,7 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package runtime + +// TODO: basic-vector-p, general-vector-p, create-vector, vector From 0f931e684b1fe3a2d15e2607b57cc74b3e229482 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Sun, 13 Aug 2017 10:25:33 +0900 Subject: [PATCH 150/228] Fixed environment Define --- runtime/environment/stack.go | 5 +++-- runtime/eval_test.go | 8 ++++---- runtime/number_class.go | 4 ++-- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/runtime/environment/stack.go b/runtime/environment/stack.go index eaa0f4f..1e59ba7 100644 --- a/runtime/environment/stack.go +++ b/runtime/environment/stack.go @@ -34,8 +34,9 @@ func (s stack) Set(key, value ilos.Instance) bool { } func (s stack) Define(key, value ilos.Instance) bool { - if _, ok := s[0][key]; ok { - s[0][key] = value + if _, ok := s[len(s)-1][key]; !ok { + s[len(s)-1][key] = value + return true } return false } diff --git a/runtime/eval_test.go b/runtime/eval_test.go index 6b9e154..9e31ee7 100644 --- a/runtime/eval_test.go +++ b/runtime/eval_test.go @@ -20,8 +20,8 @@ func TestEval(t *testing.T) { defun("INC", func(local, global *environment.Environment, arg ilos.Instance) (ilos.Instance, ilos.Instance) { return instance.New(class.Integer, int(arg.(instance.Integer))+1), nil }) - defglobal("PI", instance.New(class.Float, 3.14)) - defmacro("MINC", func(local *environment.Environment, global *environment.Environment, arg ilos.Instance) (ilos.Instance, ilos.Instance) { + defglobal("*PI*", Pi) + defmacro("MINC", func(local, global *environment.Environment, arg ilos.Instance) (ilos.Instance, ilos.Instance) { return instance.New(class.Cons, instance.New(class.Symbol, "INC"), instance.New(class.Cons, arg, Nil)), nil }) type arguments struct { @@ -37,8 +37,8 @@ func TestEval(t *testing.T) { }{ { name: "local variable", - arguments: arguments{instance.New(class.Symbol, "PI"), local, global}, - want: instance.New(class.Float, 3.14), + arguments: arguments{readFromString("*pi*"), local, global}, + want: Pi, wantErr: false, }, { diff --git a/runtime/number_class.go b/runtime/number_class.go index b0f910d..d92ffdf 100644 --- a/runtime/number_class.go +++ b/runtime/number_class.go @@ -383,8 +383,8 @@ func Sqrt(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos.I return instance.New(class.Float, math.Sqrt(a)), nil } -// PI is an approximation of π. -var PI = instance.New(class.Float, 3.141592653589793) +// Pi is an approximation of π. +var Pi = instance.New(class.Float, 3.141592653589793) // Sin returns the sine of x . x must be given in radians. // An error shall be signaled if x is not a number (error-id. domain-error). From 1eb88ef82c8c9eda7dadb42d3e208380cfc7099e Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Sun, 13 Aug 2017 10:25:56 +0900 Subject: [PATCH 151/228] Changed String() --- runtime/ilos/instance/instance.go | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/runtime/ilos/instance/instance.go b/runtime/ilos/instance/instance.go index d3b9ef8..3d43ef2 100644 --- a/runtime/ilos/instance/instance.go +++ b/runtime/ilos/instance/instance.go @@ -5,7 +5,8 @@ package instance import ( - "github.com/k0kubun/pp" + "fmt" + "github.com/ta2gch/iris/runtime/ilos" "github.com/ta2gch/iris/runtime/ilos/class" ) @@ -91,6 +92,22 @@ func (i *instance) SetSlotValue(key ilos.Instance, value ilos.Instance, class il return false } +func (i *instance) Slots() map[string]ilos.Instance { + m := map[string]ilos.Instance{} + for k, v := range i.slots { + m[k] = v + } + for _, c := range i.supers { + if _, ok := c.(*instance); ok { + for k, v := range c.(*instance).Slots() { + m[k] = v + } + } + } + return m +} + func (i *instance) String() string { - return pp.Sprint(i) + c := i.Class().String() + return fmt.Sprintf("#%v %v>", c[:len(c)-1], i.Slots()) } From f270a582665fe165ea36e62192a09b4bb1a25530 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Sun, 13 Aug 2017 10:39:35 +0900 Subject: [PATCH 152/228] Renamed functions --- runtime/number_class.go | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/runtime/number_class.go b/runtime/number_class.go index d92ffdf..38d8464 100644 --- a/runtime/number_class.go +++ b/runtime/number_class.go @@ -46,13 +46,13 @@ func ParseNumber(_, _ *environment.Environment, str ilos.Instance) (ilos.Instanc return ret, err } -// EqualNumber returns t if x1 has the same mathematical value as x2 ; +// NumberEqual returns t if x1 has the same mathematical value as x2 ; // otherwise, returns nil. An error shall be signaled if either x1 or x2 is not a number // (error-id. domain-error). // // Note: = differs from eql because = compares only the mathematical values of its arguments, // whereas eql also compares the representations -func EqualNumber(_, _ *environment.Environment, x1, x2 ilos.Instance) (ilos.Instance, ilos.Instance) { +func NumberEqual(_, _ *environment.Environment, x1, x2 ilos.Instance) (ilos.Instance, ilos.Instance) { if !instance.Of(class.Number, x1) { return nil, instance.New(class.DomainError, map[string]ilos.Instance{ "OBJECT": x1, @@ -82,19 +82,19 @@ func EqualNumber(_, _ *environment.Environment, x1, x2 ilos.Instance) (ilos.Inst return Nil, nil } -// NotEqualNumber returns t if x1 and x2 have mathematically distinct values; +// NumberNotEqual returns t if x1 and x2 have mathematically distinct values; // otherwise, returns nil. An error shall be signaled if either x1 or x2 is not // a number (error-id. domain-error). -func NotEqualNumber(_, _ *environment.Environment, x1, x2 ilos.Instance) (ilos.Instance, ilos.Instance) { - ret, err := EqualNumber(nil, nil, x1, x2) +func NumberNotEqual(_, _ *environment.Environment, x1, x2 ilos.Instance) (ilos.Instance, ilos.Instance) { + ret, err := NumberEqual(nil, nil, x1, x2) if err != nil { return ret, err } return Not(nil, nil, ret) } -// GreaterThan returns t if x1 is greater than x2 -func GreaterThan(_, _ *environment.Environment, x1, x2 ilos.Instance) (ilos.Instance, ilos.Instance) { +// NumberGreaterThan returns t if x1 is greater than x2 +func NumberGreaterThan(_, _ *environment.Environment, x1, x2 ilos.Instance) (ilos.Instance, ilos.Instance) { if !instance.Of(class.Number, x1) { return nil, instance.New(class.DomainError, map[string]ilos.Instance{ "OBJECT": x1, @@ -124,13 +124,13 @@ func GreaterThan(_, _ *environment.Environment, x1, x2 ilos.Instance) (ilos.Inst return Nil, nil } -// GreaterThanOrEqual returns t if x1 is greater than or = x2 -func GreaterThanOrEqual(_, _ *environment.Environment, x1, x2 ilos.Instance) (ilos.Instance, ilos.Instance) { - gt, err := GreaterThan(nil, nil, x1, x2) +// NumberGreaterThanOrEqual returns t if x1 is greater than or = x2 +func NumberGreaterThanOrEqual(_, _ *environment.Environment, x1, x2 ilos.Instance) (ilos.Instance, ilos.Instance) { + gt, err := NumberGreaterThan(nil, nil, x1, x2) if err != nil { return nil, err } - eq, err := EqualNumber(nil, nil, x1, x2) + eq, err := NumberEqual(nil, nil, x1, x2) if err != nil { return nil, err } @@ -140,18 +140,18 @@ func GreaterThanOrEqual(_, _ *environment.Environment, x1, x2 ilos.Instance) (il return T, nil } -// LessThan returns t if x1 is less than x2 -func LessThan(_, _ *environment.Environment, x1, x2 ilos.Instance) (ilos.Instance, ilos.Instance) { - ge, err := GreaterThanOrEqual(nil, nil, x1, x2) +// NumberLessThan returns t if x1 is less than x2 +func NumberLessThan(_, _ *environment.Environment, x1, x2 ilos.Instance) (ilos.Instance, ilos.Instance) { + ge, err := NumberGreaterThanOrEqual(nil, nil, x1, x2) if err != nil { return nil, err } return Not(nil, nil, ge) } -// LessThanOrEqulal returns t if x1 is less than or = x2 -func LessThanOrEqulal(_, _ *environment.Environment, x1, x2 ilos.Instance) (ilos.Instance, ilos.Instance) { - gt, err := GreaterThan(nil, nil, x1, x2) +// NumberLessThanOrEqulal returns t if x1 is less than or = x2 +func NumberLessThanOrEqulal(_, _ *environment.Environment, x1, x2 ilos.Instance) (ilos.Instance, ilos.Instance) { + gt, err := NumberGreaterThan(nil, nil, x1, x2) if err != nil { return nil, err } @@ -275,7 +275,7 @@ func Reciprocal(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, func Max(_, _ *environment.Environment, x ilos.Instance, xs ...ilos.Instance) (ilos.Instance, ilos.Instance) { max := x for _, y := range xs { - ret, err := GreaterThan(nil, nil, y, max) + ret, err := NumberGreaterThan(nil, nil, y, max) if err != nil { return nil, err } @@ -291,7 +291,7 @@ func Max(_, _ *environment.Environment, x ilos.Instance, xs ...ilos.Instance) (i func Min(_, _ *environment.Environment, x ilos.Instance, xs ...ilos.Instance) (ilos.Instance, ilos.Instance) { min := x for _, y := range xs { - ret, err := LessThan(nil, nil, y, min) + ret, err := NumberLessThan(nil, nil, y, min) if err != nil { return nil, err } @@ -305,7 +305,7 @@ func Min(_, _ *environment.Environment, x ilos.Instance, xs ...ilos.Instance) (i // Abs returns the absolute value of its argument. // An error shall be signaled if x is not a number (error-id. domain-error). func Abs(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { - ret, err := LessThan(nil, nil, x, instance.New(class.Integer, 0)) + ret, err := NumberLessThan(nil, nil, x, instance.New(class.Integer, 0)) if err != nil { return nil, err } From f5b72105efaa8928686b8581890efe6ac70387cf Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Sun, 13 Aug 2017 10:39:56 +0900 Subject: [PATCH 153/228] Added functions of section 20 --- runtime/character_class.go | 105 ++++++++++++++++++++++++++++++++++++- 1 file changed, 104 insertions(+), 1 deletion(-) diff --git a/runtime/character_class.go b/runtime/character_class.go index 6bcc9dd..cc26623 100644 --- a/runtime/character_class.go +++ b/runtime/character_class.go @@ -4,4 +4,107 @@ package runtime -//TODO: characterp, char=, char/=, char<, char>, char<=, char>= +import ( + "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/ilos" + "github.com/ta2gch/iris/runtime/ilos/class" + "github.com/ta2gch/iris/runtime/ilos/instance" +) + +//TODO: char<, char>, char<=, char>= + +// Characterp returns t if obj is a character (instance of class character); +// otherwise, returns nil. obj may be any ISLISP object. +func Characterp(_, _ *environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { + if instance.Of(class.Character, obj) { + return T, nil + } + return Nil, nil +} + +// CharEqual tests whether char1 is the same character as char2. +func CharEqual(_, _ *environment.Environment, c1, c2 ilos.Instance) (ilos.Instance, ilos.Instance) { + if !instance.Of(class.Character, c1) { + return nil, instance.New(class.DomainError, map[string]ilos.Instance{ + "OBJECT": c1, + "EXPECTED-CLASS": class.Character, + }) + } + if !instance.Of(class.Character, c2) { + return nil, instance.New(class.DomainError, map[string]ilos.Instance{ + "OBJECT": c2, + "EXPECTED-CLASS": class.Character, + }) + } + if c1 == c2 { + return T, nil + } + return Nil, nil +} + +// CharNotEqual if and only if they are not char=. +func CharNotEqual(_, _ *environment.Environment, c1, c2 ilos.Instance) (ilos.Instance, ilos.Instance) { + ret, err := CharEqual(nil, nil, c1, c2) + if err != nil { + return nil, err + } + return Not(nil, nil, ret) +} + +// CharGreaterThan tests whether char1 is greater than char2. +// An error shall be signaled if either char1 or char2 is not a character (error-id. domain-error). +func CharGreaterThan(_, _ *environment.Environment, c1, c2 ilos.Instance) (ilos.Instance, ilos.Instance) { + if !instance.Of(class.Character, c1) { + return nil, instance.New(class.DomainError, map[string]ilos.Instance{ + "OBJECT": c1, + "EXPECTED-CLASS": class.Character, + }) + } + if !instance.Of(class.Character, c2) { + return nil, instance.New(class.DomainError, map[string]ilos.Instance{ + "OBJECT": c2, + "EXPECTED-CLASS": class.Character, + }) + } + if c1.(instance.Character) > c2.(instance.Character) { + return T, nil + } + return Nil, nil +} + +// CharGreaterThanOrEqual tests whether char1 is greater than or equal to char2. +// An error shall be signaled if either char1 or char2 is not a character (error-id. domain-error). +func CharGreaterThanOrEqual(_, _ *environment.Environment, c1, c2 ilos.Instance) (ilos.Instance, ilos.Instance) { + gt, err := CharGreaterThan(nil, nil, c1, c2) + if err != nil { + return nil, err + } + eq, err := CharEqual(nil, nil, c1, c2) + if err != nil { + return nil, err + } + if gt == Nil && eq == Nil { + return Nil, nil + } + return T, nil +} + +// CharLessThan tests whether char1 is less than char2. +// An error shall be signaled if either char1 or char2 is not a character (error-id. domain-error). +func CharLessThan(_, _ *environment.Environment, c1, c2 ilos.Instance) (ilos.Instance, ilos.Instance) { + gt, err := CharGreaterThanOrEqual(nil, nil, c1, c2) + if err != nil { + return nil, err + } + return Not(nil, nil, gt) +} + +// CharLessThanOrEqual tests whether char1 is less than or equal to char2. +// An error shall be signaled if either char1 or char2 is not a character (error-id. domain-error). +func CharLessThanOrEqual(_, _ *environment.Environment, c1, c2 ilos.Instance) (ilos.Instance, ilos.Instance) { + gt, err := CharGreaterThan(nil, nil, c1, c2) + if err != nil { + return nil, err + } + return Not(nil, nil, gt) +} From 508d157640a48288b4fb7c1aa13d129230924beb Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Sun, 13 Aug 2017 10:59:30 +0900 Subject: [PATCH 154/228] Added functions of section 23 --- runtime/vectors.go | 62 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 61 insertions(+), 1 deletion(-) diff --git a/runtime/vectors.go b/runtime/vectors.go index 53f588a..491ca5b 100644 --- a/runtime/vectors.go +++ b/runtime/vectors.go @@ -4,4 +4,64 @@ package runtime -// TODO: basic-vector-p, general-vector-p, create-vector, vector +import ( + "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/ilos" + "github.com/ta2gch/iris/runtime/ilos/class" + "github.com/ta2gch/iris/runtime/ilos/instance" +) + +// BasicVectorP returns t if obj is a basic-vector (instance of class basic-vector); +// otherwise, returns nil. obj may be any ISLISP object. +func BasicVectorP(_, _ *environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { + if instance.Of(class.BasicVector, obj) { + return T, nil + } + return Nil, nil +} + +// GeneralVectorP returns t if obj is a general-vector (instance of class general-vector); +// otherwise, returns nil. obj may be any ISLISP object. +func GeneralVectorP(_, _ *environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { + if instance.Of(class.GeneralVector, obj) { + return T, nil + } + return Nil, nil +} + +// CreateVector returns a general-vector of length i. If initial-element is given, +// the elements of the new vector are initialized with this object, +// otherwise the initialization is implementation defined. An error shall be signaled +// if the requested vector cannot be allocated (error-id. cannot-create-vector). +// An error shall be signaled if i is not a non-negative integer (error-id. domain-error). +// initial-element may be any ISLISP object. +func CreateVector(_, _ *environment.Environment, i ilos.Instance, initialElement ...ilos.Instance) (ilos.Instance, ilos.Instance) { + if !instance.Of(class.Integer, i) || int(i.(instance.Integer)) < 0 { + return nil, instance.New(class.DomainError, map[string]ilos.Instance{ + "OBJECT": i, + "EXPECTED-CLASS": class.Integer, + }) + } + if len(initialElement) > 1 { + return nil, instance.New(class.ProgramError) + } + n := int(i.(instance.Integer)) + v := make([]ilos.Instance, n) + for i := 0; i < n; i++ { + if len(initialElement) == 0 { + v[i] = Nil + } else { + v[i] = initialElement[0] + } + } + return instance.New(class.GeneralVector, v), nil +} + +// Vector returns a new general-vector whose elements are its obj arguments. +// The length of the newly created vector is, therefore, the number of objs passed as arguments. +// The vector is indexed by integers ranging from 0 to dimension−1. An error shall be signaled +// if the requested vector cannot be allocated (error-id. cannot-create-vector). +// Each obj may be any ISLISP object. +func Vector(_, _ *environment.Environment, obj ...ilos.Instance) (ilos.Instance, ilos.Instance) { + return instance.New(class.GeneralVector, obj), nil +} From a2b5b47732d0134077fb2eac56057d5199e842f8 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Sun, 13 Aug 2017 11:48:43 +0900 Subject: [PATCH 155/228] Rename arguments --- runtime/character_class.go | 42 +++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/runtime/character_class.go b/runtime/character_class.go index cc26623..1ecfc59 100644 --- a/runtime/character_class.go +++ b/runtime/character_class.go @@ -23,28 +23,28 @@ func Characterp(_, _ *environment.Environment, obj ilos.Instance) (ilos.Instance } // CharEqual tests whether char1 is the same character as char2. -func CharEqual(_, _ *environment.Environment, c1, c2 ilos.Instance) (ilos.Instance, ilos.Instance) { - if !instance.Of(class.Character, c1) { +func CharEqual(_, _ *environment.Environment, char1, char2 ilos.Instance) (ilos.Instance, ilos.Instance) { + if !instance.Of(class.Character, char1) { return nil, instance.New(class.DomainError, map[string]ilos.Instance{ - "OBJECT": c1, + "OBJECT": char1, "EXPECTED-CLASS": class.Character, }) } - if !instance.Of(class.Character, c2) { + if !instance.Of(class.Character, char2) { return nil, instance.New(class.DomainError, map[string]ilos.Instance{ - "OBJECT": c2, + "OBJECT": char2, "EXPECTED-CLASS": class.Character, }) } - if c1 == c2 { + if char1 == char2 { return T, nil } return Nil, nil } // CharNotEqual if and only if they are not char=. -func CharNotEqual(_, _ *environment.Environment, c1, c2 ilos.Instance) (ilos.Instance, ilos.Instance) { - ret, err := CharEqual(nil, nil, c1, c2) +func CharNotEqual(_, _ *environment.Environment, char1, char2 ilos.Instance) (ilos.Instance, ilos.Instance) { + ret, err := CharEqual(nil, nil, char1, char2) if err != nil { return nil, err } @@ -53,20 +53,20 @@ func CharNotEqual(_, _ *environment.Environment, c1, c2 ilos.Instance) (ilos.Ins // CharGreaterThan tests whether char1 is greater than char2. // An error shall be signaled if either char1 or char2 is not a character (error-id. domain-error). -func CharGreaterThan(_, _ *environment.Environment, c1, c2 ilos.Instance) (ilos.Instance, ilos.Instance) { - if !instance.Of(class.Character, c1) { +func CharGreaterThan(_, _ *environment.Environment, char1, char2 ilos.Instance) (ilos.Instance, ilos.Instance) { + if !instance.Of(class.Character, char1) { return nil, instance.New(class.DomainError, map[string]ilos.Instance{ - "OBJECT": c1, + "OBJECT": char1, "EXPECTED-CLASS": class.Character, }) } - if !instance.Of(class.Character, c2) { + if !instance.Of(class.Character, char2) { return nil, instance.New(class.DomainError, map[string]ilos.Instance{ - "OBJECT": c2, + "OBJECT": char2, "EXPECTED-CLASS": class.Character, }) } - if c1.(instance.Character) > c2.(instance.Character) { + if char1.(instance.Character) > char2.(instance.Character) { return T, nil } return Nil, nil @@ -74,12 +74,12 @@ func CharGreaterThan(_, _ *environment.Environment, c1, c2 ilos.Instance) (ilos. // CharGreaterThanOrEqual tests whether char1 is greater than or equal to char2. // An error shall be signaled if either char1 or char2 is not a character (error-id. domain-error). -func CharGreaterThanOrEqual(_, _ *environment.Environment, c1, c2 ilos.Instance) (ilos.Instance, ilos.Instance) { - gt, err := CharGreaterThan(nil, nil, c1, c2) +func CharGreaterThanOrEqual(_, _ *environment.Environment, char1, char2 ilos.Instance) (ilos.Instance, ilos.Instance) { + gt, err := CharGreaterThan(nil, nil, char1, char2) if err != nil { return nil, err } - eq, err := CharEqual(nil, nil, c1, c2) + eq, err := CharEqual(nil, nil, char1, char2) if err != nil { return nil, err } @@ -91,8 +91,8 @@ func CharGreaterThanOrEqual(_, _ *environment.Environment, c1, c2 ilos.Instance) // CharLessThan tests whether char1 is less than char2. // An error shall be signaled if either char1 or char2 is not a character (error-id. domain-error). -func CharLessThan(_, _ *environment.Environment, c1, c2 ilos.Instance) (ilos.Instance, ilos.Instance) { - gt, err := CharGreaterThanOrEqual(nil, nil, c1, c2) +func CharLessThan(_, _ *environment.Environment, char1, char2 ilos.Instance) (ilos.Instance, ilos.Instance) { + gt, err := CharGreaterThanOrEqual(nil, nil, char1, char2) if err != nil { return nil, err } @@ -101,8 +101,8 @@ func CharLessThan(_, _ *environment.Environment, c1, c2 ilos.Instance) (ilos.Ins // CharLessThanOrEqual tests whether char1 is less than or equal to char2. // An error shall be signaled if either char1 or char2 is not a character (error-id. domain-error). -func CharLessThanOrEqual(_, _ *environment.Environment, c1, c2 ilos.Instance) (ilos.Instance, ilos.Instance) { - gt, err := CharGreaterThan(nil, nil, c1, c2) +func CharLessThanOrEqual(_, _ *environment.Environment, char1, char2 ilos.Instance) (ilos.Instance, ilos.Instance) { + gt, err := CharGreaterThan(nil, nil, char1, char2) if err != nil { return nil, err } From 473a759bed1a5bce148f0b4a15d0e88adefef1ee Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Sun, 13 Aug 2017 11:48:56 +0900 Subject: [PATCH 156/228] Added functions of section 24 --- runtime/string_class.go | 238 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 238 insertions(+) diff --git a/runtime/string_class.go b/runtime/string_class.go index 07899c1..b658cff 100644 --- a/runtime/string_class.go +++ b/runtime/string_class.go @@ -4,4 +4,242 @@ package runtime +import ( + "strings" + + "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/ilos" + "github.com/ta2gch/iris/runtime/ilos/class" + "github.com/ta2gch/iris/runtime/ilos/instance" +) + // TODO: stringp, create-string, string=, string/=, string<, string>, string>=, string <=, char-index, string-append + +// Stringp returns t if obj is a string (instance of class string); +// otherwise, returns nil. obj may be any ISLISP object. +func Stringp(_, _ *environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { + if instance.Of(class.String, obj) { + return T, nil + } + return Nil, nil +} + +// CreateString returns a string of length i. If initial-character is given, then the characters of +// the new string are initialized with this character, otherwise the initialization is implementation defined. +// An error shall be signaled if the requested string cannot be allocated (error-id. cannot-create-string). +// An error shall be signaled if i is not a non-negative integer or if initial-character is not a character (error-id. domain-error). +func CreateString(_, _ *environment.Environment, i ilos.Instance, initialElement ...ilos.Instance) (ilos.Instance, ilos.Instance) { + if !instance.Of(class.Integer, i) || int(i.(instance.Integer)) < 0 { + return nil, instance.New(class.DomainError, map[string]ilos.Instance{ + "OBJECT": i, + "EXPECTED-CLASS": class.Integer, + }) + } + if len(initialElement) > 1 { + return nil, instance.New(class.ProgramError) + } + n := int(i.(instance.Integer)) + v := make([]ilos.Instance, n) + for i := 0; i < n; i++ { + if len(initialElement) == 0 { + v[i] = Nil + } else { + if !instance.Of(class.Character, initialElement[0]) { + return nil, instance.New(class.DomainError, map[string]ilos.Instance{ + "OBJECT": initialElement[0], + "EXPECTED-CLASS": class.Character, + }) + } + v[i] = initialElement[0] + } + } + return instance.New(class.GeneralVector, v), nil +} + +// StringEqual tests whether string1 is the same string as string2. +func StringEqual(_, _ *environment.Environment, string1, string2 ilos.Instance) (ilos.Instance, ilos.Instance) { + if !instance.Of(class.String, string1) { + return nil, instance.New(class.DomainError, map[string]ilos.Instance{ + "OBJECT": string1, + "EXPECTED-CLASS": class.String, + }) + } + if !instance.Of(class.String, string2) { + return nil, instance.New(class.DomainError, map[string]ilos.Instance{ + "OBJECT": string2, + "EXPECTED-CLASS": class.String, + }) + } + if string1 == string2 { + return T, nil + } + return Nil, nil +} + +// StringNotEqual tests whether string1 not is the same string as string2. +func StringNotEqual(_, _ *environment.Environment, string1, string2 ilos.Instance) (ilos.Instance, ilos.Instance) { + ret, err := StringEqual(nil, nil, string1, string2) + if err != nil { + return nil, err + } + return Not(nil, nil, ret) +} + +// StringGreaterThan tests whether string1 is greater than string2. +func StringGreaterThan(_, _ *environment.Environment, string1, string2 ilos.Instance) (ilos.Instance, ilos.Instance) { + if !instance.Of(class.String, string1) { + return nil, instance.New(class.DomainError, map[string]ilos.Instance{ + "OBJECT": string1, + "EXPECTED-CLASS": class.String, + }) + } + if !instance.Of(class.String, string2) { + return nil, instance.New(class.DomainError, map[string]ilos.Instance{ + "OBJECT": string2, + "EXPECTED-CLASS": class.String, + }) + } + if string(string1.(instance.String)) > string(string2.(instance.String)) { + return T, nil + } + return Nil, nil +} + +// StringGreaterThanOrEqual tests whether string1 is greater than or equal to string2. +func StringGreaterThanOrEqual(_, _ *environment.Environment, string1, string2 ilos.Instance) (ilos.Instance, ilos.Instance) { + gt, err := StringGreaterThan(nil, nil, string1, string2) + if err != nil { + return nil, err + } + eq, err := StringEqual(nil, nil, string1, string2) + if err != nil { + return nil, err + } + if gt == Nil && eq == Nil { + return Nil, nil + } + return T, nil +} + +// StringLessThan tests whether string1 is less than string2. +func StringLessThan(_, _ *environment.Environment, string1, string2 ilos.Instance) (ilos.Instance, ilos.Instance) { + gt, err := StringGreaterThanOrEqual(nil, nil, string1, string2) + if err != nil { + return nil, err + } + return Not(nil, nil, gt) +} + +// StringLessThanOrEqual tests whether string1 is less than or equal to string2. +func StringLessThanOrEqual(_, _ *environment.Environment, string1, string2 ilos.Instance) (ilos.Instance, ilos.Instance) { + gt, err := StringGreaterThan(nil, nil, string1, string2) + if err != nil { + return nil, err + } + return Not(nil, nil, gt) +} + +// CharIndex returns the position of char in string, The search starts from the position indicated +// by start-position (which is 0-based and defaults to 0). The value returned if the search +// succeeds is an offset from the beginning of the string, not from the starting point. +// If the char does not occur in the string, nil is returned. The function char= is used for the comparisons. +// +// An error shall be signaled if char is not a character or if string is not a string (error-id. domain-error). +func CharIndex(_, _ *environment.Environment, char, str ilos.Instance, startPosition ...ilos.Instance) (ilos.Instance, ilos.Instance) { + if !instance.Of(class.Character, char) { + return nil, instance.New(class.DomainError, map[string]ilos.Instance{ + "OBJECT": char, + "EXPECTED-CLASS": class.Character, + }) + } + if !instance.Of(class.String, str) { + return nil, instance.New(class.DomainError, map[string]ilos.Instance{ + "OBJECT": str, + "EXPECTED-CLASS": class.String, + }) + } + if len(startPosition) > 1 { + return nil, instance.New(class.ProgramError) + } + n := 0 + if len(startPosition) == 1 { + if !instance.Of(class.Integer, startPosition[0]) { + return nil, instance.New(class.DomainError, map[string]ilos.Instance{ + "OBJECT": startPosition[0], + "EXPECTED-CLASS": class.Integer, + }) + } + n = int(startPosition[0].(instance.Integer)) + } + s := string(str.(instance.String)[n:]) + c := rune(char.(instance.Character)) + i := strings.IndexRune(s, c) + if i < 0 { + return Nil, nil + } + return instance.New(class.Integer, i), nil +} + +// StringIndex returns the position of the given substring within string. The search starts +// from the position indicated by start-position (which is 0-based and defaults to 0). +// The value returned if the search succeeds is an offset from the beginning of the string, +// not from the starting point. If that substring does not occur in the string, nil is returned. +// Presence of the substring is done by sequential use of char= on corresponding elements of the two strings. +// +// An error shall be signaled if either substring or string is not a string (error-id. domain-error). +func StringIndex(_, _ *environment.Environment, sub, str ilos.Instance, startPosition ...ilos.Instance) (ilos.Instance, ilos.Instance) { + if !instance.Of(class.String, sub) { + return nil, instance.New(class.DomainError, map[string]ilos.Instance{ + "OBJECT": sub, + "EXPECTED-CLASS": class.String, + }) + } + if !instance.Of(class.String, str) { + return nil, instance.New(class.DomainError, map[string]ilos.Instance{ + "OBJECT": str, + "EXPECTED-CLASS": class.String, + }) + } + if len(startPosition) > 1 { + return nil, instance.New(class.ProgramError) + } + n := 0 + if len(startPosition) == 1 { + if !instance.Of(class.Integer, startPosition[0]) { + return nil, instance.New(class.DomainError, map[string]ilos.Instance{ + "OBJECT": startPosition[0], + "EXPECTED-CLASS": class.Integer, + }) + } + n = int(startPosition[0].(instance.Integer)) + } + s := string(str.(instance.String)[n:]) + c := string(sub.(instance.String)) + i := strings.Index(s, c) + if i < 0 { + return Nil, nil + } + return instance.New(class.Integer, i), nil +} + +// StringAppend returns a single string containing a sequence of characters that results +// from appending the sequences of characters of each of the strings, or "" if given no strings. +// An error shall be signaled if any string is not a string (error-id. domain-error). +// +// This function does not modify its arguments. It is implementation defined whether and +// when the result shares structure with its string arguments. +// +// An error shall be signaled if the string cannot be allocated (error-id. cannot-create-string). +func StringAppend(_, _ *environment.Environment, str ...ilos.Instance) (ilos.Instance, ilos.Instance) { + ret := "" + for _, s := range str { + if !instance.Of(class.String, s) { + return nil, instance.New(class.DomainError, map[string]ilos.Instance{ + "OBJECT": s, + "EXPECTED-CLASS": class.String, + }) + } + ret += string(s.(instance.String)) + } + return instance.New(class.String, ret), nil +} From 04b48497d30a8a85a1ed978aee40265a6ab8983f Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Sun, 13 Aug 2017 12:04:40 +0900 Subject: [PATCH 157/228] Removed TODOs --- runtime/character_class.go | 2 -- runtime/string_class.go | 2 -- 2 files changed, 4 deletions(-) diff --git a/runtime/character_class.go b/runtime/character_class.go index 1ecfc59..db18c1c 100644 --- a/runtime/character_class.go +++ b/runtime/character_class.go @@ -11,8 +11,6 @@ import ( "github.com/ta2gch/iris/runtime/ilos/instance" ) -//TODO: char<, char>, char<=, char>= - // Characterp returns t if obj is a character (instance of class character); // otherwise, returns nil. obj may be any ISLISP object. func Characterp(_, _ *environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { diff --git a/runtime/string_class.go b/runtime/string_class.go index b658cff..3f159b1 100644 --- a/runtime/string_class.go +++ b/runtime/string_class.go @@ -13,8 +13,6 @@ import ( "github.com/ta2gch/iris/runtime/ilos/instance" ) -// TODO: stringp, create-string, string=, string/=, string<, string>, string>=, string <=, char-index, string-append - // Stringp returns t if obj is a string (instance of class string); // otherwise, returns nil. obj may be any ISLISP object. func Stringp(_, _ *environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { From 5d62974f5b4558e7f9d7a226970c6937d10c1db9 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Sun, 13 Aug 2017 15:54:29 +0900 Subject: [PATCH 158/228] Added convSlice --- runtime/conditional_expressions.go | 59 +++++++++++++++++++++++ runtime/functions.go | 76 +++++++++++------------------- runtime/namedfunc.go | 32 ++++++++++--- runtime/util.go | 12 +++++ runtime/variables.go | 22 +++++---- 5 files changed, 138 insertions(+), 63 deletions(-) diff --git a/runtime/conditional_expressions.go b/runtime/conditional_expressions.go index c865c2a..d695d78 100644 --- a/runtime/conditional_expressions.go +++ b/runtime/conditional_expressions.go @@ -4,4 +4,63 @@ package runtime +import ( + "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/ilos" + "github.com/ta2gch/iris/runtime/ilos/class" + "github.com/ta2gch/iris/runtime/ilos/instance" +) + // TODO: if, cond, case, case-using + +// If is conditional expression. +// The test-form is evaluated. If its result is anything non-nil, +// the then-form is evaluated and its value is returned; +// otherwise (if the test-form returned nil), the else-form +// is evaluated and its value is returned. +// +// If no else-form is provided, it defaults to nil. +func If(local, global *environment.Environment, testForm, thenForm ilos.Instance, elseForm ...ilos.Instance) (ilos.Instance, ilos.Instance) { + tf, err := Eval(local, global, testForm) + if err != nil { + return nil, err + } + if tf == T { + return Eval(local, global, thenForm) + } + if len(elseForm) > 1 { + return nil, instance.New(class.ProgramError) + } + if len(elseForm) == 0 { + return Nil, nil + } + return Eval(local, global, elseForm[0]) +} + +func Cond(local, global *environment.Environment, testFrom ...ilos.Instance) (ilos.Instance, ilos.Instance) { + for _, tf := range testFrom { + s, ln, err := convSlice(tf) + if err != nil { + return nil, err + } + if ln == 0 { + return nil, instance.New(class.ProgramError) + } + ret, err := Eval(local, global, s[0]) + if err != nil { + return nil, err + } + if ret == T { + var err ilos.Instance + ret := Nil + for _, e := range s[1:] { + ret, err = Eval(local, global, e) + if err != nil { + return nil, err + } + } + return ret, nil + } + } + return Nil, nil +} diff --git a/runtime/functions.go b/runtime/functions.go index 7b010d3..87937ff 100644 --- a/runtime/functions.go +++ b/runtime/functions.go @@ -51,32 +51,6 @@ func Function(local, global *environment.Environment, fun ilos.Instance) (ilos.I }) } -func checkLambdaList(lambdaList ilos.Instance) ilos.Instance { - cdr := lambdaList - ok := false - for instance.Of(class.Cons, cdr) { - cadr := instance.UnsafeCar(cdr) - cddr := instance.UnsafeCdr(cdr) - if !instance.Of(class.Symbol, cadr) { - break - } - if cadr == instance.New(class.Symbol, ":REST") || cadr == instance.New(class.Symbol, "&REST") { - if instance.Of(class.Cons, cddr) && instance.Of(class.Symbol, instance.UnsafeCar(cddr)) && instance.Of(class.Null, instance.UnsafeCdr(cddr)) { - ok = true - } - break - } - cdr = cddr - } - if !ok && cdr == Nil { - ok = true - } - if !ok { - return instance.New(class.ProgramError) - } - return nil -} - // Lambda special form creates a function object. // // The scope of the identifiers of the lambda-list is the sequence of forms form*, @@ -105,7 +79,7 @@ func Lambda(local, global *environment.Environment, lambdaList ilos.Instance, fo if err := checkLambdaList(lambdaList); err != nil { return nil, err } - return newNamedFunction(local, global, instance.New(class.Symbol, "ANONYMOUS-FUNCTION"), lambdaList, form...), nil + return newNamedFunction(local, global, instance.New(class.Symbol, "ANONYMOUS-FUNCTION"), lambdaList, form...) } // Labels special form allow the definition of new identifiers in the function @@ -132,9 +106,11 @@ func Lambda(local, global *environment.Environment, lambdaList ilos.Instance, fo // // No function-name may appear more than once in the function bindings. func Labels(local, global *environment.Environment, functions ilos.Instance, bodyForm ...ilos.Instance) (ilos.Instance, ilos.Instance) { - cdr := functions - for instance.Of(class.Cons, cdr) { - cadr := instance.UnsafeCar(cdr) // Checked at the top of this loop + cdr, _, err := convSlice(functions) + if err != nil { + return nil, err + } + for _, cadr := range cdr { if !instance.Of(class.Cons, cadr) { // #1 return nil, instance.New(class.ProgramError) } @@ -151,19 +127,19 @@ func Labels(local, global *environment.Environment, functions ilos.Instance, bod if !isProperList(cddadr) { return nil, instance.New(class.ProgramError) } - form := []ilos.Instance{} - for instance.Of(class.Cons, cddadr) { - caddadr := instance.UnsafeCar(cddadr) // Checked at the top of this loop - form = append(form, caddadr) - cddadr = instance.UnsafeCdr(cddadr) // Checked at the top of this loop + form, _, err := convSlice(cddadr) + if err != nil { + return nil, err } - if local.Function.Define(functionName, newNamedFunction(local, global, functionName, lambdaList, form...)) { + fun, err := newNamedFunction(local, global, functionName, lambdaList, form...) + if err != nil { + return nil, err + } + if local.Function.Define(functionName, fun) { return nil, instance.New(class.ProgramError) } - cdr = instance.UnsafeCdr(cdr) // Checked at #1 } ret := Nil - var err ilos.Instance for _, form := range bodyForm { ret, err = Eval(local, global, form) if err != nil { @@ -176,7 +152,10 @@ func Labels(local, global *environment.Environment, functions ilos.Instance, bod // Flet special form allow the definition of new identifiers in the function // namespace for function objects (see Labels). func Flet(local, global *environment.Environment, functions ilos.Instance, bodyForm ...ilos.Instance) (ilos.Instance, ilos.Instance) { - cdr := functions + cdr, _, err := convSlice(functions) + if err != nil { + return nil, err + } env := environment.New() env.BlockTag = append(local.BlockTag, env.BlockTag...) env.TagbodyTag = append(local.TagbodyTag, env.TagbodyTag...) @@ -186,8 +165,7 @@ func Flet(local, global *environment.Environment, functions ilos.Instance, bodyF env.Special = append(local.Special, env.Special...) env.Macro = append(local.Macro, env.Macro...) env.DynamicVariable = append(local.DynamicVariable, env.DynamicVariable...) - for instance.Of(class.Cons, cdr) { - cadr := instance.UnsafeCar(cdr) // Checked at the top of this loop + for _, cadr := range cdr { if !instance.Of(class.Cons, cadr) { // #1 return nil, instance.New(class.ProgramError) } @@ -204,19 +182,19 @@ func Flet(local, global *environment.Environment, functions ilos.Instance, bodyF if !isProperList(cddadr) { return nil, instance.New(class.ProgramError) } - form := []ilos.Instance{} - for instance.Of(class.Cons, cddadr) { - caddadr := instance.UnsafeCar(cddadr) // Checked at the top of this loop - form = append(form, caddadr) - cddadr = instance.UnsafeCdr(cddadr) // Checked at the top of this loop + form, _, err := convSlice(cddadr) + if err != nil { + return nil, err + } + fun, err := newNamedFunction(local, global, functionName, lambdaList, form...) + if err != nil { + return nil, err } - if env.Function.Define(functionName, newNamedFunction(local, global, functionName, lambdaList, form...)) { + if local.Function.Define(functionName, fun) { return nil, instance.New(class.ProgramError) } - cdr = instance.UnsafeCdr(cdr) // Checked at #1 } ret := Nil - var err ilos.Instance for _, form := range bodyForm { ret, err = Eval(env, global, form) if err != nil { diff --git a/runtime/namedfunc.go b/runtime/namedfunc.go index 9615dc3..b3c6bb1 100644 --- a/runtime/namedfunc.go +++ b/runtime/namedfunc.go @@ -11,18 +11,38 @@ import ( "github.com/ta2gch/iris/runtime/ilos/instance" ) -func newNamedFunction(local, global *environment.Environment, functionName, lambdaList ilos.Instance, forms ...ilos.Instance) ilos.Instance { +func checkLambdaList(lambdaList ilos.Instance) ilos.Instance { + cdr, _, err := convSlice(lambdaList) + if err != nil { + return err + } + for i, cadr := range cdr { + if !instance.Of(class.Symbol, cadr) { + return instance.New(class.ProgramError) + } + if cadr == instance.New(class.Symbol, ":REST") || cadr == instance.New(class.Symbol, "&REST") { + if len(cdr) != i+2 { + return instance.New(class.ProgramError) + } + } + } + return nil +} + +func newNamedFunction(local, global *environment.Environment, functionName, lambdaList ilos.Instance, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { lexical := local - cdr := lambdaList + // TODO: Check lambdalist + if err := checkLambdaList(lambdaList); err != nil { + return nil, err + } + cdr, _, _ := convSlice(lambdaList) parameters := []ilos.Instance{} variadic := false - for instance.Of(class.Cons, cdr) { - cadr := instance.UnsafeCar(cdr) // Checked at the top of this loop + for _, cadr := range cdr { if cadr == instance.New(class.Symbol, ":REST") || cadr == instance.New(class.Symbol, "&REST") { variadic = true } parameters = append(parameters, cadr) - cdr = instance.UnsafeCdr(cdr) // Checked at the top of this loop } return instance.New(class.Function, functionName, func(local, global *environment.Environment, arguments ...ilos.Instance) (ilos.Instance, ilos.Instance) { local.BlockTag = append(lexical.BlockTag, local.BlockTag...) @@ -67,5 +87,5 @@ func newNamedFunction(local, global *environment.Environment, functionName, lamb } } return ret, nil - }) + }), nil } diff --git a/runtime/util.go b/runtime/util.go index b482817..ca2cea5 100644 --- a/runtime/util.go +++ b/runtime/util.go @@ -16,6 +16,18 @@ import ( "github.com/ta2gch/iris/runtime/ilos/instance" ) +func convSlice(cons ilos.Instance) ([]ilos.Instance, int, ilos.Instance) { + is := []ilos.Instance{} + if isProperList(cons) { + return nil, 0, instance.New(class.ProgramError) + } + for instance.Of(class.Cons, cons) { + is = append(is, instance.UnsafeCar(cons)) + cons = instance.UnsafeCdr(cons) + } + return is, len(is), nil +} + func isProperList(i ilos.Instance) bool { if instance.Of(class.Cons, i) { return isProperList(instance.UnsafeCdr(i)) // Checked at the top of this statements diff --git a/runtime/variables.go b/runtime/variables.go index 61664d9..d4a50fd 100644 --- a/runtime/variables.go +++ b/runtime/variables.go @@ -56,15 +56,18 @@ func Let(local, global *environment.Environment, varForm ilos.Instance, bodyForm for instance.Of(class.Cons, cdr) { uCar, uCdr := instance.UnsafeCar, instance.UnsafeCdr cadr, cddr := uCar(cdr), uCdr(cdr) // Checked at the top of this loop - if !(instance.Of(class.Cons, cadr) && instance.Of(class.Cons, uCdr(cadr)) && uCdr(uCdr(cadr)) == Nil) { + s, ln, err := convSlice(cadr) + if err != nil { + return nil, err + } + if ln != 2 { return nil, instance.New(class.ProgramError) } - v := uCar(cadr) // Checked before statement - f, err := Eval(local, global, uCar(uCdr(cadr))) + f, err := Eval(local, global, s[1]) if err != nil { return nil, err } - vfs[v] = f + vfs[s[0]] = f cdr = cddr } for v, f := range vfs { @@ -102,15 +105,18 @@ func LetStar(local, global *environment.Environment, varForm ilos.Instance, body for instance.Of(class.Cons, cdr) { uCar, uCdr := instance.UnsafeCar, instance.UnsafeCdr cadr, cddr := uCar(cdr), uCdr(cdr) // Checked at the top of this loop - if !(instance.Of(class.Cons, cadr) && instance.Of(class.Cons, uCdr(cadr)) && uCdr(uCdr(cadr)) == Nil) { + s, ln, err := convSlice(cadr) + if err != nil { + return nil, err + } + if ln != 2 { return nil, instance.New(class.ProgramError) } - v := uCar(cadr) // Checked before statement - f, err := Eval(local, global, uCar(uCdr(cadr))) + f, err := Eval(local, global, s[1]) if err != nil { return nil, err } - if local.Variable.Define(v, f) { + if local.Variable.Define(s[0], f) { return nil, instance.New(class.ProgramError) } cdr = cddr From d8fde584ce1d8f21a45e52d7fd7d23ed05bacdc5 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Sun, 13 Aug 2017 16:27:32 +0900 Subject: [PATCH 159/228] Added functions of section 14.4 --- runtime/conditional_expressions.go | 136 ++++++++++++++++++++++++++++- 1 file changed, 134 insertions(+), 2 deletions(-) diff --git a/runtime/conditional_expressions.go b/runtime/conditional_expressions.go index d695d78..d9a216f 100644 --- a/runtime/conditional_expressions.go +++ b/runtime/conditional_expressions.go @@ -11,8 +11,6 @@ import ( "github.com/ta2gch/iris/runtime/ilos/instance" ) -// TODO: if, cond, case, case-using - // If is conditional expression. // The test-form is evaluated. If its result is anything non-nil, // the then-form is evaluated and its value is returned; @@ -37,6 +35,12 @@ func If(local, global *environment.Environment, testForm, thenForm ilos.Instance return Eval(local, global, elseForm[0]) } +// Cond the clauses (test form*) are scanned sequentially +// and in each case the test is evaluated; when a test delivers a non-nil value +// the scanning process stops and all forms associated with the corresponding clause +//are sequentially evaluated and the value of the last one is returned. +// If no test is true, then nil is returned. +// If no form exists for the successful test then the value of this test is returned. func Cond(local, global *environment.Environment, testFrom ...ilos.Instance) (ilos.Instance, ilos.Instance) { for _, tf := range testFrom { s, ln, err := convSlice(tf) @@ -64,3 +68,131 @@ func Cond(local, global *environment.Environment, testFrom ...ilos.Instance) (il } return Nil, nil } + +// Case special form, called case form, provide a mechanism +// to execute a matching clause from a series of clauses based on the value of a dispatching form keyform. +// +// The clause to be executed is identified by a set of keys. A key can be any object. +// If the keylist of the last clause is t the associated clause is executed if no key matches the keyform. +// +// keyform is a form to be computed at the beginning of execution of the case form. +// If the result of evaluating keyform is equivalent to a key, then the forms, if any, +// in the corresponding clause are evaluated sequentially and the value of the last one +// is returned as value of the whole case form. case determines match equivalence by using eql; +// the value returned by keyform and key. If no form exists for a matching key, the case form evaluates to nil. +// If the value of keyform is different from every key, and there is a default clause, its forms, if any, +// are evaluated sequentially, and the value of the last one is the result of the case form. +func Case(local, global *environment.Environment, key ilos.Instance, pattern ...ilos.Instance) (ilos.Instance, ilos.Instance) { + key, err := Eval(local, global, key) + if err != nil { + return nil, err + } + for idx, pat := range pattern { + form, ln, err := convSlice(pat) + if err != nil { + return nil, err + } + if ln < 1 { + return nil, instance.New(class.ProgramError) + } + if idx == len(pattern)-1 && form[0] == T { + var err ilos.Instance + ret := Nil + for _, e := range form[1:] { + ret, err = Eval(local, global, e) + if err != nil { + return nil, err + } + } + return ret, nil + } + keys, _, err := convSlice(form[0]) + if err != nil { + return nil, err + } + for _, k := range keys { + if k == key { + var err ilos.Instance + ret := Nil + for _, e := range form[1:] { + ret, err = Eval(local, global, e) + if err != nil { + return nil, err + } + } + return ret, nil + } + } + } + return Nil, nil +} + +// CaseUsing special form, called case forms, provide a mechanism +// to execute a matching clause from a series of clauses based on the value of a dispatching form keyform. +// +// The clause to be executed is identified by a set of keys. A key can be any object. +// If the keylist of the last clause is t the associated clause is executed if no key matches the keyform. +// +// keyform is a form to be computed at the beginning of execution of the case form. +// If the result of evaluating keyform is equivalent to a key, then the forms, if any, +// in the corresponding clause are evaluated sequentially and the value of the last one +// is returned as value of the whole case form. +// case-using match determines equivalence by using the result of evaluating predform. +// predform must be a boolean or quasi-boolean function that accepts two arguments, +// the value returned by keyform and key. If no form exists for a matching key, the case form evaluates to nil. +// If the value of keyform is different from every key, and there is a default clause, its forms, if any, +// are evaluated sequentially, and the value of the last one is the result of the case form. +func CaseUsing(local, global *environment.Environment, key, pred ilos.Instance, pattern ...ilos.Instance) (ilos.Instance, ilos.Instance) { + key, err := Eval(local, global, key) + if err != nil { + return nil, err + } + if !instance.Of(class.Function, pred) { + return nil, instance.New(class.DomainError, map[string]ilos.Instance{ + "OBJECT": pred, + "EXPECTED-CLASS": instance.New(class.Symbol, "FUNCTION"), + }) + } + for idx, pat := range pattern { + form, ln, err := convSlice(pat) + if err != nil { + return nil, err + } + if ln < 1 { + return nil, instance.New(class.ProgramError) + } + if idx == len(pattern)-1 && form[0] == T { + var err ilos.Instance + ret := Nil + for _, e := range form[1:] { + ret, err = Eval(local, global, e) + if err != nil { + return nil, err + } + } + return ret, nil + } + keys, _, err := convSlice(form[0]) + if err != nil { + return nil, err + } + for _, k := range keys { + ret, err := pred.(instance.Function).Apply(local, global, instance.New(class.Cons, k, instance.New(class.Cons, key, Nil))) + if err != nil { + return nil, err + } + if ret != Nil { + var err ilos.Instance + ret := Nil + for _, e := range form[1:] { + ret, err = Eval(local, global, e) + if err != nil { + return nil, err + } + } + return ret, nil + } + } + } + return Nil, nil +} From 2911f1cf908da252a4da2fd2e46b05d47bda4a4e Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Sun, 13 Aug 2017 16:38:26 +0900 Subject: [PATCH 160/228] Added Progn --- runtime/namedfunc.go | 1 - runtime/sequencing_forms.go | 22 +++++++++++++++++++++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/runtime/namedfunc.go b/runtime/namedfunc.go index b3c6bb1..c78cea0 100644 --- a/runtime/namedfunc.go +++ b/runtime/namedfunc.go @@ -31,7 +31,6 @@ func checkLambdaList(lambdaList ilos.Instance) ilos.Instance { func newNamedFunction(local, global *environment.Environment, functionName, lambdaList ilos.Instance, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { lexical := local - // TODO: Check lambdalist if err := checkLambdaList(lambdaList); err != nil { return nil, err } diff --git a/runtime/sequencing_forms.go b/runtime/sequencing_forms.go index 2c338c7..d1e5269 100644 --- a/runtime/sequencing_forms.go +++ b/runtime/sequencing_forms.go @@ -4,4 +4,24 @@ package runtime -// TODO: progn +import ( + "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/ilos" +) + +// Progn allows a series of forms to be evaluated, where normally only one could be used. +// +// The result of evaluation of the last form of form* is returned. All the forms are +// evaluated from left to right. The values of all the forms but the last are discarded, +// so they are executed only for their side-effects. progn without forms returns nil. +func Progn(local, global *environment.Environment, form ...ilos.Instance) (ilos.Instance, ilos.Instance) { + var err ilos.Instance + ret := Nil + for _, e := range form { + ret, err = Eval(local, global, e) + if err != nil { + return nil, err + } + } + return ret, nil +} From 34fcda608af5f4739088b842ae45b4574ad57d92 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Sun, 13 Aug 2017 17:05:44 +0900 Subject: [PATCH 161/228] Added Eq, Eql, Equal --- runtime/equality.go | 41 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/runtime/equality.go b/runtime/equality.go index f172c63..9210ee8 100644 --- a/runtime/equality.go +++ b/runtime/equality.go @@ -4,4 +4,43 @@ package runtime -// TODO: eq, eql, equal +import ( + "reflect" + + "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/ilos" +) + +// Eq tests whether obj1 and obj2 are same identical object. +// They return t if the objects are the same; otherwise, they return nil. +// Two objects are the same if there is no operation that could distinguish +// them (without modifying them), and if modifying one would modify the other the same way. +func Eq(_, _ *environment.Environment, obj1, obj2 ilos.Instance) (ilos.Instance, ilos.Instance) { + if obj1 == obj2 { + return T, nil + } + return Nil, nil +} + +// Eql tests whether obj1 and obj2 are same identical object. +// They return t if the objects are the same; otherwise, they return nil. +// Two objects are the same if there is no operation that could distinguish +// them (without modifying them), and if modifying one would modify the other the same way. +func Eql(_, _ *environment.Environment, obj1, obj2 ilos.Instance) (ilos.Instance, ilos.Instance) { + if obj1 == obj2 { + return T, nil + } + return Nil, nil +} + +// Equal tests whether obj1 and obj2 are isomorphic—i.e., whether obj1 and obj2 denote the same +// structure with equivalent values. equal returns t if the test was satisfied, and nil if not. +// Specifically: +// +// If obj1 and obj2 are direct instances of the same class, equal returns t if they are eql. +func Equal(_, _ *environment.Environment, obj1, obj2 ilos.Instance) (ilos.Instance, ilos.Instance) { + if reflect.DeepEqual(obj1, obj2) { + return T, nil + } + return Nil, nil +} From 0069aee1c1f41be7b31d65108ffbec10aaadc495 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Sun, 13 Aug 2017 18:14:43 +0900 Subject: [PATCH 162/228] Added functins for iterations --- runtime/iteration.go | 116 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 115 insertions(+), 1 deletion(-) diff --git a/runtime/iteration.go b/runtime/iteration.go index e0aad44..25a991d 100644 --- a/runtime/iteration.go +++ b/runtime/iteration.go @@ -4,4 +4,118 @@ package runtime -// TODO: while, for +import ( + "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/ilos" + "github.com/ta2gch/iris/runtime/ilos/class" + "github.com/ta2gch/iris/runtime/ilos/instance" +) + +// While the test-form returns a true value. Specifically: +// +// 1. test-form is evaluated, producing a value Vt. +// +// 2. If Vt is nil, then the while form immediately returns nil. +// +// 3. Otherwise, if Vt is non-nil, the forms body-form* are evaluated sequentially (from left to right). +// +// 4. Upon successful completion of the body-forms*, the while form begins again with step 1. +func While(local, global *environment.Environment, testForm ilos.Instance, bodyForm ...ilos.Instance) (ilos.Instance, ilos.Instance) { + test, err := Eval(local, global, testForm) + for test == T { + for _, form := range bodyForm { + _, err = Eval(local, global, form) + if err != nil { + return nil, err + } + } + test, err = Eval(local, global, testForm) + if err != nil { + return nil, err + } + } + return Nil, nil +} + +// For repeatedly executes a sequence of forms form*, called its body. It specifies a set of identifiers naming +// variables that will be local to the for form, their initialization, and their update for each iteration. +// When a termination condition is met, the iteration exits with a specified result value. +// +// The scope of an identifier var is the body, the steps, the end-test , and the result *. A step might be omitted, +// in which case the effect is the same as if (var init var) had been written instead of (var init). +// It is a violation if more than one iteration-spec names the same var in the same for form. +// +// The for special form is executed as follows: The init forms are evaluated sequentially from left to right. +// Then each value is used as the initial value of the variable denoted by the corresponding identifier var , +// and the iteration phase begins. +// +//Each iteration begins by evaluating end-test . If the result is nil, the forms in the body are +// evaluated sequentially (for side-effects). Afterwards, the step-forms are evaluated sequentially +// order from left to right. Then their values are assigned to the corresponding variables and the next iteration begins. +// If end-test returns a non-nil value, then the result * are evaluated sequentially and the value of the +// last one is returned as value of the whole for macro. If no result is present, then the value of the for macro is nil. +func For(local, global *environment.Environment, iterationSpecs, endTestAndResults ilos.Instance, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { + iss, _, err := convSlice(iterationSpecs) + if err != nil { + return nil, err + } + for _, is := range iss { + i, ln, err := convSlice(is) + if err != nil { + return nil, err + } + switch ln { + case 2, 3: + var1 := i[0] + init := i[1] + if local.Variable.Define(var1, init) { + return nil, instance.New(class.ProgramError) + } + default: + return nil, instance.New(class.ProgramError) + } + } + ends, ln, err := convSlice(endTestAndResults) + if err != nil { + return nil, err + } + if ln == 0 { + return nil, instance.New(class.ParseError) + } + endTest := ends[0] + results := ends[1:] + test, err := Eval(local, global, endTest) + if err != nil { + return nil, err + } + for test == Nil { + for _, form := range forms { + _, err = Eval(local, global, form) + if err != nil { + return nil, err + } + } + for _, is := range iss { + i, ln, err := convSlice(is) + if err != nil { + return nil, err + } + switch ln { + case 2: + case 3: + var1 := i[0] + step := i[2] + if local.Variable.Set(var1, step) { + return nil, instance.New(class.ProgramError) + } + default: + return nil, instance.New(class.ProgramError) + } + } + test, err = Eval(local, global, endTest) + if err != nil { + return nil, err + } + } + return Progn(local, global, results...) +} From 2034bd95fdf65f9f2470cbd55843ef7c33af0a61 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Sun, 13 Aug 2017 18:28:13 +0900 Subject: [PATCH 163/228] bugfix for Define --- runtime/functions.go | 4 ++-- runtime/iteration.go | 2 +- runtime/namedfunc.go | 4 ++-- runtime/non-local_exits.go | 6 +++--- runtime/variables.go | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/runtime/functions.go b/runtime/functions.go index 87937ff..226a07e 100644 --- a/runtime/functions.go +++ b/runtime/functions.go @@ -135,7 +135,7 @@ func Labels(local, global *environment.Environment, functions ilos.Instance, bod if err != nil { return nil, err } - if local.Function.Define(functionName, fun) { + if !local.Function.Define(functionName, fun) { return nil, instance.New(class.ProgramError) } } @@ -190,7 +190,7 @@ func Flet(local, global *environment.Environment, functions ilos.Instance, bodyF if err != nil { return nil, err } - if local.Function.Define(functionName, fun) { + if !local.Function.Define(functionName, fun) { return nil, instance.New(class.ProgramError) } } diff --git a/runtime/iteration.go b/runtime/iteration.go index 25a991d..07deb90 100644 --- a/runtime/iteration.go +++ b/runtime/iteration.go @@ -68,7 +68,7 @@ func For(local, global *environment.Environment, iterationSpecs, endTestAndResul case 2, 3: var1 := i[0] init := i[1] - if local.Variable.Define(var1, init) { + if !local.Variable.Define(var1, init) { return nil, instance.New(class.ProgramError) } default: diff --git a/runtime/namedfunc.go b/runtime/namedfunc.go index c78cea0..6ec712d 100644 --- a/runtime/namedfunc.go +++ b/runtime/namedfunc.go @@ -67,13 +67,13 @@ func newNamedFunction(local, global *environment.Environment, functionName, lamb for i := len(arguments) - 1; i >= idx; i-- { value = instance.New(class.Cons, arguments[i], value) } - if local.Variable.Define(key, value) { + if !local.Variable.Define(key, value) { return nil, instance.New(class.ProgramError) } break } value := arguments[idx] - if local.Variable.Define(key, value) { + if !local.Variable.Define(key, value) { return nil, instance.New(class.ProgramError) } } diff --git a/runtime/non-local_exits.go b/runtime/non-local_exits.go index d0431c0..e890457 100644 --- a/runtime/non-local_exits.go +++ b/runtime/non-local_exits.go @@ -50,7 +50,7 @@ func Block(local, global *environment.Environment, tag ilos.Instance, body ...il "EXPECTED-CLASS": class.Object, }) } - if local.BlockTag.Define(tag, nil) { + if !local.BlockTag.Define(tag, nil) { return nil, instance.New(class.ProgramError) } var fail ilos.Instance @@ -108,7 +108,7 @@ func Catch(local, global *environment.Environment, tag ilos.Instance, body ...il if instance.Of(class.Number, tag) || instance.Of(class.Character, tag) { return nil, instance.New(class.DomainError, tag, class.Object) } - if local.CatchTag.Define(tag, nil) { + if !local.CatchTag.Define(tag, nil) { return nil, instance.New(class.ProgramError) } var fail ilos.Instance @@ -161,7 +161,7 @@ func Tagbody(local, global *environment.Environment, body ...ilos.Instance) (ilo for idx, cadr := range body { cddr := instance.New(class.GeneralVector, body[idx+1:]) if !instance.Of(class.Cons, cadr) { - if local.TagbodyTag.Define(cadr, cddr) { + if !local.TagbodyTag.Define(cadr, cddr) { return nil, instance.New(class.ProgramError) } } diff --git a/runtime/variables.go b/runtime/variables.go index d4a50fd..42becc1 100644 --- a/runtime/variables.go +++ b/runtime/variables.go @@ -71,7 +71,7 @@ func Let(local, global *environment.Environment, varForm ilos.Instance, bodyForm cdr = cddr } for v, f := range vfs { - if local.Variable.Define(v, f) { + if !local.Variable.Define(v, f) { return nil, instance.New(class.ProgramError) } } @@ -116,7 +116,7 @@ func LetStar(local, global *environment.Environment, varForm ilos.Instance, body if err != nil { return nil, err } - if local.Variable.Define(s[0], f) { + if !local.Variable.Define(s[0], f) { return nil, instance.New(class.ProgramError) } cdr = cddr From 9501d1da777b5e0ff415279a8d6ae6f2c9a140ea Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Sun, 13 Aug 2017 18:52:02 +0900 Subject: [PATCH 164/228] Added define-operators --- runtime/defining_operators.go | 104 ++++++++++++++++++++++++++++- runtime/environment/environment.go | 15 +++++ runtime/eval.go | 13 ++-- runtime/functions.go | 10 +-- runtime/namedfunc.go | 9 +-- 5 files changed, 124 insertions(+), 27 deletions(-) diff --git a/runtime/defining_operators.go b/runtime/defining_operators.go index 00d95a8..c212c38 100644 --- a/runtime/defining_operators.go +++ b/runtime/defining_operators.go @@ -4,4 +4,106 @@ package runtime -// TODO: defconstant, defglobal, defdynamic, defun +import ( + "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/ilos" + "github.com/ta2gch/iris/runtime/ilos/class" + "github.com/ta2gch/iris/runtime/ilos/instance" +) + +// Defconstant is used to define a named constant in the variable namespace of the current toplevel +// scope. The scope of name is the entire current toplevel scope except the body form. +// +// Although name is globally constant, a variable binding for name can be locally established by a +// binding form. +// +// The result of the evaluation of form is bound to the variable named by name. The binding and +// the object created as the result of evaluating the second argument are immutable. The symbol named +// name is returned. +func Defconstant(local, global *environment.Environment, name, form ilos.Instance) (ilos.Instance, ilos.Instance) { + if !instance.Of(class.Symbol, name) { + return nil, instance.New(class.DomainError, map[string]ilos.Instance{ + "OBJECT": name, + "EXPECTED-CLASS": class.Symbol, + }) + } + ret, err := Eval(local, global, form) + if err != nil { + return nil, err + } + if !global.Constant.Define(name, ret) { + return nil, instance.New(class.ProgramError) + } + return name, nil +} + +// Defglobal is used to define an identifier in the variable namespace of the current toplevel scope. +// The scope of name is the entire current toplevel scope except the body form. +// +// form is evaluated to compute an initializing value for the variable named name. Therefore, +// defglobal is used only for defining variables and not for modifying them. The symbol named name is +// returned. +// +// A lexical variable binding for name can still be locally established by a binding form; in that +// case, the local binding lexically shadows the outer binding of name defined by defglobal. +func Defglobal(local, global *environment.Environment, name, form ilos.Instance) (ilos.Instance, ilos.Instance) { + if !instance.Of(class.Symbol, name) { + return nil, instance.New(class.DomainError, map[string]ilos.Instance{ + "OBJECT": name, + "EXPECTED-CLASS": class.Symbol, + }) + } + ret, err := Eval(local, global, form) + if err != nil { + return nil, err + } + if _, ok := global.Constant.Get(name); ok { + return nil, instance.New(class.ProgramError) + } + if !global.Variable.Define(name, ret) { + return nil, instance.New(class.ProgramError) + } + return name, nil +} + +// Defdynamic is used to define a dynamic variable identifier in the dynamic variable namespace. +// The scope of name is the entire current toplevel scope except the body form. +// +//The symbol named name is returned. +func Defdynamic(local, global *environment.Environment, name, form ilos.Instance) (ilos.Instance, ilos.Instance) { + if !instance.Of(class.Symbol, name) { + return nil, instance.New(class.DomainError, map[string]ilos.Instance{ + "OBJECT": name, + "EXPECTED-CLASS": class.Symbol, + }) + } + ret, err := Eval(local, global, form) + if err != nil { + return nil, err + } + if !global.DynamicVariable.Define(name, ret) { + return nil, instance.New(class.ProgramError) + } + return name, nil +} + +// Defun defines function-name as an identifier in the function namespace; function-name is +// bound to a function object equivalent to (lambda lambda-list form*). +// +// The scope of function-name is the whole current toplevel scope. Therefore, the definition of a +// function admits recursion, occurrences of function-name within the form* refer to the function +// being defined. The binding between function-name and the function object is immutable. +// +// defun returns the function name which is the symbol named function-name. The free identifiers in +// the body form* (i.e., those which are not contained in the lambda list) follow the rules of lexical +// scoping. +func Defun(local, global *environment.Environment, functionName, lambdaList ilos.Instance, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { + ret, err := newNamedFunction(local, global, functionName, lambdaList, forms...) + if err != nil { + return nil, err + } + if !global.Function.Define(functionName, ret) { + return nil, instance.New(class.ProgramError) + } + return functionName, nil +} diff --git a/runtime/environment/environment.go b/runtime/environment/environment.go index 14f87be..c6c7210 100644 --- a/runtime/environment/environment.go +++ b/runtime/environment/environment.go @@ -14,6 +14,7 @@ type Environment struct { Special stack Variable stack DynamicVariable stack // deep biding + Constant stack } // New creates new environment @@ -27,6 +28,20 @@ func New() *Environment { env.Special = newStack() env.Variable = newStack() env.DynamicVariable = newStack() + env.Constant = newStack() + return env +} + +func (env *Environment) Merge(before *Environment) *Environment { + env.BlockTag = append(before.BlockTag, env.BlockTag...) + env.TagbodyTag = append(before.TagbodyTag, env.TagbodyTag...) + env.CatchTag = append(before.CatchTag, env.CatchTag...) + env.Variable = append(before.Variable, env.Variable...) + env.Function = append(before.Function, env.Function...) + env.Special = append(before.Special, env.Special...) + env.Macro = append(before.Macro, env.Macro...) + env.DynamicVariable = append(before.DynamicVariable, env.DynamicVariable...) + env.Constant = append(before.Constant, env.Constant...) return env } diff --git a/runtime/eval.go b/runtime/eval.go index f73d061..758aa9f 100644 --- a/runtime/eval.go +++ b/runtime/eval.go @@ -71,15 +71,7 @@ func evalSpecial(local, global *environment.Environment, car, cdr ilos.Instance) spl = s } if spl != nil { - env := environment.New() - env.BlockTag = append(local.BlockTag, env.BlockTag...) - env.TagbodyTag = append(local.TagbodyTag, env.TagbodyTag...) - env.CatchTag = append(local.CatchTag, env.CatchTag...) - env.Variable = append(local.Variable, env.Variable...) - env.Function = append(local.Function, env.Function...) - env.Special = append(local.Special, env.Special...) - env.Macro = append(local.Macro, env.Macro...) - env.DynamicVariable = append(local.DynamicVariable, env.DynamicVariable...) + env := environment.New().Merge(local) ret, err := spl.(instance.Applicable).Apply(env, global, cdr) if err != nil { return nil, err, true @@ -182,6 +174,9 @@ func evalVariable(local, global *environment.Environment, obj ilos.Instance) (il if val, ok := global.Variable.Get(obj); ok { return val, nil } + if val, ok := global.Constant.Get(obj); ok { + return val, nil + } return nil, instance.New(class.UndefinedVariable, map[string]ilos.Instance{ "NAME": obj, "NAMESPACE": instance.New(class.Symbol, "VARIABLE"), diff --git a/runtime/functions.go b/runtime/functions.go index 226a07e..de2f338 100644 --- a/runtime/functions.go +++ b/runtime/functions.go @@ -156,15 +156,7 @@ func Flet(local, global *environment.Environment, functions ilos.Instance, bodyF if err != nil { return nil, err } - env := environment.New() - env.BlockTag = append(local.BlockTag, env.BlockTag...) - env.TagbodyTag = append(local.TagbodyTag, env.TagbodyTag...) - env.CatchTag = append(local.CatchTag, env.CatchTag...) - env.Variable = append(local.Variable, env.Variable...) - env.Function = append(local.Function, env.Function...) - env.Special = append(local.Special, env.Special...) - env.Macro = append(local.Macro, env.Macro...) - env.DynamicVariable = append(local.DynamicVariable, env.DynamicVariable...) + env := environment.New().Merge(local) for _, cadr := range cdr { if !instance.Of(class.Cons, cadr) { // #1 return nil, instance.New(class.ProgramError) diff --git a/runtime/namedfunc.go b/runtime/namedfunc.go index 6ec712d..8edd0f5 100644 --- a/runtime/namedfunc.go +++ b/runtime/namedfunc.go @@ -44,14 +44,7 @@ func newNamedFunction(local, global *environment.Environment, functionName, lamb parameters = append(parameters, cadr) } return instance.New(class.Function, functionName, func(local, global *environment.Environment, arguments ...ilos.Instance) (ilos.Instance, ilos.Instance) { - local.BlockTag = append(lexical.BlockTag, local.BlockTag...) - local.TagbodyTag = append(lexical.TagbodyTag, local.TagbodyTag...) - local.CatchTag = append(lexical.CatchTag, local.CatchTag...) - local.Variable = append(lexical.Variable, local.Variable...) - local.Function = append(lexical.Function, local.Function...) - local.Special = append(lexical.Special, local.Special...) - local.Macro = append(lexical.Macro, local.Macro...) - local.DynamicVariable = append(lexical.DynamicVariable, local.DynamicVariable...) + local.Merge(lexical) if (variadic && len(parameters)-2 > len(arguments)) || (!variadic && len(parameters) != len(arguments)) { v := Nil for i := len(arguments) - 1; i >= 0; i-- { From ba7df172eadebb6d7eb0af1dd3c53ae665fd2c20 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Sun, 13 Aug 2017 19:17:02 +0900 Subject: [PATCH 165/228] replace for to progn --- runtime/conditional_expressions.go | 50 +++--------------------------- runtime/functions.go | 18 ++--------- runtime/iteration.go | 19 ++++++------ runtime/namedfunc.go | 10 +----- runtime/variables.go | 20 ++---------- 5 files changed, 19 insertions(+), 98 deletions(-) diff --git a/runtime/conditional_expressions.go b/runtime/conditional_expressions.go index d9a216f..dcf47a0 100644 --- a/runtime/conditional_expressions.go +++ b/runtime/conditional_expressions.go @@ -55,15 +55,7 @@ func Cond(local, global *environment.Environment, testFrom ...ilos.Instance) (il return nil, err } if ret == T { - var err ilos.Instance - ret := Nil - for _, e := range s[1:] { - ret, err = Eval(local, global, e) - if err != nil { - return nil, err - } - } - return ret, nil + return Progn(local, global, s[1:]...) } } return Nil, nil @@ -96,15 +88,7 @@ func Case(local, global *environment.Environment, key ilos.Instance, pattern ... return nil, instance.New(class.ProgramError) } if idx == len(pattern)-1 && form[0] == T { - var err ilos.Instance - ret := Nil - for _, e := range form[1:] { - ret, err = Eval(local, global, e) - if err != nil { - return nil, err - } - } - return ret, nil + return Progn(local, global, form[1:]...) } keys, _, err := convSlice(form[0]) if err != nil { @@ -112,15 +96,7 @@ func Case(local, global *environment.Environment, key ilos.Instance, pattern ... } for _, k := range keys { if k == key { - var err ilos.Instance - ret := Nil - for _, e := range form[1:] { - ret, err = Eval(local, global, e) - if err != nil { - return nil, err - } - } - return ret, nil + return Progn(local, global, form[1:]...) } } } @@ -162,15 +138,7 @@ func CaseUsing(local, global *environment.Environment, key, pred ilos.Instance, return nil, instance.New(class.ProgramError) } if idx == len(pattern)-1 && form[0] == T { - var err ilos.Instance - ret := Nil - for _, e := range form[1:] { - ret, err = Eval(local, global, e) - if err != nil { - return nil, err - } - } - return ret, nil + return Progn(local, global, form[1:]...) } keys, _, err := convSlice(form[0]) if err != nil { @@ -182,15 +150,7 @@ func CaseUsing(local, global *environment.Environment, key, pred ilos.Instance, return nil, err } if ret != Nil { - var err ilos.Instance - ret := Nil - for _, e := range form[1:] { - ret, err = Eval(local, global, e) - if err != nil { - return nil, err - } - } - return ret, nil + return Progn(local, global, form[1:]...) } } } diff --git a/runtime/functions.go b/runtime/functions.go index de2f338..2638536 100644 --- a/runtime/functions.go +++ b/runtime/functions.go @@ -139,14 +139,7 @@ func Labels(local, global *environment.Environment, functions ilos.Instance, bod return nil, instance.New(class.ProgramError) } } - ret := Nil - for _, form := range bodyForm { - ret, err = Eval(local, global, form) - if err != nil { - return nil, err - } - } - return ret, nil + return Progn(local, global, bodyForm...) } // Flet special form allow the definition of new identifiers in the function @@ -186,14 +179,7 @@ func Flet(local, global *environment.Environment, functions ilos.Instance, bodyF return nil, instance.New(class.ProgramError) } } - ret := Nil - for _, form := range bodyForm { - ret, err = Eval(env, global, form) - if err != nil { - return nil, err - } - } - return ret, nil + return Progn(local, global, bodyForm...) } // Apply applies function to the arguments, obj*, followed by the elements of list, diff --git a/runtime/iteration.go b/runtime/iteration.go index 07deb90..05dcb63 100644 --- a/runtime/iteration.go +++ b/runtime/iteration.go @@ -22,12 +22,13 @@ import ( // 4. Upon successful completion of the body-forms*, the while form begins again with step 1. func While(local, global *environment.Environment, testForm ilos.Instance, bodyForm ...ilos.Instance) (ilos.Instance, ilos.Instance) { test, err := Eval(local, global, testForm) + if err != nil { + return nil, err + } for test == T { - for _, form := range bodyForm { - _, err = Eval(local, global, form) - if err != nil { - return nil, err - } + _, err := Progn(local, global, bodyForm...) + if err != nil { + return nil, err } test, err = Eval(local, global, testForm) if err != nil { @@ -89,11 +90,9 @@ func For(local, global *environment.Environment, iterationSpecs, endTestAndResul return nil, err } for test == Nil { - for _, form := range forms { - _, err = Eval(local, global, form) - if err != nil { - return nil, err - } + _, err := Progn(local, global, forms...) + if err != nil { + return nil, err } for _, is := range iss { i, ln, err := convSlice(is) diff --git a/runtime/namedfunc.go b/runtime/namedfunc.go index 8edd0f5..db25fd1 100644 --- a/runtime/namedfunc.go +++ b/runtime/namedfunc.go @@ -70,14 +70,6 @@ func newNamedFunction(local, global *environment.Environment, functionName, lamb return nil, instance.New(class.ProgramError) } } - ret := Nil - var err ilos.Instance - for _, form := range forms { - ret, err = Eval(local, global, form) - if err != nil { - return nil, err - } - } - return ret, nil + return Progn(local, global, forms...) }), nil } diff --git a/runtime/variables.go b/runtime/variables.go index 42becc1..5d9c023 100644 --- a/runtime/variables.go +++ b/runtime/variables.go @@ -75,15 +75,7 @@ func Let(local, global *environment.Environment, varForm ilos.Instance, bodyForm return nil, instance.New(class.ProgramError) } } - var err ilos.Instance - ret := Nil - for _, form := range bodyForm { - ret, err = Eval(local, global, form) - if err != nil { - return nil, err - } - } - return ret, nil + return Progn(local, global, bodyForm...) } // LetStar form is used to define a scope for a group of identifiers for a sequence @@ -121,13 +113,5 @@ func LetStar(local, global *environment.Environment, varForm ilos.Instance, body } cdr = cddr } - var err ilos.Instance - ret := Nil - for _, form := range bodyForm { - ret, err = Eval(local, global, form) - if err != nil { - return nil, err - } - } - return ret, nil + return Progn(local, global, bodyForm...) } From 8438dc95a305f5bbd810eae0eb2d6058c958411c Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Sun, 13 Aug 2017 20:41:45 +0900 Subject: [PATCH 166/228] Added ensure function --- runtime/character_class.go | 26 ++-------- runtime/conditional_expressions.go | 7 +-- runtime/cons.go | 28 +++------- runtime/defining_operators.go | 24 +++------ runtime/functions.go | 14 ++--- runtime/integer_class.go | 7 +-- runtime/number_class.go | 33 +++--------- runtime/string_class.go | 82 ++++++++---------------------- runtime/util.go | 11 ++++ 9 files changed, 64 insertions(+), 168 deletions(-) diff --git a/runtime/character_class.go b/runtime/character_class.go index db18c1c..cef8b89 100644 --- a/runtime/character_class.go +++ b/runtime/character_class.go @@ -22,17 +22,8 @@ func Characterp(_, _ *environment.Environment, obj ilos.Instance) (ilos.Instance // CharEqual tests whether char1 is the same character as char2. func CharEqual(_, _ *environment.Environment, char1, char2 ilos.Instance) (ilos.Instance, ilos.Instance) { - if !instance.Of(class.Character, char1) { - return nil, instance.New(class.DomainError, map[string]ilos.Instance{ - "OBJECT": char1, - "EXPECTED-CLASS": class.Character, - }) - } - if !instance.Of(class.Character, char2) { - return nil, instance.New(class.DomainError, map[string]ilos.Instance{ - "OBJECT": char2, - "EXPECTED-CLASS": class.Character, - }) + if err := ensure(class.Character, char1, char2); err != nil { + return nil, err } if char1 == char2 { return T, nil @@ -52,17 +43,8 @@ func CharNotEqual(_, _ *environment.Environment, char1, char2 ilos.Instance) (il // CharGreaterThan tests whether char1 is greater than char2. // An error shall be signaled if either char1 or char2 is not a character (error-id. domain-error). func CharGreaterThan(_, _ *environment.Environment, char1, char2 ilos.Instance) (ilos.Instance, ilos.Instance) { - if !instance.Of(class.Character, char1) { - return nil, instance.New(class.DomainError, map[string]ilos.Instance{ - "OBJECT": char1, - "EXPECTED-CLASS": class.Character, - }) - } - if !instance.Of(class.Character, char2) { - return nil, instance.New(class.DomainError, map[string]ilos.Instance{ - "OBJECT": char2, - "EXPECTED-CLASS": class.Character, - }) + if err := ensure(class.Character, char1, char2); err != nil { + return nil, err } if char1.(instance.Character) > char2.(instance.Character) { return T, nil diff --git a/runtime/conditional_expressions.go b/runtime/conditional_expressions.go index dcf47a0..89df440 100644 --- a/runtime/conditional_expressions.go +++ b/runtime/conditional_expressions.go @@ -123,11 +123,8 @@ func CaseUsing(local, global *environment.Environment, key, pred ilos.Instance, if err != nil { return nil, err } - if !instance.Of(class.Function, pred) { - return nil, instance.New(class.DomainError, map[string]ilos.Instance{ - "OBJECT": pred, - "EXPECTED-CLASS": instance.New(class.Symbol, "FUNCTION"), - }) + if err := ensure(class.Function, pred); err != nil { + return nil, err } for idx, pat := range pattern { form, ln, err := convSlice(pat) diff --git a/runtime/cons.go b/runtime/cons.go index 1702cdc..823f4a2 100644 --- a/runtime/cons.go +++ b/runtime/cons.go @@ -32,11 +32,8 @@ func Cons(_, _ *environment.Environment, obj1, obj2 ilos.Instance) (ilos.Instanc // Car returns the left component of the cons. // An error shall be signaled if cons is not a cons (error-id. domain-error). func Car(_, _ *environment.Environment, cons ilos.Instance) (ilos.Instance, ilos.Instance) { - if !instance.Of(class.Cons, cons) { - return nil, instance.New(class.DomainError, map[string]ilos.Instance{ - "OBJECT": cons, - "EXPECTED-CLASS": class.Cons, - }) + if err := ensure(class.Cons, cons); err != nil { + return nil, err } return instance.UnsafeCar(cons), nil // Checked at the top of this function } @@ -44,11 +41,8 @@ func Car(_, _ *environment.Environment, cons ilos.Instance) (ilos.Instance, ilos // Cdr returns the right component of the cons. // An error shall be signaled if cons is not a cons (error-id. domain-error). func Cdr(_, _ *environment.Environment, cons ilos.Instance) (ilos.Instance, ilos.Instance) { - if !instance.Of(class.Cons, cons) { - return nil, instance.New(class.DomainError, map[string]ilos.Instance{ - "OBJECT": cons, - "EXPECTED-CLASS": class.Cons, - }) + if err := ensure(class.Cons, cons); err != nil { + return nil, err } return instance.UnsafeCdr(cons), nil // Checked at the top of this function } @@ -59,11 +53,8 @@ func Cdr(_, _ *environment.Environment, cons ilos.Instance) (ilos.Instance, ilos // An error shall be signaled if cons is not a cons (error-id. domain-error). // obj may be any ISLISP object. func SetCar(_, _ *environment.Environment, obj, cons ilos.Instance) (ilos.Instance, ilos.Instance) { - if !instance.Of(class.Cons, cons) { - return nil, instance.New(class.DomainError, map[string]ilos.Instance{ - "OBJECT": cons, - "EXPECTED-CLASS": class.Cons, - }) + if err := ensure(class.Cons, cons); err != nil { + return nil, err } instance.UnsafeSetCar(obj, cons) return obj, nil @@ -75,11 +66,8 @@ func SetCar(_, _ *environment.Environment, obj, cons ilos.Instance) (ilos.Instan // An error shall be signaled if cons is not a cons (error-id. domain-error). // obj may be any ISLISP object. func SetCdr(_, _ *environment.Environment, obj, cons ilos.Instance) (ilos.Instance, ilos.Instance) { - if !instance.Of(class.Cons, cons) { - return nil, instance.New(class.DomainError, map[string]ilos.Instance{ - "OBJECT": cons, - "EXPECTED-CLASS": class.Cons, - }) + if err := ensure(class.Cons, cons); err != nil { + return nil, err } instance.UnsafeSetCdr(obj, cons) return obj, nil diff --git a/runtime/defining_operators.go b/runtime/defining_operators.go index c212c38..34d4511 100644 --- a/runtime/defining_operators.go +++ b/runtime/defining_operators.go @@ -21,11 +21,8 @@ import ( // the object created as the result of evaluating the second argument are immutable. The symbol named // name is returned. func Defconstant(local, global *environment.Environment, name, form ilos.Instance) (ilos.Instance, ilos.Instance) { - if !instance.Of(class.Symbol, name) { - return nil, instance.New(class.DomainError, map[string]ilos.Instance{ - "OBJECT": name, - "EXPECTED-CLASS": class.Symbol, - }) + if err := ensure(class.Symbol, name); err != nil { + return nil, err } ret, err := Eval(local, global, form) if err != nil { @@ -47,11 +44,8 @@ func Defconstant(local, global *environment.Environment, name, form ilos.Instanc // A lexical variable binding for name can still be locally established by a binding form; in that // case, the local binding lexically shadows the outer binding of name defined by defglobal. func Defglobal(local, global *environment.Environment, name, form ilos.Instance) (ilos.Instance, ilos.Instance) { - if !instance.Of(class.Symbol, name) { - return nil, instance.New(class.DomainError, map[string]ilos.Instance{ - "OBJECT": name, - "EXPECTED-CLASS": class.Symbol, - }) + if err := ensure(class.Symbol, name); err != nil { + return nil, err } ret, err := Eval(local, global, form) if err != nil { @@ -71,11 +65,8 @@ func Defglobal(local, global *environment.Environment, name, form ilos.Instance) // //The symbol named name is returned. func Defdynamic(local, global *environment.Environment, name, form ilos.Instance) (ilos.Instance, ilos.Instance) { - if !instance.Of(class.Symbol, name) { - return nil, instance.New(class.DomainError, map[string]ilos.Instance{ - "OBJECT": name, - "EXPECTED-CLASS": class.Symbol, - }) + if err := ensure(class.Symbol, name); err != nil { + return nil, err } ret, err := Eval(local, global, form) if err != nil { @@ -98,8 +89,7 @@ func Defdynamic(local, global *environment.Environment, name, form ilos.Instance // the body form* (i.e., those which are not contained in the lambda list) follow the rules of lexical // scoping. func Defun(local, global *environment.Environment, functionName, lambdaList ilos.Instance, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { - ret, err := newNamedFunction(local, global, functionName, lambdaList, forms...) - if err != nil { + if err := ensure(class.Symbol, functionName); err != nil { return nil, err } if !global.Function.Define(functionName, ret) { diff --git a/runtime/functions.go b/runtime/functions.go index 2638536..59133a0 100644 --- a/runtime/functions.go +++ b/runtime/functions.go @@ -33,11 +33,8 @@ func Functionp(local, global *environment.Environment, fun ilos.Instance) (ilos. // The consequences are undefined if the function-name names a macro or special form func Function(local, global *environment.Environment, fun ilos.Instance) (ilos.Instance, ilos.Instance) { // car must be a symbol - if !instance.Of(class.Symbol, fun) { - return nil, instance.New(class.DomainError, map[string]ilos.Instance{ - "OBJECT": fun, - "EXPECTED-CLASS": class.Symbol, - }) + if err := ensure(class.Symbol, fun); err != nil { + return nil, err } if f, ok := local.Function.Get(fun); ok { return f, nil @@ -200,11 +197,8 @@ func Apply(local, global *environment.Environment, function ilos.Instance, obj . for i := len(obj) - 1; i >= 0; i-- { list = instance.New(class.Cons, obj[i], list) } - if !instance.Of(class.Function, function) { - return nil, instance.New(class.DomainError, map[string]ilos.Instance{ - "OBJECT": function, - "EXPECTED-CLASS": class.Function, - }) + if err := ensure(class.Function, function); err != nil { + return nil, err } ret, err := function.(instance.Applicable).Apply(local, global, list) return ret, err diff --git a/runtime/integer_class.go b/runtime/integer_class.go index 011f9b9..d96283d 100644 --- a/runtime/integer_class.go +++ b/runtime/integer_class.go @@ -14,11 +14,8 @@ import ( ) func convInt(z ilos.Instance) (int, ilos.Instance) { - if instance.Of(class.Integer, z) { - return 0, instance.New(class.DomainError, map[string]ilos.Instance{ - "OBJECT": z, - "EXPECTED-CLASS": class.Integer, - }) + if err := ensure(class.Integer, z); err != nil { + return 0, err } return int(z.(instance.Integer)), nil } diff --git a/runtime/number_class.go b/runtime/number_class.go index 38d8464..faf98a5 100644 --- a/runtime/number_class.go +++ b/runtime/number_class.go @@ -30,11 +30,8 @@ func Numberp(_, _ *environment.Environment, obj ilos.Instance) (ilos.Instance, i // An error shall be signaled if string is not the textual representation // of a number (error-id. cannot-parse-number). func ParseNumber(_, _ *environment.Environment, str ilos.Instance) (ilos.Instance, ilos.Instance) { - if !instance.Of(class.String, str) { - return nil, instance.New(class.DomainError, map[string]ilos.Instance{ - "OBJECT": str, - "EXPECTED-CLASS": class.String, - }) + if err := ensure(class.String, str); err != nil { + return nil, err } ret, err := parser.ParseAtom(string(str.(instance.String))) if err != nil || !instance.Of(class.Number, ret) { @@ -53,17 +50,8 @@ func ParseNumber(_, _ *environment.Environment, str ilos.Instance) (ilos.Instanc // Note: = differs from eql because = compares only the mathematical values of its arguments, // whereas eql also compares the representations func NumberEqual(_, _ *environment.Environment, x1, x2 ilos.Instance) (ilos.Instance, ilos.Instance) { - if !instance.Of(class.Number, x1) { - return nil, instance.New(class.DomainError, map[string]ilos.Instance{ - "OBJECT": x1, - "EXPECTED-CLASS": class.Number, - }) - } - if !instance.Of(class.Number, x2) { - return nil, instance.New(class.DomainError, map[string]ilos.Instance{ - "OBJECT": x2, - "EXPECTED-CLASS": class.Number, - }) + if err := ensure(class.Number, x1, x2); err != nil { + return nil, err } ret := false switch { @@ -95,17 +83,8 @@ func NumberNotEqual(_, _ *environment.Environment, x1, x2 ilos.Instance) (ilos.I // NumberGreaterThan returns t if x1 is greater than x2 func NumberGreaterThan(_, _ *environment.Environment, x1, x2 ilos.Instance) (ilos.Instance, ilos.Instance) { - if !instance.Of(class.Number, x1) { - return nil, instance.New(class.DomainError, map[string]ilos.Instance{ - "OBJECT": x1, - "EXPECTED-CLASS": class.Number, - }) - } - if !instance.Of(class.Number, x2) { - return nil, instance.New(class.DomainError, map[string]ilos.Instance{ - "OBJECT": x2, - "EXPECTED-CLASS": class.Number, - }) + if err := ensure(class.Number, x1, x2); err != nil { + return nil, err } ret := false switch { diff --git a/runtime/string_class.go b/runtime/string_class.go index 3f159b1..6b962ec 100644 --- a/runtime/string_class.go +++ b/runtime/string_class.go @@ -42,11 +42,8 @@ func CreateString(_, _ *environment.Environment, i ilos.Instance, initialElement if len(initialElement) == 0 { v[i] = Nil } else { - if !instance.Of(class.Character, initialElement[0]) { - return nil, instance.New(class.DomainError, map[string]ilos.Instance{ - "OBJECT": initialElement[0], - "EXPECTED-CLASS": class.Character, - }) + if err := ensure(class.Character, initialElement[0]); err != nil { + return nil, err } v[i] = initialElement[0] } @@ -56,17 +53,8 @@ func CreateString(_, _ *environment.Environment, i ilos.Instance, initialElement // StringEqual tests whether string1 is the same string as string2. func StringEqual(_, _ *environment.Environment, string1, string2 ilos.Instance) (ilos.Instance, ilos.Instance) { - if !instance.Of(class.String, string1) { - return nil, instance.New(class.DomainError, map[string]ilos.Instance{ - "OBJECT": string1, - "EXPECTED-CLASS": class.String, - }) - } - if !instance.Of(class.String, string2) { - return nil, instance.New(class.DomainError, map[string]ilos.Instance{ - "OBJECT": string2, - "EXPECTED-CLASS": class.String, - }) + if err := ensure(class.String, string1, string2); err != nil { + return nil, err } if string1 == string2 { return T, nil @@ -85,17 +73,8 @@ func StringNotEqual(_, _ *environment.Environment, string1, string2 ilos.Instanc // StringGreaterThan tests whether string1 is greater than string2. func StringGreaterThan(_, _ *environment.Environment, string1, string2 ilos.Instance) (ilos.Instance, ilos.Instance) { - if !instance.Of(class.String, string1) { - return nil, instance.New(class.DomainError, map[string]ilos.Instance{ - "OBJECT": string1, - "EXPECTED-CLASS": class.String, - }) - } - if !instance.Of(class.String, string2) { - return nil, instance.New(class.DomainError, map[string]ilos.Instance{ - "OBJECT": string2, - "EXPECTED-CLASS": class.String, - }) + if err := ensure(class.String, string1, string2); err != nil { + return nil, err } if string(string1.(instance.String)) > string(string2.(instance.String)) { return T, nil @@ -144,28 +123,19 @@ func StringLessThanOrEqual(_, _ *environment.Environment, string1, string2 ilos. // // An error shall be signaled if char is not a character or if string is not a string (error-id. domain-error). func CharIndex(_, _ *environment.Environment, char, str ilos.Instance, startPosition ...ilos.Instance) (ilos.Instance, ilos.Instance) { - if !instance.Of(class.Character, char) { - return nil, instance.New(class.DomainError, map[string]ilos.Instance{ - "OBJECT": char, - "EXPECTED-CLASS": class.Character, - }) + if err := ensure(class.Character, char); err != nil { + return nil, err } - if !instance.Of(class.String, str) { - return nil, instance.New(class.DomainError, map[string]ilos.Instance{ - "OBJECT": str, - "EXPECTED-CLASS": class.String, - }) + if err := ensure(class.String, str); err != nil { + return nil, err } if len(startPosition) > 1 { return nil, instance.New(class.ProgramError) } n := 0 if len(startPosition) == 1 { - if !instance.Of(class.Integer, startPosition[0]) { - return nil, instance.New(class.DomainError, map[string]ilos.Instance{ - "OBJECT": startPosition[0], - "EXPECTED-CLASS": class.Integer, - }) + if err := ensure(class.Integer, startPosition[0]); err != nil { + return nil, err } n = int(startPosition[0].(instance.Integer)) } @@ -186,28 +156,19 @@ func CharIndex(_, _ *environment.Environment, char, str ilos.Instance, startPosi // // An error shall be signaled if either substring or string is not a string (error-id. domain-error). func StringIndex(_, _ *environment.Environment, sub, str ilos.Instance, startPosition ...ilos.Instance) (ilos.Instance, ilos.Instance) { - if !instance.Of(class.String, sub) { - return nil, instance.New(class.DomainError, map[string]ilos.Instance{ - "OBJECT": sub, - "EXPECTED-CLASS": class.String, - }) + if err := ensure(class.String, sub); err != nil { + return nil, err } - if !instance.Of(class.String, str) { - return nil, instance.New(class.DomainError, map[string]ilos.Instance{ - "OBJECT": str, - "EXPECTED-CLASS": class.String, - }) + if err := ensure(class.String, str); err != nil { + return nil, err } if len(startPosition) > 1 { return nil, instance.New(class.ProgramError) } n := 0 if len(startPosition) == 1 { - if !instance.Of(class.Integer, startPosition[0]) { - return nil, instance.New(class.DomainError, map[string]ilos.Instance{ - "OBJECT": startPosition[0], - "EXPECTED-CLASS": class.Integer, - }) + if err := ensure(class.Integer, startPosition[0]); err != nil { + return nil, err } n = int(startPosition[0].(instance.Integer)) } @@ -231,11 +192,8 @@ func StringIndex(_, _ *environment.Environment, sub, str ilos.Instance, startPos func StringAppend(_, _ *environment.Environment, str ...ilos.Instance) (ilos.Instance, ilos.Instance) { ret := "" for _, s := range str { - if !instance.Of(class.String, s) { - return nil, instance.New(class.DomainError, map[string]ilos.Instance{ - "OBJECT": s, - "EXPECTED-CLASS": class.String, - }) + if err := ensure(class.String, s); err != nil { + return nil, err } ret += string(s.(instance.String)) } diff --git a/runtime/util.go b/runtime/util.go index ca2cea5..b95fcd1 100644 --- a/runtime/util.go +++ b/runtime/util.go @@ -75,3 +75,14 @@ func defglobal(name string, value ilos.Instance) { symbol := instance.New(class.Symbol, name) environment.TopLevel.Variable.Define(symbol, value) } +func ensure(c ilos.Class, i ...ilos.Instance) ilos.Instance { + for _, o := range i { + if !instance.Of(c, o) { + return instance.New(class.DomainError, map[string]ilos.Instance{ + "OBJECT": o, + "EXPECTED-CLASS": c, + }) + } + } + return nil +} From 303de8f4e22a922efc4a3e087572235c7d431f90 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Mon, 14 Aug 2017 03:28:48 +0900 Subject: [PATCH 167/228] bugfix --- runtime/defining_operators.go | 4 ++++ runtime/functions.go | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/runtime/defining_operators.go b/runtime/defining_operators.go index 34d4511..3e8baba 100644 --- a/runtime/defining_operators.go +++ b/runtime/defining_operators.go @@ -92,6 +92,10 @@ func Defun(local, global *environment.Environment, functionName, lambdaList ilos if err := ensure(class.Symbol, functionName); err != nil { return nil, err } + ret, err := newNamedFunction(local, global, functionName, lambdaList, forms...) + if err != nil { + return nil, err + } if !global.Function.Define(functionName, ret) { return nil, instance.New(class.ProgramError) } diff --git a/runtime/functions.go b/runtime/functions.go index 59133a0..c2b9ba2 100644 --- a/runtime/functions.go +++ b/runtime/functions.go @@ -172,11 +172,11 @@ func Flet(local, global *environment.Environment, functions ilos.Instance, bodyF if err != nil { return nil, err } - if !local.Function.Define(functionName, fun) { + if !env.Function.Define(functionName, fun) { return nil, instance.New(class.ProgramError) } } - return Progn(local, global, bodyForm...) + return Progn(env, global, bodyForm...) } // Apply applies function to the arguments, obj*, followed by the elements of list, From ea89b1952474d3d9b951af8f22d70c44bde4ed39 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Mon, 14 Aug 2017 14:00:31 +0900 Subject: [PATCH 168/228] Added Slice() method --- runtime/conditional_expressions.go | 26 ++++----- runtime/cons.go | 8 +-- runtime/eval.go | 18 +++--- runtime/functions.go | 60 ++++++++------------ runtime/ilos/instance/function.go | 9 ++- runtime/ilos/instance/list.go | 52 ++++++++--------- runtime/iteration.go | 25 ++++---- runtime/list_operations.go | 91 ++++++++++++++++++++++++++++++ runtime/namedfunc.go | 7 +-- runtime/util.go | 14 +---- runtime/variables.go | 30 +++++----- 11 files changed, 197 insertions(+), 143 deletions(-) diff --git a/runtime/conditional_expressions.go b/runtime/conditional_expressions.go index 89df440..c32695f 100644 --- a/runtime/conditional_expressions.go +++ b/runtime/conditional_expressions.go @@ -43,11 +43,11 @@ func If(local, global *environment.Environment, testForm, thenForm ilos.Instance // If no form exists for the successful test then the value of this test is returned. func Cond(local, global *environment.Environment, testFrom ...ilos.Instance) (ilos.Instance, ilos.Instance) { for _, tf := range testFrom { - s, ln, err := convSlice(tf) - if err != nil { + if err := ensure(class.List, tf); err != nil { return nil, err } - if ln == 0 { + s := tf.(instance.List).Slice() + if len(s) == 0 { return nil, instance.New(class.ProgramError) } ret, err := Eval(local, global, s[0]) @@ -80,20 +80,20 @@ func Case(local, global *environment.Environment, key ilos.Instance, pattern ... return nil, err } for idx, pat := range pattern { - form, ln, err := convSlice(pat) - if err != nil { + if err := ensure(class.List, pat); err != nil { return nil, err } - if ln < 1 { + form := pat.(instance.List).Slice() + if len(form) < 1 { return nil, instance.New(class.ProgramError) } if idx == len(pattern)-1 && form[0] == T { return Progn(local, global, form[1:]...) } - keys, _, err := convSlice(form[0]) - if err != nil { + if err := ensure(class.List, form[0]); err != nil { return nil, err } + keys := form[0].(instance.List).Slice() for _, k := range keys { if k == key { return Progn(local, global, form[1:]...) @@ -127,20 +127,20 @@ func CaseUsing(local, global *environment.Environment, key, pred ilos.Instance, return nil, err } for idx, pat := range pattern { - form, ln, err := convSlice(pat) - if err != nil { + if err := ensure(class.List, pat); err != nil { return nil, err } - if ln < 1 { + form := pat.(instance.List).Slice() + if len(form) < 1 { return nil, instance.New(class.ProgramError) } if idx == len(pattern)-1 && form[0] == T { return Progn(local, global, form[1:]...) } - keys, _, err := convSlice(form[0]) - if err != nil { + if err := ensure(class.List, form[0]); err != nil { return nil, err } + keys := form[0].(instance.List).Slice() for _, k := range keys { ret, err := pred.(instance.Function).Apply(local, global, instance.New(class.Cons, k, instance.New(class.Cons, key, Nil))) if err != nil { diff --git a/runtime/cons.go b/runtime/cons.go index 823f4a2..b5b1f56 100644 --- a/runtime/cons.go +++ b/runtime/cons.go @@ -35,7 +35,7 @@ func Car(_, _ *environment.Environment, cons ilos.Instance) (ilos.Instance, ilos if err := ensure(class.Cons, cons); err != nil { return nil, err } - return instance.UnsafeCar(cons), nil // Checked at the top of this function + return cons.(*instance.Cons).Car, nil // Checked at the top of this function } // Cdr returns the right component of the cons. @@ -44,7 +44,7 @@ func Cdr(_, _ *environment.Environment, cons ilos.Instance) (ilos.Instance, ilos if err := ensure(class.Cons, cons); err != nil { return nil, err } - return instance.UnsafeCdr(cons), nil // Checked at the top of this function + return cons.(*instance.Cons).Cdr, nil // Checked at the top of this function } // TODO: setf car @@ -56,7 +56,7 @@ func SetCar(_, _ *environment.Environment, obj, cons ilos.Instance) (ilos.Instan if err := ensure(class.Cons, cons); err != nil { return nil, err } - instance.UnsafeSetCar(obj, cons) + cons.(*instance.Cons).Car = obj return obj, nil } @@ -69,6 +69,6 @@ func SetCdr(_, _ *environment.Environment, obj, cons ilos.Instance) (ilos.Instan if err := ensure(class.Cons, cons); err != nil { return nil, err } - instance.UnsafeSetCdr(obj, cons) + cons.(*instance.Cons).Cdr = obj return obj, nil } diff --git a/runtime/eval.go b/runtime/eval.go index 758aa9f..ad3a41c 100644 --- a/runtime/eval.go +++ b/runtime/eval.go @@ -16,15 +16,11 @@ func evalArguments(local, global *environment.Environment, arguments ilos.Instan if arguments == Nil { return Nil, nil } - // arguments must be a instance of list and ends with nil - if !isProperList(arguments) { - return nil, instance.New(class.ParseError, map[string]ilos.Instance{ - "STRING": arguments, - "EXPECTED-CLASS": class.List, - }) + if err := ensure(class.Cons, arguments); err != nil { + return nil, err } - car := instance.UnsafeCar(arguments) // Checked there - cdr := instance.UnsafeCdr(arguments) // Checked there + car := arguments.(*instance.Cons).Car // Checked there + cdr := arguments.(*instance.Cons).Cdr // Checked there a, err := Eval(local, global, car) if err != nil { return nil, err @@ -40,7 +36,7 @@ func evalArguments(local, global *environment.Environment, arguments ilos.Instan func evalLambda(local, global *environment.Environment, car, cdr ilos.Instance) (ilos.Instance, ilos.Instance, bool) { // eval if lambda form if instance.Of(class.Cons, car) { - caar := instance.UnsafeCar(car) // Checked at the top of// This sentence + caar := car.(*instance.Cons).Car // Checked at the top of// This sentence if caar == instance.New(class.Symbol, "LAMBDA") { fun, err := Eval(local, global, car) if err != nil { @@ -141,8 +137,8 @@ func evalCons(local, global *environment.Environment, obj ilos.Instance) (ilos.I "EXPECTED-CLASS": class.Cons, }) } - car := instance.UnsafeCar(obj) // Checked at the top of// This function - cdr := instance.UnsafeCdr(obj) // Checked at the top of// This function + car := obj.(*instance.Cons).Car // Checked at the top of// This function + cdr := obj.(*instance.Cons).Cdr // Checked at the top of// This function // eval if lambda form if a, b, c := evalLambda(local, global, car, cdr); c { diff --git a/runtime/functions.go b/runtime/functions.go index c2b9ba2..ff3548b 100644 --- a/runtime/functions.go +++ b/runtime/functions.go @@ -103,32 +103,24 @@ func Lambda(local, global *environment.Environment, lambdaList ilos.Instance, fo // // No function-name may appear more than once in the function bindings. func Labels(local, global *environment.Environment, functions ilos.Instance, bodyForm ...ilos.Instance) (ilos.Instance, ilos.Instance) { - cdr, _, err := convSlice(functions) - if err != nil { + if err := ensure(class.List, functions); err != nil { return nil, err } - for _, cadr := range cdr { - if !instance.Of(class.Cons, cadr) { // #1 - return nil, instance.New(class.ProgramError) - } - functionName := instance.UnsafeCar(cadr) // Checked at #1 - cdadr := instance.UnsafeCdr(cadr) - if !instance.Of(class.Cons, cdadr) { // #2 - return nil, instance.New(class.ProgramError) - } - lambdaList := instance.UnsafeCar(cdadr) // Checked at #2 - if err := checkLambdaList(lambdaList); err != nil { + for _, cadr := range functions.(instance.List).Slice() { + if err := ensure(class.Cons, cadr); err != nil { // #1 return nil, err } - cddadr := instance.UnsafeCdr(cdadr) // Checked at #2 - if !isProperList(cddadr) { - return nil, instance.New(class.ProgramError) + functionName := cadr.(*instance.Cons).Car // Checked at #1 + cdadr := cadr.(*instance.Cons).Cdr // Checked at #1 + if err := ensure(class.Cons, cdadr); err != nil { // #2 + return nil, err } - form, _, err := convSlice(cddadr) - if err != nil { + lambdaList := cdadr.(*instance.Cons).Car // Checked at #2 + forms := cdadr.(*instance.Cons).Cdr // Checked at #2 + if err := ensure(class.List, forms); err != nil { return nil, err } - fun, err := newNamedFunction(local, global, functionName, lambdaList, form...) + fun, err := newNamedFunction(local, global, functionName, lambdaList, forms.(instance.List).Slice()...) if err != nil { return nil, err } @@ -142,33 +134,25 @@ func Labels(local, global *environment.Environment, functions ilos.Instance, bod // Flet special form allow the definition of new identifiers in the function // namespace for function objects (see Labels). func Flet(local, global *environment.Environment, functions ilos.Instance, bodyForm ...ilos.Instance) (ilos.Instance, ilos.Instance) { - cdr, _, err := convSlice(functions) - if err != nil { + if err := ensure(class.List, functions); err != nil { return nil, err } env := environment.New().Merge(local) - for _, cadr := range cdr { - if !instance.Of(class.Cons, cadr) { // #1 - return nil, instance.New(class.ProgramError) - } - functionName := instance.UnsafeCar(cadr) // Checked at #1 - cdadr := instance.UnsafeCdr(cadr) - if !instance.Of(class.Cons, cdadr) { // #2 - return nil, instance.New(class.ProgramError) - } - lambdaList := instance.UnsafeCar(cdadr) // Checked at #2 - if err := checkLambdaList(lambdaList); err != nil { + for _, cadr := range functions.(instance.List).Slice() { + if err := ensure(class.Cons, cadr); err != nil { // #1 return nil, err } - cddadr := instance.UnsafeCdr(cdadr) // Checked at #2 - if !isProperList(cddadr) { - return nil, instance.New(class.ProgramError) + functionName := cadr.(*instance.Cons).Car // Checked at #1 + cdadr := cadr.(*instance.Cons).Cdr // Checked at #1 + if err := ensure(class.Cons, cdadr); err != nil { // #2 + return nil, err } - form, _, err := convSlice(cddadr) - if err != nil { + lambdaList := cdadr.(*instance.Cons).Car // Checked at #2 + forms := cdadr.(*instance.Cons).Cdr // Checked at #2 + if err := ensure(class.List, forms); err != nil { return nil, err } - fun, err := newNamedFunction(local, global, functionName, lambdaList, form...) + fun, err := newNamedFunction(local, global, functionName, lambdaList, forms.(instance.List).Slice()...) if err != nil { return nil, err } diff --git a/runtime/ilos/instance/function.go b/runtime/ilos/instance/function.go index f4d6077..801bd83 100644 --- a/runtime/ilos/instance/function.go +++ b/runtime/ilos/instance/function.go @@ -41,13 +41,12 @@ func (f Function) String() string { func (f Function) Apply(local, global *environment.Environment, arguments ilos.Instance) (ilos.Instance, ilos.Instance) { fv := reflect.ValueOf(f.function) ft := reflect.TypeOf(f.function) - cdr := arguments argv := []reflect.Value{reflect.ValueOf(local), reflect.ValueOf(global)} - for Of(class.Cons, cdr) { - cadr := UnsafeCar(cdr) // Checked at the top of this loop - cddr := UnsafeCdr(cdr) // Checked at the top of this loop + if !Of(class.List, arguments) { + return nil, New(class.ProgramError) + } + for _, cadr := range arguments.(List).Slice() { argv = append(argv, reflect.ValueOf(cadr)) - cdr = cddr } if ft.NumIn() != len(argv) && (!ft.IsVariadic() || ft.NumIn()-2 >= len(argv)) { return nil, New(class.ProgramError) diff --git a/runtime/ilos/instance/list.go b/runtime/ilos/instance/list.go index e728f90..7e8c258 100644 --- a/runtime/ilos/instance/list.go +++ b/runtime/ilos/instance/list.go @@ -11,13 +11,17 @@ import ( "github.com/ta2gch/iris/runtime/ilos/class" ) +type List interface { + Slice() []ilos.Instance +} + // // Cons // type Cons struct { - car ilos.Instance - cdr ilos.Instance + Car ilos.Instance + Cdr ilos.Instance } func (*Cons) Class() ilos.Class { @@ -28,9 +32,9 @@ func (i *Cons) GetSlotValue(key ilos.Instance, _ ilos.Class) (ilos.Instance, boo if symbol, ok := key.(Symbol); ok { switch symbol { case "CAR": - return i.car, true + return i.Car, true case "CDR": - return i.cdr, true + return i.Cdr, true } } return nil, false @@ -40,10 +44,10 @@ func (i *Cons) SetSlotValue(key ilos.Instance, value ilos.Instance, _ ilos.Class if symbol, ok := key.(Symbol); ok { switch symbol { case "CAR": - i.car = value + i.Car = value return true case "CDR": - i.cdr = value + i.Cdr = value return true } } @@ -51,11 +55,11 @@ func (i *Cons) SetSlotValue(key ilos.Instance, value ilos.Instance, _ ilos.Class } func (i *Cons) String() string { - str := "(" + fmt.Sprint(i.car) - cdr := i.cdr + str := "(" + fmt.Sprint(i.Car) + cdr := i.Cdr for Of(class.Cons, cdr) { - str += fmt.Sprintf(" %v", UnsafeCar(cdr)) // Checked at the top of this loop - cdr = UnsafeCdr(cdr) // Checked at the top of this loop + str += fmt.Sprintf(" %v", cdr.(*Cons).Car) // Checked at the top of this loop + cdr = cdr.(*Cons).Cdr // Checked at the top of this loop } if Of(class.Null, cdr) { str += ")" @@ -65,22 +69,14 @@ func (i *Cons) String() string { return str } -func UnsafeCar(i ilos.Instance) ilos.Instance { - return i.(*Cons).car -} - -func UnsafeCdr(i ilos.Instance) ilos.Instance { - return i.(*Cons).cdr -} - -func UnsafeSetCar(o, i ilos.Instance) ilos.Instance { - i.(*Cons).car = o - return o -} - -func UnsafeSetCdr(o, i ilos.Instance) ilos.Instance { - i.(*Cons).cdr = o - return o +func (i *Cons) Slice() []ilos.Instance { + s := []ilos.Instance{} + var cdr ilos.Instance = i + for Of(class.Cons, cdr) { + s = append(s, cdr.(*Cons).Car) + cdr = cdr.(*Cons).Cdr + } + return s } // @@ -104,3 +100,7 @@ func (i Null) SetSlotValue(key ilos.Instance, value ilos.Instance, _ ilos.Class) func (Null) String() string { return "nil" } + +func (Null) Slice() []ilos.Instance { + return []ilos.Instance{} +} diff --git a/runtime/iteration.go b/runtime/iteration.go index 05dcb63..7e3aa5a 100644 --- a/runtime/iteration.go +++ b/runtime/iteration.go @@ -56,16 +56,15 @@ func While(local, global *environment.Environment, testForm ilos.Instance, bodyF // If end-test returns a non-nil value, then the result * are evaluated sequentially and the value of the // last one is returned as value of the whole for macro. If no result is present, then the value of the for macro is nil. func For(local, global *environment.Environment, iterationSpecs, endTestAndResults ilos.Instance, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { - iss, _, err := convSlice(iterationSpecs) - if err != nil { + if err := ensure(class.List, iterationSpecs); err != nil { return nil, err } - for _, is := range iss { - i, ln, err := convSlice(is) - if err != nil { + for _, is := range iterationSpecs.(instance.List).Slice() { + if err := ensure(class.List, is); err != nil { return nil, err } - switch ln { + i := is.(instance.List).Slice() + switch len(i) { case 2, 3: var1 := i[0] init := i[1] @@ -76,11 +75,11 @@ func For(local, global *environment.Environment, iterationSpecs, endTestAndResul return nil, instance.New(class.ProgramError) } } - ends, ln, err := convSlice(endTestAndResults) - if err != nil { + if err := ensure(class.List, endTestAndResults); err != nil { return nil, err } - if ln == 0 { + ends := endTestAndResults.(instance.List).Slice() + if len(ends) == 0 { return nil, instance.New(class.ParseError) } endTest := ends[0] @@ -94,12 +93,12 @@ func For(local, global *environment.Environment, iterationSpecs, endTestAndResul if err != nil { return nil, err } - for _, is := range iss { - i, ln, err := convSlice(is) - if err != nil { + for _, is := range iterationSpecs.(instance.List).Slice() { + if err := ensure(class.List, is); err != nil { return nil, err } - switch ln { + i := is.(instance.List).Slice() + switch len(i) { case 2: case 3: var1 := i[0] diff --git a/runtime/list_operations.go b/runtime/list_operations.go index bd4e6df..6e5065b 100644 --- a/runtime/list_operations.go +++ b/runtime/list_operations.go @@ -4,4 +4,95 @@ package runtime +import ( + "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/ilos" + "github.com/ta2gch/iris/runtime/ilos/class" + "github.com/ta2gch/iris/runtime/ilos/instance" +) + // TODO: listp, craete-list, list, reverse, nreverse, append, member, mapcar, mapc, mapcan, maplist, mapcon, assoc + +func Listp(_, _ *environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { + if instance.Of(class.Cons, obj) { + return T, nil + } + return Nil, nil +} + +func CreateList(_, _ *environment.Environment, i ilos.Instance, initialElement ...ilos.Instance) (ilos.Instance, ilos.Instance) { + if err := ensure(class.Integer, i); err != nil { + return nil, err + } + if len(initialElement) > 1 { + return nil, instance.New(class.ProgramError) + } + elm := Nil + if len(initialElement) == 1 { + elm = initialElement[0] + } + cons := Nil + for j := 0; j < int(i.(instance.Integer)); j++ { + cons = instance.New(class.Cons, elm, cons) + } + return cons, nil +} + +func List(_, _ *environment.Environment, objs ...ilos.Instance) (ilos.Instance, ilos.Instance) { + cons := Nil + for i := len(objs) - 1; i >= 0; i-- { + cons = instance.New(class.Cons, objs[i], cons) + } + return cons, nil +} + +func Reverse(_, _ *environment.Environment, list ilos.Instance) (ilos.Instance, ilos.Instance) { + if err := ensure(class.List, list); err != nil { + return nil, err + } + cons := Nil + cdr := list + for instance.Of(class.Cons, cdr) { + car := cdr.(*instance.Cons).Car + cons = instance.New(class.Cons, car, cons) + cdr = cdr.(*instance.Cons).Cdr + } + return cons, nil +} + +func Nreverse(_, _ *environment.Environment, list ilos.Instance) (ilos.Instance, ilos.Instance) { + // TODO: tests literal object + if err := ensure(class.List, list); err != nil { + return nil, err + } + cons := Nil + cdr := list + for instance.Of(class.Cons, cdr) { + car := cdr.(*instance.Cons).Car + cons = instance.New(class.Cons, car, cons) + cdr = cdr.(*instance.Cons).Cdr + } + return cons, nil +} + +func Append(_, _ *environment.Environment, lists ...ilos.Instance) (ilos.Instance, ilos.Instance) { + result, err := List(nil, nil, Nil) + if err != nil { + return nil, err + } + cdr := result + if err := ensure(class.List, lists...); err != nil { + return nil, err + } + for _, list := range lists { + for _, elt := range list.(instance.List).Slice() { + it, err := List(nil, nil, elt) + if err != nil { + return nil, err + } + cdr.(*instance.Cons).Cdr = it + cdr = cdr.(*instance.Cons).Cdr + } + } + return result.(*instance.Cons).Cdr, nil +} diff --git a/runtime/namedfunc.go b/runtime/namedfunc.go index db25fd1..594b3d8 100644 --- a/runtime/namedfunc.go +++ b/runtime/namedfunc.go @@ -12,10 +12,10 @@ import ( ) func checkLambdaList(lambdaList ilos.Instance) ilos.Instance { - cdr, _, err := convSlice(lambdaList) - if err != nil { + if err := ensure(class.List, lambdaList); err != nil { return err } + cdr := lambdaList.(instance.List).Slice() for i, cadr := range cdr { if !instance.Of(class.Symbol, cadr) { return instance.New(class.ProgramError) @@ -34,10 +34,9 @@ func newNamedFunction(local, global *environment.Environment, functionName, lamb if err := checkLambdaList(lambdaList); err != nil { return nil, err } - cdr, _, _ := convSlice(lambdaList) parameters := []ilos.Instance{} variadic := false - for _, cadr := range cdr { + for _, cadr := range lambdaList.(instance.List).Slice() { if cadr == instance.New(class.Symbol, ":REST") || cadr == instance.New(class.Symbol, "&REST") { variadic = true } diff --git a/runtime/util.go b/runtime/util.go index b95fcd1..38afd09 100644 --- a/runtime/util.go +++ b/runtime/util.go @@ -16,21 +16,9 @@ import ( "github.com/ta2gch/iris/runtime/ilos/instance" ) -func convSlice(cons ilos.Instance) ([]ilos.Instance, int, ilos.Instance) { - is := []ilos.Instance{} - if isProperList(cons) { - return nil, 0, instance.New(class.ProgramError) - } - for instance.Of(class.Cons, cons) { - is = append(is, instance.UnsafeCar(cons)) - cons = instance.UnsafeCdr(cons) - } - return is, len(is), nil -} - func isProperList(i ilos.Instance) bool { if instance.Of(class.Cons, i) { - return isProperList(instance.UnsafeCdr(i)) // Checked at the top of this statements + return isProperList(i.(*instance.Cons).Cdr) // Checked at the top of this statements } if i == Nil { return true diff --git a/runtime/variables.go b/runtime/variables.go index 5d9c023..d6c9281 100644 --- a/runtime/variables.go +++ b/runtime/variables.go @@ -51,16 +51,16 @@ func Setq(local, global *environment.Environment, var1, form ilos.Instance) (ilo // // No var may appear more than once in let variable list. func Let(local, global *environment.Environment, varForm ilos.Instance, bodyForm ...ilos.Instance) (ilos.Instance, ilos.Instance) { - cdr := varForm vfs := map[ilos.Instance]ilos.Instance{} - for instance.Of(class.Cons, cdr) { - uCar, uCdr := instance.UnsafeCar, instance.UnsafeCdr - cadr, cddr := uCar(cdr), uCdr(cdr) // Checked at the top of this loop - s, ln, err := convSlice(cadr) - if err != nil { + if err := ensure(class.List, varForm); err != nil { + return nil, err + } + for _, cadr := range varForm.(instance.List).Slice() { + if err := ensure(class.List, cadr); err != nil { return nil, err } - if ln != 2 { + s := cadr.(instance.List).Slice() + if len(s) != 2 { return nil, instance.New(class.ProgramError) } f, err := Eval(local, global, s[1]) @@ -68,7 +68,6 @@ func Let(local, global *environment.Environment, varForm ilos.Instance, bodyForm return nil, err } vfs[s[0]] = f - cdr = cddr } for v, f := range vfs { if !local.Variable.Define(v, f) { @@ -93,15 +92,15 @@ func Let(local, global *environment.Environment, varForm ilos.Instance, bodyForm // The returned value of let* is the result of the evaluation of the last form // of its body (or nil if there is none). func LetStar(local, global *environment.Environment, varForm ilos.Instance, bodyForm ...ilos.Instance) (ilos.Instance, ilos.Instance) { - cdr := varForm - for instance.Of(class.Cons, cdr) { - uCar, uCdr := instance.UnsafeCar, instance.UnsafeCdr - cadr, cddr := uCar(cdr), uCdr(cdr) // Checked at the top of this loop - s, ln, err := convSlice(cadr) - if err != nil { + if err := ensure(class.List, varForm); err != nil { + return nil, err + } + for _, cadr := range varForm.(instance.List).Slice() { + if err := ensure(class.List, cadr); err != nil { return nil, err } - if ln != 2 { + s := cadr.(instance.List).Slice() + if len(s) != 2 { return nil, instance.New(class.ProgramError) } f, err := Eval(local, global, s[1]) @@ -111,7 +110,6 @@ func LetStar(local, global *environment.Environment, varForm ilos.Instance, body if !local.Variable.Define(s[0], f) { return nil, instance.New(class.ProgramError) } - cdr = cddr } return Progn(local, global, bodyForm...) } From 9b4c714a50916c2c2ed9117ed0c98a4d495e6db5 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Mon, 14 Aug 2017 14:17:59 +0900 Subject: [PATCH 169/228] remove Car & Cdr --- runtime/functions.go | 42 ++++++++++++++++---------------------- runtime/list_operations.go | 10 ++------- 2 files changed, 20 insertions(+), 32 deletions(-) diff --git a/runtime/functions.go b/runtime/functions.go index ff3548b..ca19bcf 100644 --- a/runtime/functions.go +++ b/runtime/functions.go @@ -106,21 +106,18 @@ func Labels(local, global *environment.Environment, functions ilos.Instance, bod if err := ensure(class.List, functions); err != nil { return nil, err } - for _, cadr := range functions.(instance.List).Slice() { - if err := ensure(class.Cons, cadr); err != nil { // #1 + for _, function := range functions.(instance.List).Slice() { + if err := ensure(class.List, function); err != nil { return nil, err } - functionName := cadr.(*instance.Cons).Car // Checked at #1 - cdadr := cadr.(*instance.Cons).Cdr // Checked at #1 - if err := ensure(class.Cons, cdadr); err != nil { // #2 - return nil, err - } - lambdaList := cdadr.(*instance.Cons).Car // Checked at #2 - forms := cdadr.(*instance.Cons).Cdr // Checked at #2 - if err := ensure(class.List, forms); err != nil { - return nil, err + definition := function.(instance.List).Slice() + if len(definition) < 2 { + return nil, instance.New(class.ProgramError) } - fun, err := newNamedFunction(local, global, functionName, lambdaList, forms.(instance.List).Slice()...) + functionName := definition[0] + lambdaList := definition[1] + forms := definition[2:] + fun, err := newNamedFunction(local, global, functionName, lambdaList, forms...) if err != nil { return nil, err } @@ -138,21 +135,18 @@ func Flet(local, global *environment.Environment, functions ilos.Instance, bodyF return nil, err } env := environment.New().Merge(local) - for _, cadr := range functions.(instance.List).Slice() { - if err := ensure(class.Cons, cadr); err != nil { // #1 + for _, function := range functions.(instance.List).Slice() { + if err := ensure(class.List, function); err != nil { return nil, err } - functionName := cadr.(*instance.Cons).Car // Checked at #1 - cdadr := cadr.(*instance.Cons).Cdr // Checked at #1 - if err := ensure(class.Cons, cdadr); err != nil { // #2 - return nil, err - } - lambdaList := cdadr.(*instance.Cons).Car // Checked at #2 - forms := cdadr.(*instance.Cons).Cdr // Checked at #2 - if err := ensure(class.List, forms); err != nil { - return nil, err + definition := function.(instance.List).Slice() + if len(definition) < 2 { + return nil, instance.New(class.ProgramError) } - fun, err := newNamedFunction(local, global, functionName, lambdaList, forms.(instance.List).Slice()...) + functionName := definition[0] + lambdaList := definition[1] + forms := definition[2:] + fun, err := newNamedFunction(local, global, functionName, lambdaList, forms...) if err != nil { return nil, err } diff --git a/runtime/list_operations.go b/runtime/list_operations.go index 6e5065b..4425070 100644 --- a/runtime/list_operations.go +++ b/runtime/list_operations.go @@ -51,11 +51,8 @@ func Reverse(_, _ *environment.Environment, list ilos.Instance) (ilos.Instance, return nil, err } cons := Nil - cdr := list - for instance.Of(class.Cons, cdr) { - car := cdr.(*instance.Cons).Car + for _, car := range list.(instance.List).Slice() { cons = instance.New(class.Cons, car, cons) - cdr = cdr.(*instance.Cons).Cdr } return cons, nil } @@ -66,11 +63,8 @@ func Nreverse(_, _ *environment.Environment, list ilos.Instance) (ilos.Instance, return nil, err } cons := Nil - cdr := list - for instance.Of(class.Cons, cdr) { - car := cdr.(*instance.Cons).Car + for _, car := range list.(instance.List).Slice() { cons = instance.New(class.Cons, car, cons) - cdr = cdr.(*instance.Cons).Cdr } return cons, nil } From 711459e35c20be70767d9a9379a6f313a4fe89bf Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Mon, 14 Aug 2017 14:21:32 +0900 Subject: [PATCH 170/228] Added reference --- runtime/list_operations.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/runtime/list_operations.go b/runtime/list_operations.go index 4425070..862879c 100644 --- a/runtime/list_operations.go +++ b/runtime/list_operations.go @@ -70,6 +70,8 @@ func Nreverse(_, _ *environment.Environment, list ilos.Instance) (ilos.Instance, } func Append(_, _ *environment.Environment, lists ...ilos.Instance) (ilos.Instance, ilos.Instance) { + // Ref: https://github.com/sbcl/sbcl/blob/fe4faef65315c6ad52b3b89b62b6c6497cb78d09/src/code/list.lisp#L364 + result, err := List(nil, nil, Nil) if err != nil { return nil, err From 7d15fdf65b1aa4b4ad90145b8dda9a3548329588 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Mon, 14 Aug 2017 15:41:24 +0900 Subject: [PATCH 171/228] Added list operations --- runtime/conditional_expressions.go | 6 +- runtime/list_operations.go | 274 ++++++++++++++++++++++++++++- 2 files changed, 277 insertions(+), 3 deletions(-) diff --git a/runtime/conditional_expressions.go b/runtime/conditional_expressions.go index c32695f..131b760 100644 --- a/runtime/conditional_expressions.go +++ b/runtime/conditional_expressions.go @@ -142,7 +142,11 @@ func CaseUsing(local, global *environment.Environment, key, pred ilos.Instance, } keys := form[0].(instance.List).Slice() for _, k := range keys { - ret, err := pred.(instance.Function).Apply(local, global, instance.New(class.Cons, k, instance.New(class.Cons, key, Nil))) + args, err := List(nil, nil, k, key) + if err != nil { + return nil, err + } + ret, err := pred.(instance.Function).Apply(local, global, args) if err != nil { return nil, err } diff --git a/runtime/list_operations.go b/runtime/list_operations.go index 862879c..b427e66 100644 --- a/runtime/list_operations.go +++ b/runtime/list_operations.go @@ -5,14 +5,16 @@ package runtime import ( + "math" + "github.com/ta2gch/iris/runtime/environment" "github.com/ta2gch/iris/runtime/ilos" "github.com/ta2gch/iris/runtime/ilos/class" "github.com/ta2gch/iris/runtime/ilos/instance" ) -// TODO: listp, craete-list, list, reverse, nreverse, append, member, mapcar, mapc, mapcan, maplist, mapcon, assoc - +// Listp returns t if obj is a list (instance of class list); otherwise, returns nil. +// obj may be any ISLISP object. func Listp(_, _ *environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { if instance.Of(class.Cons, obj) { return T, nil @@ -20,6 +22,11 @@ func Listp(_, _ *environment.Environment, obj ilos.Instance) (ilos.Instance, ilo return Nil, nil } +// CreateList returns a list of length i. If initial-element is given, the elements of the new list +// are initialized with this object; otherwise, the initialization is implementation defined. An +// error shall be signaled if the requested list cannot be allocated (error-id. cannot-create-list). +// An error shall be signaled if i is not a non-negative integer (error-id. domain-error). +//initial-element may be any ISLISP object. func CreateList(_, _ *environment.Environment, i ilos.Instance, initialElement ...ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Integer, i); err != nil { return nil, err @@ -38,6 +45,9 @@ func CreateList(_, _ *environment.Environment, i ilos.Instance, initialElement . return cons, nil } +// List returns a new list whose length is the number of arguments and whose elements are the +// arguments in the same order as in the list-form. An error shall be signaled if the requested list +// cannot be allocated (error-id. cannot-create-list). Each obj may be any ISLISP object. func List(_, _ *environment.Environment, objs ...ilos.Instance) (ilos.Instance, ilos.Instance) { cons := Nil for i := len(objs) - 1; i >= 0; i-- { @@ -46,6 +56,11 @@ func List(_, _ *environment.Environment, objs ...ilos.Instance) (ilos.Instance, return cons, nil } +// Reverse returns a list whose elements are those of the given list, but in reverse +// order. An error shall be signaled if list is not a list (error-id. domain-error). +// +// For reverse, no side-effect to the given list occurs. The resulting list is permitted but not +// required to share structure with the input list. func Reverse(_, _ *environment.Environment, list ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.List, list); err != nil { return nil, err @@ -57,6 +72,12 @@ func Reverse(_, _ *environment.Environment, list ilos.Instance) (ilos.Instance, return cons, nil } +// Nreverse returns a list whose elements are those of the given list, but in reverse +// order. An error shall be signaled if list is not a list (error-id. domain-error). +// +// For nreverse, the conses which make up the top level of the given list are permitted, but not +// required, to be side-effected in order to produce this new list. nreverse should never be called +// on a literal object. func Nreverse(_, _ *environment.Environment, list ilos.Instance) (ilos.Instance, ilos.Instance) { // TODO: tests literal object if err := ensure(class.List, list); err != nil { @@ -69,6 +90,13 @@ func Nreverse(_, _ *environment.Environment, list ilos.Instance) (ilos.Instance, return cons, nil } +// Append returns the result of appending all of the lists, or () if given no lists. An error shall +// be signaled if any list is not a list (error-id. domain-error). +// +// This function does not modify its arguments. It is implementation defined whether and when the +// result shares structure with its list arguments. +// +// An error shall be signaled if the list cannot be allocated (error-id. cannot-create-list). func Append(_, _ *environment.Environment, lists ...ilos.Instance) (ilos.Instance, ilos.Instance) { // Ref: https://github.com/sbcl/sbcl/blob/fe4faef65315c6ad52b3b89b62b6c6497cb78d09/src/code/list.lisp#L364 @@ -92,3 +120,245 @@ func Append(_, _ *environment.Environment, lists ...ilos.Instance) (ilos.Instanc } return result.(*instance.Cons).Cdr, nil } + +// Member returnes the first sublist of list whose car is obj if list contains at least one +// occurrence of obj (as determined by eql). Otherwise, nil is returned. An error shall be signaled +// if list is not a list (error-id. domain-error). +func Member(_, _ *environment.Environment, obj, list ilos.Instance) (ilos.Instance, ilos.Instance) { + if err := ensure(class.List, list); err != nil { + return nil, err + } + for idx, elt := range list.(instance.List).Slice() { + if obj == elt { // eql + return List(nil, nil, list.(instance.List).Slice()[idx:]...) + } + } + return Nil, nil +} + +// Mapcar operates on successive elements of the lists. function is applied to the first element of +// each list, then to the second element of each list, and so on. The iteration terminates when the +// shortest list runs out, and excess elements in other lists are ignored. The value returned by +// mapcar is a list of the results of successive calls to function. +func Mapcar(local, global *environment.Environment, function, list1 ilos.Instance, lists ...ilos.Instance) (ilos.Instance, ilos.Instance) { + lists = append([]ilos.Instance{list1}, lists...) + if err := ensure(class.Function, function); err != nil { + return nil, err + } + if err := ensure(class.List, lists...); err != nil { + return nil, err + } + max := 0.0 + for _, list := range lists { + max = math.Max(max, float64(len(list.(instance.List).Slice()))) + } + result := []ilos.Instance{} + for i := 0; i < int(max); i++ { + arguments := make([]ilos.Instance, len(lists)) + for j, list := range lists { + arguments[j] = list.(instance.List).Slice()[i] + } + args, err := List(nil, nil, arguments...) + if err != nil { + return nil, err + } + ret, err := function.(instance.Function).Apply(local, global, args) + if err != nil { + return nil, err + } + result = append(result, ret) + } + return List(nil, nil, result...) +} + +// Mapc is like mapcar except that the results of applying function are not accumulated; +// list1 is returned. +func Mapc(local, global *environment.Environment, function, list1 ilos.Instance, lists ...ilos.Instance) (ilos.Instance, ilos.Instance) { + lists = append([]ilos.Instance{list1}, lists...) + if err := ensure(class.Function, function); err != nil { + return nil, err + } + if err := ensure(class.List, lists...); err != nil { + return nil, err + } + max := 0.0 + for _, list := range lists { + max = math.Max(max, float64(len(list.(instance.List).Slice()))) + } + for i := 0; i < int(max); i++ { + arguments := make([]ilos.Instance, len(lists)) + for j, list := range lists { + arguments[j] = list.(instance.List).Slice()[i] + } + args, err := List(nil, nil, arguments...) + if err != nil { + return nil, err + } + if _, err = function.(instance.Function).Apply(local, global, args); err != nil { + return nil, err + } + } + return list1, nil +} + +// Mapcan is like mapcar respectively, except that the results of applying +// function are combined into a list by the use of an operation that performs a destructive form of +// append rather than list. +func Mapcan(local, global *environment.Environment, function, list1 ilos.Instance, lists ...ilos.Instance) (ilos.Instance, ilos.Instance) { + lists = append([]ilos.Instance{list1}, lists...) + if err := ensure(class.Function, function); err != nil { + return nil, err + } + if err := ensure(class.List, lists...); err != nil { + return nil, err + } + max := 0.0 + for _, list := range lists { + max = math.Max(max, float64(len(list.(instance.List).Slice()))) + } + result := []ilos.Instance{} + for i := 0; i < int(max); i++ { + arguments := make([]ilos.Instance, len(lists)) + for j, list := range lists { + arguments[j] = list.(instance.List).Slice()[i] + } + args, err := List(nil, nil, arguments...) + if err != nil { + return nil, err + } + ret, err := function.(instance.Function).Apply(local, global, args) + if err != nil { + return nil, err + } + result = append(result, ret) + } + return Append(nil, nil, result...) +} + +// Maplist is like mapcar except that function is applied to successive sublists of the lists. +// function is first applied to the lists themselves, and then to the cdr of each list, and then to +// the cdr of the cdr of each list, and so on. +func Maplist(local, global *environment.Environment, function, list1 ilos.Instance, lists ...ilos.Instance) (ilos.Instance, ilos.Instance) { + lists = append([]ilos.Instance{list1}, lists...) + if err := ensure(class.Function, function); err != nil { + return nil, err + } + if err := ensure(class.List, lists...); err != nil { + return nil, err + } + max := 0.0 + for _, list := range lists { + max = math.Max(max, float64(len(list.(instance.List).Slice()))) + } + result := []ilos.Instance{} + for i := 0; i < int(max); i++ { + arguments := make([]ilos.Instance, len(lists)) + for j, list := range lists { + var err ilos.Instance + arguments[j], err = List(nil, nil, list.(instance.List).Slice()[i:]...) + if err != nil { + return nil, err + } + } + args, err := List(nil, nil, arguments...) + if err != nil { + return nil, err + } + ret, err := function.(instance.Function).Apply(local, global, args) + if err != nil { + return nil, err + } + result = append(result, ret) + } + return List(nil, nil, result...) +} + +// Mapl is like maplist except that the results of applying function are not accumulated; +// list1 is returned. +func Mapl(local, global *environment.Environment, function, list1 ilos.Instance, lists ...ilos.Instance) (ilos.Instance, ilos.Instance) { + lists = append([]ilos.Instance{list1}, lists...) + if err := ensure(class.Function, function); err != nil { + return nil, err + } + if err := ensure(class.List, lists...); err != nil { + return nil, err + } + max := 0.0 + for _, list := range lists { + max = math.Max(max, float64(len(list.(instance.List).Slice()))) + } + for i := 0; i < int(max); i++ { + arguments := make([]ilos.Instance, len(lists)) + for j, list := range lists { + var err ilos.Instance + arguments[j], err = List(nil, nil, list.(instance.List).Slice()[i:]...) + if err != nil { + return nil, err + } + } + args, err := List(nil, nil, arguments...) + if err != nil { + return nil, err + } + if _, err := function.(instance.Function).Apply(local, global, args); err != nil { + return nil, err + } + } + return list1, nil +} + +// Mapcon is like maplist respectively, except that the results of applying +// function are combined into a list by the use of an operation that performs a destructive form of +// append rather than list. +func Mapcon(local, global *environment.Environment, function, list1 ilos.Instance, lists ...ilos.Instance) (ilos.Instance, ilos.Instance) { + lists = append([]ilos.Instance{list1}, lists...) + if err := ensure(class.Function, function); err != nil { + return nil, err + } + if err := ensure(class.List, lists...); err != nil { + return nil, err + } + max := 0.0 + for _, list := range lists { + max = math.Max(max, float64(len(list.(instance.List).Slice()))) + } + result := []ilos.Instance{} + for i := 0; i < int(max); i++ { + arguments := make([]ilos.Instance, len(lists)) + for j, list := range lists { + var err ilos.Instance + arguments[j], err = List(nil, nil, list.(instance.List).Slice()[i:]...) + if err != nil { + return nil, err + } + } + args, err := List(nil, nil, arguments...) + if err != nil { + return nil, err + } + ret, err := function.(instance.Function).Apply(local, global, args) + if err != nil { + return nil, err + } + result = append(result, ret) + } + return Append(nil, nil, result...) +} + +// Assoc returns the first cons if assocation-list contains at least one cons whose car is +// obj (as determined by eql). Otherwise, nil is returned. An error shall be signaled +// if association-list is not a list of conses (error-id. domain-error). +func Assoc(_, _ *environment.Environment, obj, associationList ilos.Instance) (ilos.Instance, ilos.Instance) { + if err := ensure(class.List, associationList); err != nil { + return nil, err + } + for _, pair := range associationList.(instance.List).Slice() { + if err := ensure(class.Cons, pair); err != nil { + return nil, err + } + if pair.(*instance.Cons).Car == obj { // eql + return pair.(*instance.Cons).Cdr, nil + } + } + return Nil, nil +} From 2ede189a6fe433288c2e73cc0a51c44b36406872 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Mon, 14 Aug 2017 17:40:56 +0900 Subject: [PATCH 172/228] Added symbol property --- runtime/environment/environment.go | 6 +++ runtime/environment/mmap.go | 29 +++++++++++ runtime/symbol_class.go | 83 ++++++++++++++++++++++++++++++ runtime/symbol_properties.go | 7 --- 4 files changed, 118 insertions(+), 7 deletions(-) create mode 100644 runtime/environment/mmap.go create mode 100644 runtime/symbol_class.go delete mode 100644 runtime/symbol_properties.go diff --git a/runtime/environment/environment.go b/runtime/environment/environment.go index c6c7210..56f4b07 100644 --- a/runtime/environment/environment.go +++ b/runtime/environment/environment.go @@ -15,6 +15,8 @@ type Environment struct { Variable stack DynamicVariable stack // deep biding Constant stack + GensymID int + Property mmap } // New creates new environment @@ -29,6 +31,8 @@ func New() *Environment { env.Variable = newStack() env.DynamicVariable = newStack() env.Constant = newStack() + env.GensymID = 0 + env.Property = mmap{} return env } @@ -42,6 +46,8 @@ func (env *Environment) Merge(before *Environment) *Environment { env.Macro = append(before.Macro, env.Macro...) env.DynamicVariable = append(before.DynamicVariable, env.DynamicVariable...) env.Constant = append(before.Constant, env.Constant...) + env.GensymID = before.GensymID + env.Property = before.Property return env } diff --git a/runtime/environment/mmap.go b/runtime/environment/mmap.go new file mode 100644 index 0000000..de83b43 --- /dev/null +++ b/runtime/environment/mmap.go @@ -0,0 +1,29 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package environment + +import ( + "github.com/ta2gch/iris/runtime/ilos" +) + +type mmap map[[2]ilos.Instance]ilos.Instance + +func (s mmap) Get(key1, key2 ilos.Instance) (ilos.Instance, bool) { + if v, ok := s[[2]ilos.Instance{key1, key2}]; ok { + return v, true + } + return nil, false +} +func (s mmap) Set(key1, key2, value ilos.Instance) { + s[[2]ilos.Instance{key1, key2}] = value +} + +func (s mmap) Delete(key1, key2 ilos.Instance) (ilos.Instance, bool) { + if v, ok := s[[2]ilos.Instance{key1, key2}]; ok { + delete(s, [2]ilos.Instance{key1, key2}) + return v, true + } + return nil, false +} diff --git a/runtime/symbol_class.go b/runtime/symbol_class.go new file mode 100644 index 0000000..863a2e7 --- /dev/null +++ b/runtime/symbol_class.go @@ -0,0 +1,83 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package runtime + +import ( + "fmt" + + "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/ilos" + "github.com/ta2gch/iris/runtime/ilos/class" + "github.com/ta2gch/iris/runtime/ilos/instance" +) + +// TODO: setf property + +// Symbolp returns t if obj is a symbol (instance of class symbol); +// otherwise, returns nil. The obj may be any ISLISP object. +func Symbolp(_, _ *environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { + if instance.Of(class.Symbol, obj) { + return T, nil + } + return Nil, nil +} + +// Property returns the value of the property named property-name +// associated with the symbol symbol . If symbol has no property named +// property-name, obj (which defaults to nil) is returned. +// +// An error shall be signaled if either symbol or property-name is not a +// symbol (error-id. domain-error). obj may be any ISLISP object +func Property(local, global *environment.Environment, symbol, propertyName ilos.Instance, obj ...ilos.Instance) (ilos.Instance, ilos.Instance) { + if err := ensure(class.Symbol, symbol); err != nil { + return nil, err + } + if len(obj) > 1 { + return nil, instance.New(class.ProgramError) + } + ret, ok := global.Property.Get(symbol, propertyName) + if ok { + return ret, nil + } + return obj[1], nil +} + +// SetProperty causes obj to be the new value of the property named +// property-name asssociated with the symbol symbol . If the property +// named property-name already exists, its corresponding property value is +// replaced; otherwise, a new property is created. obj is returned. +// +// An error shall be signaled if either symbol or property-name is not a +// symbol (error-id. domain-error). obj may be any ISLISP object +func SetProperty(local, global *environment.Environment, obj, symbol, propertyName ilos.Instance) (ilos.Instance, ilos.Instance) { + if err := ensure(class.Symbol, symbol); err != nil { + return nil, err + } + global.Property.Set(symbol, propertyName, obj) + return obj, nil +} + +// RemoveProperty removes the property property-name associated with +// symbol and returns the property value of the removed property if there +// is such a property. If there is no such property, nil is returned. +// +// An error shall be signaled if either symbol or property-name is not a +// symbol (error-id. domain-error). +func RemoveProperty(local, global *environment.Environment, symbol, propertyName ilos.Instance) (ilos.Instance, ilos.Instance) { + if err := ensure(class.Symbol, symbol); err != nil { + return nil, err + } + if v, ok := global.Property.Delete(symbol, propertyName); ok { + return v, nil + } + return Nil, nil +} + +// Gensym returns an unnamed symbol. gensym is useful for writing macros. +// It is impossible for an identifier to name an unnamed symbol. +func Gensym(local, global *environment.Environment) (ilos.Instance, ilos.Instance) { + global.GensymID++ + return instance.New(class.Symbol, fmt.Sprintf("IRIS:G#%v", global.GensymID)), nil +} diff --git a/runtime/symbol_properties.go b/runtime/symbol_properties.go deleted file mode 100644 index e2d9bbd..0000000 --- a/runtime/symbol_properties.go +++ /dev/null @@ -1,7 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at http://mozilla.org/MPL/2.0/. - -package runtime - -// TODO: property, setf property, set-property, remove-property From 7b58133f80d21218caf646b268847c592f5afde3 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Mon, 14 Aug 2017 18:04:58 +0900 Subject: [PATCH 173/228] Added DynamicVariable operations --- runtime/dynamic_variables.go | 106 ++++++++++++++++++++++++++++++++++- 1 file changed, 105 insertions(+), 1 deletion(-) diff --git a/runtime/dynamic_variables.go b/runtime/dynamic_variables.go index 1a14773..dc00910 100644 --- a/runtime/dynamic_variables.go +++ b/runtime/dynamic_variables.go @@ -4,4 +4,108 @@ package runtime -// TODO: dynamic, setf dynamic, set-dynamic, dynamic-let +import ( + "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/ilos" + "github.com/ta2gch/iris/runtime/ilos/class" + "github.com/ta2gch/iris/runtime/ilos/instance" +) + +// TODO: setf dynamic + +// Dynamic denotes a reference to the identifier denoting a +// dynamic variable. This special form is not allowed in the scope of a +// definition of var which is not done by defdynamic or dynamic-let. +// +// During activation, the current dynamic binding of the variable var is +// returned that was established most recently and is still in effect. An +// error shall be signaled if such a binding does not exist +// (error-id. unbound-variable). +func Dynamic(local, global *environment.Environment, var1 ilos.Instance) (ilos.Instance, ilos.Instance) { + if err := ensure(class.Symbol, var1); err != nil { + return nil, err + } + if v, ok := local.DynamicVariable.Get(var1); ok { + return v, nil + } + if v, ok := global.DynamicVariable.Get(var1); ok { + return v, nil + } + return nil, instance.New(class.UndefinedVariable, map[string]ilos.Instance{ + "NAME": var1, + "NAMESPACE": instance.New(class.Symbol, "Variable"), + }) +} + +// SetDynamic denotes an assignment to a dynamic variable. This +// form can appear anywhere that (dynamic var) can appear. +// +// form is evaluated and the result of the evaluation is used to change +// the dynamic binding of var. +// +// An error shall be signaled if var has no dynamic value +// (error-id. unbound-variable). setf of dynamic can be used only for +// modifying bindings, and not for establishing them. +func SetDynamic(local, global *environment.Environment, form, var1 ilos.Instance) (ilos.Instance, ilos.Instance) { + if err := ensure(class.Symbol, var1); err != nil { + return nil, err + } + form, err := Eval(local, global, form) + if err != nil { + return nil, form + } + if local.DynamicVariable.Set(var1, form) { + return form, nil + } + if global.DynamicVariable.Set(var1, form) { + return form, nil + } + return nil, instance.New(class.UndefinedFunction, map[string]ilos.Instance{ + "NAME": var1, + "NAMESPACE": instance.New(class.Symbol, "FUNCTION"), + }) +} + +// DyamicLet is used to establish dynamic variable bindings. +// The first subform (the dynamic-let variable list) is a list of pairs (var +// form). The scope of an identifier var defined by dynamic-let is the current +// toplevel scope. The extent of the bindings of each var is the extent of the +// body of the dynamic-let. The dynamic-let special form establishes dynamic +// variables for all vars. +// +// References to a dynamic variable named by var must be made through the +// dynamic special form. +// +// All the initializing forms are evaluated sequentially from left to right, and +// then the values are associated with the corresponding vars. Using these +// additional dynamic bindings and the already existing bindings of visible +// identifiers, the forms body-form* are evaluated in sequential order. The +// returned value of dynamic-let is that of the last body-form of the body (or +// nil if there is none). The bindings are undone when control leaves the +// prepared dynamic-let special form. +func DyamicLet(local, global *environment.Environment, varForm ilos.Instance, bodyForm ...ilos.Instance) (ilos.Instance, ilos.Instance) { + vfs := map[ilos.Instance]ilos.Instance{} + if err := ensure(class.List, varForm); err != nil { + return nil, err + } + for _, cadr := range varForm.(instance.List).Slice() { + if err := ensure(class.List, cadr); err != nil { + return nil, err + } + s := cadr.(instance.List).Slice() + if len(s) != 2 { + return nil, instance.New(class.ProgramError) + } + f, err := Eval(local, global, s[1]) + if err != nil { + return nil, err + } + vfs[s[0]] = f + } + for v, f := range vfs { + if !local.DynamicVariable.Define(v, f) { + return nil, instance.New(class.ProgramError) + } + } + return Progn(local, global, bodyForm...) +} From 3dcf59a1b5d63ce8599f56b7a951a9c7b383437b Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Mon, 14 Aug 2017 18:30:14 +0900 Subject: [PATCH 174/228] Added unwind-protect --- runtime/non-local_exits.go | 40 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/runtime/non-local_exits.go b/runtime/non-local_exits.go index e890457..3c63368 100644 --- a/runtime/non-local_exits.go +++ b/runtime/non-local_exits.go @@ -210,3 +210,43 @@ func Go(local, global *environment.Environment, tag ilos.Instance) (ilos.Instanc } return nil, instance.New(class.TagbodyTag, map[string]ilos.Instance{"TAG": tag}) } + +// UnwindProtect first evaluates form. Evaluation of the cleanup-forms always +// occurs, regardless of whether the exit is normal or non-local. +// +// If the form exits normally yielding a value R, then if all of the +// cleanup-forms exit normally the value R is returned by the +// unwind-protect form. +// +// If a non-local exit from form occurs, then the cleanup-forms are executed as +// part of that exit, and then if all of the cleanup-forms exit normally the +// original non-local exit continues. +// +// The cleanup-forms are evaluated from left to right, discarding the resulting +// values. If execution of the cleanup-forms finishes normally, exit from the +// unwind-protect form proceeds as described above. It is permissible for a +// cleanup-form to contain a non-local exit from the unwind-protect form, +// subject to the following constraint: +// +// An error shall be signaled if during execution of the cleanup-forms of an +// unwind-protect form, a non-local exit is executed to a destination which has +// been marked as invalid due to some other non-local exit that is already in +// progress (error-id. control-error). +// +// Note: Because ISLISP does not specify an interactive debugger, it is +// unspecified whether or how error recovery can occur interactively if +// programmatic handling fails. The intent is that if the ISLISP processor does +// not terminate abnormally, normal mechanisms for non-local exit (return-from, +// throw, or go) would be used as necessary and would respect these +// cleanup-forms. +func UnwindProtect(local, global *environment.Environment, form ilos.Instance, cleanupForms ...ilos.Instance) (ilos.Instance, ilos.Instance) { + ret1, err1 := Eval(local, global, form) + ret2, err2 := Progn(local, global, cleanupForms...) + if instance.Of(class.Escape, err2) { + return nil, instance.New(class.ControlError) + } + if err2 != nil { + return ret2, err2 + } + return ret1, err1 +} From df4b47bb5f25b0faa3c5ca50aeef868a5c2b7e93 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Mon, 14 Aug 2017 22:55:17 +0900 Subject: [PATCH 175/228] Added array operations --- runtime/array_operations.go | 242 +++++++++++++++++++++++++++ runtime/ilos/instance/basic-array.go | 47 +++--- runtime/ilos/instance/instance.go | 2 + 3 files changed, 269 insertions(+), 22 deletions(-) create mode 100644 runtime/array_operations.go diff --git a/runtime/array_operations.go b/runtime/array_operations.go new file mode 100644 index 0000000..f3fdccb --- /dev/null +++ b/runtime/array_operations.go @@ -0,0 +1,242 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package runtime + +import ( + "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/ilos" + "github.com/ta2gch/iris/runtime/ilos/class" + "github.com/ta2gch/iris/runtime/ilos/instance" +) + +// BasicArrayP returns t if obj is a basic-array (instance of class basic-array); +// otherwise, returns nil. obj may be any ISLISP object. +func BasicArrayP(_, _ *environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { + if instance.Of(class.BasicArray, obj) { + return T, nil + } + return Nil, nil +} + +// BasicArrayStarP returns t if obj is a basic-array* (instance of class ); +// otherwise, returns nil. obj may be any ISLISP object. +func BasicArrayStarP(_, _ *environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { + if instance.Of(class.BasicArrayStar, obj) { + return T, nil + } + return Nil, nil +} + +// GeneralArrayStarP returns t if obj is a general-array* (instance of class ); +// otherwise, returns nil. obj may be any ISLISP object. +func GeneralArrayStarP(_, _ *environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { + if instance.Of(class.GeneralArrayStar, obj) { + return T, nil + } + return Nil, nil +} + +// CreateArray creates an array of the given dimensions. The dimensions argument is a list of +// non-negative integers. +// +// The result is of class general-vector if there is only one dimension, or of class +// otherwise. +// +// If initial-element is given, the elements of the new array are initialized with this object, +// otherwise the initialization is implementation defined. +// +// An error shall be signaled if the requested array cannot be allocated +// (error-id. cannot-create-array). +// +// An error shall be signaled if dimensions is not a proper list of non-negative integers +// (error-id. domain-error). initial-element may be any ISLISP object +func CreateArray(_, _ *environment.Environment, dimensions ilos.Instance, initialElement ...ilos.Instance) (ilos.Instance, ilos.Instance) { + if err := ensure(class.List, dimensions); err != nil { + return nil, err + } + if err := ensure(class.Integer, dimensions.(instance.List).Slice()...); err != nil { + return nil, err + } + dim := dimensions.(instance.List).Slice() + elt := Nil + if len(initialElement) > 1 { + return nil, instance.New(class.ProgramError) + } + if len(initialElement) == 1 { + elt = initialElement[0] + } + switch len(dim) { + case 0: + return instance.New(class.GeneralArrayStar, nil, elt), nil + case 1: + array := make([]*instance.GeneralArrayStar, int(dim[0].(instance.Integer))) + for i := range array { + array[i] = instance.New(class.GeneralArrayStar, nil, elt).(*instance.GeneralArrayStar) + } + return instance.New(class.GeneralArrayStar, array, nil), nil + default: + array := make([]*instance.GeneralArrayStar, int(dim[len(dim)-1].(instance.Integer))) + for i := range array { + array[i] = instance.New(class.GeneralArrayStar, nil, elt).(*instance.GeneralArrayStar) + } + for i := len(dim) - 2; i >= 0; i-- { + elt := array + array := make([]*instance.GeneralArrayStar, int(dim[i].(instance.Integer))) + for i := range array { + array[i] = instance.New(class.GeneralArrayStar, elt, nil).(*instance.GeneralArrayStar) + } + } + return instance.New(class.GeneralArrayStar, array, nil), nil + } +} + +// Aref returns the object stored in the component of the basic-array specified by the sequence +// of integers z. This sequence must have exactly as many elements as there are dimensions in +// the basic-array, and each one must satisfy 0 ≤ zi < di , di the ith dimension and 0 ≤ i < d, +// d the number of dimensions. Arrays are indexed 0 based, so the ith row is accessed via the +// index i − 1. +// +// An error shall be signaled if basic-array is not a basic-array (error-id. domain-error). +// An error shall be signaled if any z is not a non-negative integer (error-id. domain-error). +func Aref(_, _ *environment.Environment, basicArray ilos.Instance, dimensions ...ilos.Instance) (ilos.Instance, ilos.Instance) { + if err := ensure(class.BasicArray, basicArray); err != nil { + return nil, err + } + if err := ensure(class.Integer, dimensions...); err != nil { + return nil, err + } + switch { + case instance.Of(class.String, basicArray): + if len(dimensions) != 1 { + return nil, instance.New(class.ProgramError) + } + index := int(dimensions[0].(instance.Integer)) + if len(basicArray.(instance.String)) <= index { + return nil, instance.New(class.ProgramError) + } + return instance.New(class.Character, basicArray.(instance.String)[index]), nil + case instance.Of(class.GeneralVector, basicArray): + if len(dimensions) != 1 { + return nil, instance.New(class.ProgramError) + } + index := int(dimensions[0].(instance.Integer)) + if len(basicArray.(instance.GeneralVector)) <= index { + return nil, instance.New(class.ProgramError) + } + return basicArray.(instance.GeneralVector)[index], nil + default: // General Array* + return Garef(nil, nil, basicArray, dimensions...) + } +} + +// Garef is like aref but an error shall be signaled if its first argument, general-array, is +// not an object of class general-vector or of class (error-id. domain-error). +func Garef(_, _ *environment.Environment, generalArray ilos.Instance, dimensions ...ilos.Instance) (ilos.Instance, ilos.Instance) { + if err := ensure(class.GeneralArrayStar, generalArray); err != nil { + return nil, err + } + if err := ensure(class.Integer, dimensions...); err != nil { + return nil, err + } + var array *instance.GeneralArrayStar + for _, dim := range dimensions { + index := int(dim.(instance.Integer)) + if array.Vector == nil || len(array.Vector) <= index { + return nil, instance.New(class.ProgramError) + } + array = array.Vector[index] + } + if array.Scalar == nil { + return nil, instance.New(class.ProgramError) + } + return array.Scalar, nil +} + +// SetAref replaces the object obtainable by aref or garef with obj . The returned value is obj. +// The constraints on the basic-array, the general-array, and the sequence of indices z is the +// same as for aref and garef. +func SetAref(_, _ *environment.Environment, obj, basicArray ilos.Instance, dimensions ...ilos.Instance) (ilos.Instance, ilos.Instance) { + if err := ensure(class.BasicArray, basicArray); err != nil { + return nil, err + } + if err := ensure(class.Integer, dimensions...); err != nil { + return nil, err + } + switch { + case instance.Of(class.String, basicArray): + if err := ensure(class.Character, obj); err != nil { + return nil, err + } + if len(dimensions) != 1 { + return nil, instance.New(class.ProgramError) + } + index := int(dimensions[0].(instance.Integer)) + if len(basicArray.(instance.String)) <= index { + return nil, instance.New(class.ProgramError) + } + basicArray.(instance.String)[index] = rune(obj.(instance.Character)) + return obj, nil + case instance.Of(class.GeneralVector, basicArray): + if len(dimensions) != 1 { + return nil, instance.New(class.ProgramError) + } + index := int(dimensions[0].(instance.Integer)) + if len(basicArray.(instance.GeneralVector)) <= index { + return nil, instance.New(class.ProgramError) + } + basicArray.(instance.GeneralVector)[index] = obj + return obj, nil + default: // General Array* + return SetGaref(nil, nil, obj, basicArray, dimensions...) + } +} + +// SetGaref replaces the object obtainable by aref or garef with obj . The returned value is obj. +// The constraints on the basic-array, the general-array, and the sequence of indices z is the +// same as for aref and garef. +func SetGaref(_, _ *environment.Environment, obj, generalArray ilos.Instance, dimensions ...ilos.Instance) (ilos.Instance, ilos.Instance) { + if err := ensure(class.GeneralArrayStar, generalArray); err != nil { + return nil, err + } + if err := ensure(class.Integer, dimensions...); err != nil { + return nil, err + } + var array *instance.GeneralArrayStar + for _, dim := range dimensions { + index := int(dim.(instance.Integer)) + if array.Vector == nil || len(array.Vector) <= index { + return nil, instance.New(class.ProgramError) + } + array = array.Vector[index] + } + if array.Scalar == nil { + return nil, instance.New(class.ProgramError) + } + array.Scalar = obj + return obj, nil +} + +// ArrayDimensions returns a list of the dimensions of a given basic-array. +// An error shall be signaled if basic-array is not a basic-array (error-id. domain-error). +// The consequences are undefined if the returned list is modified. +func ArrayDimensions(_, _ *environment.Environment, basicArray ilos.Instance) (ilos.Instance, ilos.Instance) { + if err := ensure(class.BasicArray, basicArray); err != nil { + return nil, err + } + switch { + case instance.Of(class.String, basicArray): + return List(nil, nil, instance.New(class.Integer, len(basicArray.(instance.String)))) + case instance.Of(class.GeneralVector, basicArray): + return List(nil, nil, instance.New(class.Integer, len(basicArray.(instance.GeneralVector)))) + default: // General Array* + var array *instance.GeneralArrayStar + dimensions := []ilos.Instance{} + for array.Vector != nil { + dimensions = append(dimensions, instance.New(class.Integer, len(array.Vector))) + array = array.Vector[0] + } + return List(nil, nil, dimensions...) + } +} diff --git a/runtime/ilos/instance/basic-array.go b/runtime/ilos/instance/basic-array.go index 81267bd..60081bd 100644 --- a/runtime/ilos/instance/basic-array.go +++ b/runtime/ilos/instance/basic-array.go @@ -10,6 +10,31 @@ import ( "github.com/ta2gch/iris/runtime/ilos/class" ) +// +// General Array * +// + +type GeneralArrayStar struct { + Vector []*GeneralArrayStar + Scalar ilos.Instance +} + +func (GeneralArrayStar) Class() ilos.Class { + return class.GeneralArrayStar +} + +func (i GeneralArrayStar) GetSlotValue(key ilos.Instance, _ ilos.Class) (ilos.Instance, bool) { + return nil, false +} + +func (i GeneralArrayStar) SetSlotValue(key ilos.Instance, value ilos.Instance, _ ilos.Class) bool { + return false +} + +func (i GeneralArrayStar) String() string { + return "" +} + // // General Vector // @@ -21,20 +46,10 @@ func (GeneralVector) Class() ilos.Class { } func (i GeneralVector) GetSlotValue(key ilos.Instance, _ ilos.Class) (ilos.Instance, bool) { - if symbol, ok := key.(Symbol); ok && symbol == "LENGTH" { - return New(class.Integer, len(i)), true - } - if index, ok := key.(Integer); ok && int(index) < len(i) { - return i[int(index)], true - } return nil, false } func (i GeneralVector) SetSlotValue(key ilos.Instance, value ilos.Instance, _ ilos.Class) bool { - if index, ok := key.(Integer); ok && int(index) < len(i) { - i[int(index)] = value - return true - } return false } @@ -53,22 +68,10 @@ func (String) Class() ilos.Class { } func (i String) GetSlotValue(key ilos.Instance, _ ilos.Class) (ilos.Instance, bool) { - if symbol, ok := key.(Symbol); ok && symbol == "LENGTH" { - return New(class.Integer, len(i)), true - } - if index, ok := key.(Integer); ok && int(index) < len(i) { - return New(class.Character, i[int(index)]), true - } return nil, false } func (i String) SetSlotValue(key ilos.Instance, value ilos.Instance, _ ilos.Class) bool { - if index, ok := key.(Integer); ok && int(index) < len(i) { - if character, ok := value.(Character); ok { - i[index] = rune(character) - return true - } - } return false } diff --git a/runtime/ilos/instance/instance.go b/runtime/ilos/instance/instance.go index 3d43ef2..5b0f537 100644 --- a/runtime/ilos/instance/instance.go +++ b/runtime/ilos/instance/instance.go @@ -35,6 +35,8 @@ func New(c ilos.Class, s ...interface{}) ilos.Instance { return Null{} case class.GeneralVector: return GeneralVector(s[0].([]ilos.Instance)) + case class.GeneralArrayStar: + return &GeneralArrayStar{s[0].([]*GeneralArrayStar), s[1].(ilos.Instance)} case class.String: return String(s[0].(string)) default: From bafc807e040467715cf54b4f5060aed33ea1fda0 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Tue, 15 Aug 2017 10:57:26 +0900 Subject: [PATCH 176/228] Added sequence_functions --- runtime/sequence_functions.go | 232 ++++++++++++++++++++++++++++++++++ 1 file changed, 232 insertions(+) create mode 100644 runtime/sequence_functions.go diff --git a/runtime/sequence_functions.go b/runtime/sequence_functions.go new file mode 100644 index 0000000..1e4aea5 --- /dev/null +++ b/runtime/sequence_functions.go @@ -0,0 +1,232 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package runtime + +import ( + "math" + + "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/ilos" + "github.com/ta2gch/iris/runtime/ilos/class" + "github.com/ta2gch/iris/runtime/ilos/instance" +) + +// Length returns the length of sequence as an integer greater than or equal to 0. +// +// When sequence is a basic-vector, length returns its dimension. +// +// When sequence is a list, the result is the number of elements in the list; if an element is +// itself a list, the elements within this sublist are not counted. In the case of dotted lists, +// length returns the number of conses at the uppermost level of the list. For example, (length ' +// (a b . c)) ⇒ 2, since '(a b . c) ≡ (cons 'a (cons 'b 'c)). +// +// An error shall be signaled if sequence is not a basic-vector or a list +// (error-id. domain-error). +func Length(_, _ *environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { + switch { + case instance.Of(class.String, obj): + return instance.New(class.Integer, len(obj.(instance.String))), nil + case instance.Of(class.GeneralVector, obj): + return instance.New(class.Integer, len(obj.(instance.GeneralVector))), nil + case instance.Of(class.List, obj): + return instance.New(class.Integer, len(obj.(instance.List).Slice())), nil + } + // TODO: class.Seq + return nil, instance.New(class.DomainError, map[string]ilos.Instance{ + "OBJECT": obj, + "EXPECTED-CLASS": class.Object, + }) +} + +// Elt returns the element of sequence that has index z. Indexing is 0-based; i.e., z = 0 +// designates the first element, Given a sequence and an integer z satisfying 0 ≤ z < (length +// sequence). An error shall be signaled if z is an integer outside of the mentioned range +// (error-id. index-out-of-range). +// +// An error shall be signaled if sequence is not a basic-vector or a list or if z is not an +// integer (error-id. domain-error). +func Elt(_, _ *environment.Environment, sequence, z ilos.Instance) (ilos.Instance, ilos.Instance) { + if err := ensure(class.Integer, z); err != nil { + return nil, err + } + switch { + case instance.Of(class.String, sequence): + seq := sequence.(instance.String) + idx := int(z.(instance.Integer)) + if idx > 0 && len(seq) <= idx { + return nil, instance.New(class.ProgramError) + } + return instance.New(class.Character, seq[idx]), nil + case instance.Of(class.GeneralVector, sequence): + seq := sequence.(instance.GeneralVector) + idx := int(z.(instance.Integer)) + if idx > 0 && len(seq) <= idx { + return nil, instance.New(class.ProgramError) + } + return seq[idx], nil + case instance.Of(class.List, sequence): + seq := sequence.(instance.List).Slice() + idx := int(z.(instance.Integer)) + if idx > 0 && len(seq) <= idx { + return nil, instance.New(class.ProgramError) + } + return seq[idx], nil + } + return nil, instance.New(class.DomainError, map[string]ilos.Instance{ + "OBJECT": sequence, + "EXPECTED-CLASS": class.Object, + }) +} + +// SetElt is that these replace the object obtainable by elt with obj. The returned value is obj. +// +// An error shall be signaled if z is an integer outside of the valid range of indices +// (error-id. index-out-of-range). An error shall be signaled if sequence is not a basic-vector +// or a list or if z is not an integer (error-id. domain-error). obj may be any ISLISP object. +func SetElt(_, _ *environment.Environment, obj, sequence, z ilos.Instance) (ilos.Instance, ilos.Instance) { + if err := ensure(class.Integer, z); err != nil { + return nil, err + } + switch { + case instance.Of(class.String, sequence): + seq := sequence.(instance.String) + idx := int(z.(instance.Integer)) + if idx > 0 && len(seq) <= idx { + return nil, instance.New(class.ProgramError) + } + if err := ensure(class.Character, obj); err != nil { + return nil, err + } + seq[idx] = rune(obj.(instance.Character)) + return obj, nil + case instance.Of(class.GeneralVector, sequence): + seq := sequence.(instance.GeneralVector) + idx := int(z.(instance.Integer)) + if idx > 0 && len(seq) <= idx { + return nil, instance.New(class.ProgramError) + } + seq[idx] = obj + return obj, nil + case instance.Of(class.List, sequence): + seq := sequence.(instance.List).Slice() + idx := int(z.(instance.Integer)) + if idx > 0 && len(seq) <= idx { + return nil, instance.New(class.ProgramError) + } + for idx != 0 && instance.Of(class.Cons, sequence) { + idx-- + sequence = sequence.(*instance.Cons).Cdr + } + sequence.(*instance.Cons).Car = obj + return obj, nil + } + return nil, instance.New(class.DomainError, map[string]ilos.Instance{ + "OBJECT": sequence, + "EXPECTED-CLASS": class.Object, + }) +} + +// Subseq returns the subsequence of length z2 − z1, containing the elements with indices from +// z1 (inclusive) to z2 (exclusive). The subsequence is newly allocated, and has the same class +// as sequence, Given a sequence sequence and two integers z1 and z2 satisfying 0 ≤ z1 ≤ z2 ≤ +// (length sequence) +// +// An error shall be signaled if the requested subsequence cannot be allocated (error-id. +// cannot-create-sequence). An error shall be signaled if z1 or z2 are outside of the bounds +// mentioned (error-id. index-out-of-range). An error shall be signaled if sequence is not a +// basic-vector or a list, or if z1 is not an integer, or if z2 is not an integer +// (error-id. domain-error). +func Subseq(_, _ *environment.Environment, sequence, z1, z2 ilos.Instance) (ilos.Instance, ilos.Instance) { + if err := ensure(class.Integer, z1, z2); err != nil { + return nil, err + } + start := int(z1.(instance.Integer)) + end := int(z2.(instance.Integer)) + switch { + case instance.Of(class.String, sequence): + seq := sequence.(instance.String) + if !(0 <= start && start < len(seq) && 0 <= end && end < len(seq) && start <= end) { + return nil, instance.New(class.ProgramError) + } + return seq[start:end], nil + case instance.Of(class.GeneralVector, sequence): + seq := sequence.(instance.GeneralVector) + if !(0 <= start && start < len(seq) && 0 <= end && end < len(seq) && start <= end) { + return nil, instance.New(class.ProgramError) + } + return seq[start:end], nil + case instance.Of(class.List, sequence): + seq := sequence.(instance.List).Slice() + if !(0 < start && start < len(seq) && 0 < end && end < len(seq) && start <= end) { + return nil, instance.New(class.ProgramError) + } + return List(nil, nil, seq[start:end]...) + } + return nil, instance.New(class.DomainError, map[string]ilos.Instance{ + "OBJECT": sequence, + "EXPECTED-CLASS": class.Object, + }) +} + +// Destructively modifies destination to contain the results of applying function to +// successive elements in the sequences. The destination is returned. +// +// If destination and each element of sequences are not all the same length, the +// iteration terminates when the shortest sequence (of any of the sequences or the +// destination) is exhausted. +// +// The calls to function proceed from left to right, so that if function has +// side-effects, it can rely upon being called first on all of the elements with index +// 0, then on all of those numbered 1, and so on. +// +// An error shall be signaled if destination is not a basic-vector or a list +// (error-id. domain-error). +// +// An error shall be signaled if any sequence is not a basic-vector or a list +// (error-id. domain-error). +func mapInto(local, global *environment.Environment, destination, function ilos.Instance, sequences ...ilos.Instance) (ilos.Instance, ilos.Instance) { + if err := ensure(class.List, append(sequences, destination)...); err != nil { + if err := ensure(class.BasicVector, append(sequences, destination)...); err != nil { + return nil, err + } + } + if err := ensure(class.Function, function); err != nil { + return nil, err + } + max := 0.0 + for _, seq := range sequences { + switch { + case instance.Of(class.String, seq): + max = math.Max(max, float64(len(seq.(instance.String)))) + case instance.Of(class.GeneralVector, seq): + max = math.Max(max, float64(len(seq.(instance.GeneralVector)))) + case instance.Of(class.List, seq): + max = math.Max(max, float64(len(seq.(instance.List).Slice()))) + } + } + for i := 0; i < int(max); i++ { + arguments := make([]ilos.Instance, int(max)) + for _, seq := range sequences { + var err ilos.Instance + arguments[i], err = Elt(nil, nil, seq, instance.New(class.Integer, i)) + if err != nil { + return nil, err + } + } + args, err := List(nil, nil, arguments...) + if err != nil { + return nil, err + } + ret, err := function.(instance.Function).Apply(local, global, args) + if err != nil { + return nil, err + } + _, err = SetElt(nil, nil, ret, destination, instance.New(class.Integer, i)) + if err != nil { + return nil, err + } + } + return destination, nil +} From e189801b72d7b57341c7c98777272d1104d41cc9 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Tue, 15 Aug 2017 18:59:42 +0900 Subject: [PATCH 177/228] Some Update --- reader/parser/parser.go | 17 ++- reader/tokenizer/tokenizer.go | 46 ++++--- runtime/array_operations.go | 26 ++-- runtime/conditional_expressions.go | 14 +-- runtime/constants.go | 4 +- runtime/defining_operators.go | 26 ++-- runtime/dynamic_variables.go | 4 +- runtime/eval.go | 8 +- runtime/eval_test.go | 69 ----------- runtime/functions.go | 30 ++--- runtime/functions_test.go | 186 +++++++++++++++++++++++++++++ runtime/ilos/class/class.go | 2 +- runtime/ilos/instance/function.go | 13 +- runtime/iteration.go | 8 +- runtime/list_operations.go | 38 ++---- runtime/namedfunc.go | 23 ++-- runtime/non-local_exits.go | 6 +- runtime/number_class.go | 3 + runtime/sequence_functions.go | 24 ++-- runtime/string_class.go | 6 +- runtime/symbol_class.go | 2 +- runtime/test.go | 41 +++++++ runtime/util.go | 46 +++++-- runtime/variables.go | 8 +- runtime/vectors.go | 2 +- 25 files changed, 402 insertions(+), 250 deletions(-) delete mode 100644 runtime/eval_test.go create mode 100644 runtime/functions_test.go create mode 100644 runtime/test.go diff --git a/reader/parser/parser.go b/reader/parser/parser.go index 1563303..37357cc 100644 --- a/reader/parser/parser.go +++ b/reader/parser/parser.go @@ -75,16 +75,13 @@ func ParseAtom(tok string) (ilos.Instance, ilos.Instance) { if "nil" == tok { return instance.New(class.Null), nil } - if r := regexp.MustCompile("^:([<>/*=?_!$%[\\]^{}~0-9a-zA-Z]+)$").FindStringSubmatch(tok); len(r) >= 2 { - return instance.New(class.Symbol, strings.ToUpper(r[0])), nil - } - if r := regexp.MustCompile("^&([<>/*=?_!$%[\\]^{}~0-9a-zA-Z]+)$").FindStringSubmatch(tok); len(r) >= 2 { - return instance.New(class.Symbol, strings.ToUpper(r[0])), nil - } - if m, _ := regexp.MatchString("^\\|.*\\|$", tok); m { - return instance.New(class.Symbol, tok), nil - } - if m, _ := regexp.MatchString("^[<>/*=?_!$%[\\]^{}~a-zA-Z-][<>/*=?_!$%[\\]^{}~0-9a-zA-Z-]*$", tok); m { + str := `^(` + str += `[:&][a-zA-Z]+|` + str += `\|.*\||` + str += `\+|\-|1\+|1\-|` + str += `[a-zA-Z<>/*=?_!$%[\]^{}~][-a-zA-Z0-9+<>/*=?_!$%[\]^{}~]*|` + str += ")$" + if m, _ := regexp.MatchString(str, tok); m { return instance.New(class.Symbol, strings.ToUpper(tok)), nil } return nil, instance.New(class.ParseError, map[string]ilos.Instance{ diff --git a/reader/tokenizer/tokenizer.go b/reader/tokenizer/tokenizer.go index 4b1dd04..530b159 100644 --- a/reader/tokenizer/tokenizer.go +++ b/reader/tokenizer/tokenizer.go @@ -23,21 +23,22 @@ type Tokenizer struct { var re *regexp.Regexp func New(r io.Reader) *Tokenizer { - str := "" - str += "[-+]?[[:digit:]]+|" - str += "#[bB][-+]?[01]+|" - str += "#[oO][-+]?[0-7]+|" - str += "#[xX][-+]?[[:xdigit:]]+|" - str += "[-+]?[[:digit:]]+\\.[[:digit:]]+|" - str += "[-+]?[[:digit:]]+(?:\\.[[:digit:]]+)?[eE][-+]?[[:digit:]]+|" - str += "#\\\\newline|" - str += "#\\\\space|" - str += "#\\\\[[:graph:]]|" - str += "\".*\"|" - str += ":[<>/*=?_!$%[\\]^{}~0-9a-zA-Z]+|" - str += "\\|.*\\||" - str += "[<>/*=?_!$%[\\]^{}~a-zA-Z-][<>/*=?_!$%[\\]^{}~0-9a-zA-Z-]*|" - str += "[.()]|" + str := `` + str += `[-+]?[[:digit:]]+|` + str += `#[bB][-+]?[01]+|` + str += `#[oO][-+]?[0-7]+|` + str += `#[xX][-+]?[[:xdigit:]]+|` + str += `[-+]?[[:digit:]]+\.[[:digit:]]+|` + str += `[-+]?[[:digit:]]+(?:\.[[:digit:]]+)?[eE][-+]?[[:digit:]]+|` + str += `#\\newline|` + str += `#\\space|` + str += `#\\[[:graph:]]|` + str += `".*"|` // TODO: support \" + str += `[:&][a-zA-Z]+|` + str += `\|.*\||` // TODO: support \" + str += `\+|\-|1\+|1\-|` + str += `[a-zA-Z<>/*=?_!$%[\]^{}~][-a-zA-Z0-9+<>/*=?_!$%[\]^{}~]*|` + str += `[.()]|` str += "#'|,@?|'|`|#[[:digit:]]*[aA]" re = regexp.MustCompile(str) sc := bufio.NewScanner(r) @@ -54,10 +55,21 @@ func (t *Tokenizer) Next() (string, ilos.Instance) { func splitter(data []byte, atEOF bool) (advance int, token []byte, err error) { if atEOF { - return len(data), data, nil + advance = len(data) + token = data + err = nil + return } if loc := re.FindIndex(data); loc != nil { - return loc[1], data[loc[0]:loc[1]], nil + advance = loc[1] + token = data[loc[0]:loc[1]] + err = nil + if ok, _ := regexp.Match(`^[-+]?[[:digit:]]+$`, token); ok && len(data) > loc[1] && data[loc[1]] == '.' { + advance = 0 + token = nil + err = nil + } + return } return } diff --git a/runtime/array_operations.go b/runtime/array_operations.go index f3fdccb..dc4df15 100644 --- a/runtime/array_operations.go +++ b/runtime/array_operations.go @@ -62,7 +62,7 @@ func CreateArray(_, _ *environment.Environment, dimensions ilos.Instance, initia dim := dimensions.(instance.List).Slice() elt := Nil if len(initialElement) > 1 { - return nil, instance.New(class.ProgramError) + return ProgramError("ARITY-ERROR") } if len(initialElement) == 1 { elt = initialElement[0] @@ -110,20 +110,20 @@ func Aref(_, _ *environment.Environment, basicArray ilos.Instance, dimensions .. switch { case instance.Of(class.String, basicArray): if len(dimensions) != 1 { - return nil, instance.New(class.ProgramError) + return ProgramError("ARITY-ERROR") } index := int(dimensions[0].(instance.Integer)) if len(basicArray.(instance.String)) <= index { - return nil, instance.New(class.ProgramError) + return ProgramError("INDEX-OUT-OF-RANGE") } return instance.New(class.Character, basicArray.(instance.String)[index]), nil case instance.Of(class.GeneralVector, basicArray): if len(dimensions) != 1 { - return nil, instance.New(class.ProgramError) + return ProgramError("ARITY-ERROR") } index := int(dimensions[0].(instance.Integer)) if len(basicArray.(instance.GeneralVector)) <= index { - return nil, instance.New(class.ProgramError) + return ProgramError("INDEX-OUT-OF-RANGE") } return basicArray.(instance.GeneralVector)[index], nil default: // General Array* @@ -144,12 +144,12 @@ func Garef(_, _ *environment.Environment, generalArray ilos.Instance, dimensions for _, dim := range dimensions { index := int(dim.(instance.Integer)) if array.Vector == nil || len(array.Vector) <= index { - return nil, instance.New(class.ProgramError) + return ProgramError("INDEX-OUT-OF-RANGE") } array = array.Vector[index] } if array.Scalar == nil { - return nil, instance.New(class.ProgramError) + return ProgramError("INDEX-OUT-OF-RANGE") } return array.Scalar, nil } @@ -170,21 +170,21 @@ func SetAref(_, _ *environment.Environment, obj, basicArray ilos.Instance, dimen return nil, err } if len(dimensions) != 1 { - return nil, instance.New(class.ProgramError) + return ProgramError("ARITY-ERROR") } index := int(dimensions[0].(instance.Integer)) if len(basicArray.(instance.String)) <= index { - return nil, instance.New(class.ProgramError) + return ProgramError("INDEX-OUT-OF-RANGE") } basicArray.(instance.String)[index] = rune(obj.(instance.Character)) return obj, nil case instance.Of(class.GeneralVector, basicArray): if len(dimensions) != 1 { - return nil, instance.New(class.ProgramError) + return ProgramError("ARITY-ERROR") } index := int(dimensions[0].(instance.Integer)) if len(basicArray.(instance.GeneralVector)) <= index { - return nil, instance.New(class.ProgramError) + return ProgramError("INDEX-OUT-OF-RANGE") } basicArray.(instance.GeneralVector)[index] = obj return obj, nil @@ -207,12 +207,12 @@ func SetGaref(_, _ *environment.Environment, obj, generalArray ilos.Instance, di for _, dim := range dimensions { index := int(dim.(instance.Integer)) if array.Vector == nil || len(array.Vector) <= index { - return nil, instance.New(class.ProgramError) + return ProgramError("INDEX-OUT-OF-RANGE") } array = array.Vector[index] } if array.Scalar == nil { - return nil, instance.New(class.ProgramError) + return ProgramError("INDEX-OUT-OF-RANGE") } array.Scalar = obj return obj, nil diff --git a/runtime/conditional_expressions.go b/runtime/conditional_expressions.go index 131b760..ebc672f 100644 --- a/runtime/conditional_expressions.go +++ b/runtime/conditional_expressions.go @@ -27,7 +27,7 @@ func If(local, global *environment.Environment, testForm, thenForm ilos.Instance return Eval(local, global, thenForm) } if len(elseForm) > 1 { - return nil, instance.New(class.ProgramError) + return ProgramError("ARITY-ERROR") } if len(elseForm) == 0 { return Nil, nil @@ -48,7 +48,7 @@ func Cond(local, global *environment.Environment, testFrom ...ilos.Instance) (il } s := tf.(instance.List).Slice() if len(s) == 0 { - return nil, instance.New(class.ProgramError) + return ProgramError("ARITY-ERROR") } ret, err := Eval(local, global, s[0]) if err != nil { @@ -85,7 +85,7 @@ func Case(local, global *environment.Environment, key ilos.Instance, pattern ... } form := pat.(instance.List).Slice() if len(form) < 1 { - return nil, instance.New(class.ProgramError) + return ProgramError("ARITY-ERROR") } if idx == len(pattern)-1 && form[0] == T { return Progn(local, global, form[1:]...) @@ -132,7 +132,7 @@ func CaseUsing(local, global *environment.Environment, key, pred ilos.Instance, } form := pat.(instance.List).Slice() if len(form) < 1 { - return nil, instance.New(class.ProgramError) + return ProgramError("ARITY-ERROR") } if idx == len(pattern)-1 && form[0] == T { return Progn(local, global, form[1:]...) @@ -142,11 +142,7 @@ func CaseUsing(local, global *environment.Environment, key, pred ilos.Instance, } keys := form[0].(instance.List).Slice() for _, k := range keys { - args, err := List(nil, nil, k, key) - if err != nil { - return nil, err - } - ret, err := pred.(instance.Function).Apply(local, global, args) + ret, err := pred.(instance.Function).Apply(local, global, k, key) if err != nil { return nil, err } diff --git a/runtime/constants.go b/runtime/constants.go index 2c38994..7a9271b 100644 --- a/runtime/constants.go +++ b/runtime/constants.go @@ -9,6 +9,8 @@ import ( "github.com/ta2gch/iris/runtime/ilos" ) -func quote(local, global *environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { +// Quote is used to include any object in an ISLisp text. +// A quoted expression denotes a reference to an object. +func Quote(local, global *environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { return obj, nil } diff --git a/runtime/defining_operators.go b/runtime/defining_operators.go index 3e8baba..a5a27e3 100644 --- a/runtime/defining_operators.go +++ b/runtime/defining_operators.go @@ -8,7 +8,6 @@ import ( "github.com/ta2gch/iris/runtime/environment" "github.com/ta2gch/iris/runtime/ilos" "github.com/ta2gch/iris/runtime/ilos/class" - "github.com/ta2gch/iris/runtime/ilos/instance" ) // Defconstant is used to define a named constant in the variable namespace of the current toplevel @@ -28,9 +27,7 @@ func Defconstant(local, global *environment.Environment, name, form ilos.Instanc if err != nil { return nil, err } - if !global.Constant.Define(name, ret) { - return nil, instance.New(class.ProgramError) - } + global.Constant.Define(name, ret) return name, nil } @@ -47,16 +44,14 @@ func Defglobal(local, global *environment.Environment, name, form ilos.Instance) if err := ensure(class.Symbol, name); err != nil { return nil, err } + if _, ok := global.Constant.Get(name); ok { + return ProgramError("IMMUTABLE-BIDING") + } ret, err := Eval(local, global, form) if err != nil { return nil, err } - if _, ok := global.Constant.Get(name); ok { - return nil, instance.New(class.ProgramError) - } - if !global.Variable.Define(name, ret) { - return nil, instance.New(class.ProgramError) - } + global.Variable.Define(name, ret) return name, nil } @@ -68,13 +63,14 @@ func Defdynamic(local, global *environment.Environment, name, form ilos.Instance if err := ensure(class.Symbol, name); err != nil { return nil, err } + if _, ok := global.Constant.Get(name); ok { + return ProgramError("IMMUTABLE-BIDING") + } ret, err := Eval(local, global, form) if err != nil { return nil, err } - if !global.DynamicVariable.Define(name, ret) { - return nil, instance.New(class.ProgramError) - } + global.DynamicVariable.Define(name, ret) return name, nil } @@ -96,8 +92,6 @@ func Defun(local, global *environment.Environment, functionName, lambdaList ilos if err != nil { return nil, err } - if !global.Function.Define(functionName, ret) { - return nil, instance.New(class.ProgramError) - } + global.Function.Define(functionName, ret) return functionName, nil } diff --git a/runtime/dynamic_variables.go b/runtime/dynamic_variables.go index dc00910..2da9553 100644 --- a/runtime/dynamic_variables.go +++ b/runtime/dynamic_variables.go @@ -94,7 +94,7 @@ func DyamicLet(local, global *environment.Environment, varForm ilos.Instance, bo } s := cadr.(instance.List).Slice() if len(s) != 2 { - return nil, instance.New(class.ProgramError) + return ProgramError("ARITY-ERROR") } f, err := Eval(local, global, s[1]) if err != nil { @@ -104,7 +104,7 @@ func DyamicLet(local, global *environment.Environment, varForm ilos.Instance, bo } for v, f := range vfs { if !local.DynamicVariable.Define(v, f) { - return nil, instance.New(class.ProgramError) + return ProgramError("IMMUTABLE-BINDING") } } return Progn(local, global, bodyForm...) diff --git a/runtime/eval.go b/runtime/eval.go index ad3a41c..0d488ec 100644 --- a/runtime/eval.go +++ b/runtime/eval.go @@ -50,7 +50,7 @@ func evalLambda(local, global *environment.Environment, car, cdr ilos.Instance) env := environment.New() env.DynamicVariable = append(local.DynamicVariable, env.DynamicVariable...) env.CatchTag = append(local.CatchTag, env.CatchTag...) - ret, err := fun.(instance.Applicable).Apply(env, global, arguments) + ret, err := fun.(instance.Applicable).Apply(env, global, arguments.(instance.List).Slice()...) if err != nil { return nil, err, true } @@ -68,7 +68,7 @@ func evalSpecial(local, global *environment.Environment, car, cdr ilos.Instance) } if spl != nil { env := environment.New().Merge(local) - ret, err := spl.(instance.Applicable).Apply(env, global, cdr) + ret, err := spl.(instance.Applicable).Apply(env, global, cdr.(instance.List).Slice()...) if err != nil { return nil, err, true } @@ -90,7 +90,7 @@ func evalMacro(local, global *environment.Environment, car, cdr ilos.Instance) ( env := environment.New() env.DynamicVariable = append(local.DynamicVariable, env.DynamicVariable...) env.CatchTag = append(local.DynamicVariable, env.CatchTag...) - ret, err := mac.(instance.Applicable).Apply(env, global, cdr) + ret, err := mac.(instance.Applicable).Apply(env, global, cdr.(instance.List).Slice()...) if err != nil { return nil, err, true } @@ -120,7 +120,7 @@ func evalFunction(local, global *environment.Environment, car, cdr ilos.Instance if err != nil { return nil, err, true } - ret, err := fun.(instance.Applicable).Apply(env, global, arguments) + ret, err := fun.(instance.Applicable).Apply(env, global, arguments.(instance.List).Slice()...) if err != nil { return nil, err, true } diff --git a/runtime/eval_test.go b/runtime/eval_test.go deleted file mode 100644 index 9e31ee7..0000000 --- a/runtime/eval_test.go +++ /dev/null @@ -1,69 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at http://mozilla.org/MPL/2.0/. - -package runtime - -import ( - "reflect" - "testing" - - "github.com/ta2gch/iris/runtime/environment" - "github.com/ta2gch/iris/runtime/ilos" - "github.com/ta2gch/iris/runtime/ilos/class" - "github.com/ta2gch/iris/runtime/ilos/instance" -) - -func TestEval(t *testing.T) { - local := environment.New() - global := environment.TopLevel - defun("INC", func(local, global *environment.Environment, arg ilos.Instance) (ilos.Instance, ilos.Instance) { - return instance.New(class.Integer, int(arg.(instance.Integer))+1), nil - }) - defglobal("*PI*", Pi) - defmacro("MINC", func(local, global *environment.Environment, arg ilos.Instance) (ilos.Instance, ilos.Instance) { - return instance.New(class.Cons, instance.New(class.Symbol, "INC"), instance.New(class.Cons, arg, Nil)), nil - }) - type arguments struct { - obj ilos.Instance - local *environment.Environment - global *environment.Environment - } - tests := []struct { - name string - arguments arguments - want ilos.Instance - wantErr bool - }{ - { - name: "local variable", - arguments: arguments{readFromString("*pi*"), local, global}, - want: Pi, - wantErr: false, - }, - { - name: "local function", - arguments: arguments{readFromString("(inc (inc 1))"), local, global}, - want: instance.New(class.Integer, 3), - wantErr: false, - }, - { - name: "local macro", - arguments: arguments{readFromString("(minc (minc 1))"), local, global}, - want: instance.New(class.Integer, 3), - wantErr: false, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, err := Eval(tt.arguments.local, tt.arguments.global, tt.arguments.obj) - if (err != nil) != tt.wantErr { - t.Errorf("Eval() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !reflect.DeepEqual(got, tt.want) { - t.Errorf("Eval() = %v, want %v", got, tt.want) - } - }) - } -} diff --git a/runtime/functions.go b/runtime/functions.go index ca19bcf..5a31a34 100644 --- a/runtime/functions.go +++ b/runtime/functions.go @@ -112,7 +112,7 @@ func Labels(local, global *environment.Environment, functions ilos.Instance, bod } definition := function.(instance.List).Slice() if len(definition) < 2 { - return nil, instance.New(class.ProgramError) + return ProgramError("ARITY-ERROR") } functionName := definition[0] lambdaList := definition[1] @@ -122,7 +122,7 @@ func Labels(local, global *environment.Environment, functions ilos.Instance, bod return nil, err } if !local.Function.Define(functionName, fun) { - return nil, instance.New(class.ProgramError) + return ProgramError("IMMUTABLE-BINDING") } } return Progn(local, global, bodyForm...) @@ -141,7 +141,7 @@ func Flet(local, global *environment.Environment, functions ilos.Instance, bodyF } definition := function.(instance.List).Slice() if len(definition) < 2 { - return nil, instance.New(class.ProgramError) + return ProgramError("ARITY-ERROR") } functionName := definition[0] lambdaList := definition[1] @@ -151,7 +151,7 @@ func Flet(local, global *environment.Environment, functions ilos.Instance, bodyF return nil, err } if !env.Function.Define(functionName, fun) { - return nil, instance.New(class.ProgramError) + return ProgramError("IMMUTABLE-BIDING") } } return Progn(env, global, bodyForm...) @@ -164,22 +164,14 @@ func Flet(local, global *environment.Environment, functions ilos.Instance, bodyF // Each obj may be any ISLISP object. An error shall be signaled // if list is not a proper list (error-id. improper-argument-list). func Apply(local, global *environment.Environment, function ilos.Instance, obj ...ilos.Instance) (ilos.Instance, ilos.Instance) { - list := Nil - if instance.Of(class.List, obj[len(obj)-1]) { - list = obj[len(obj)-1] - if !isProperList(list) { - return nil, instance.New(class.ProgramError) - } - obj = obj[:len(obj)-1] - } - for i := len(obj) - 1; i >= 0; i-- { - list = instance.New(class.Cons, obj[i], list) - } if err := ensure(class.Function, function); err != nil { return nil, err } - ret, err := function.(instance.Applicable).Apply(local, global, list) - return ret, err + if err := ensure(class.List, obj[len(obj)-1]); err != nil { + return nil, err + } + obj = append(obj[:len(obj)-1], obj[len(obj)-1].(instance.List).Slice()...) + return function.(instance.Applicable).Apply(local, global, obj...) } // Funcall activates the specified function function and returns the value that the function returns. @@ -188,6 +180,6 @@ func Apply(local, global *environment.Environment, function ilos.Instance, obj . // An error shall be signaled if function is not a function (error-id. domain-error). // Each obj may be any ISLISP object. func Funcall(local, global *environment.Environment, function ilos.Instance, obj ...ilos.Instance) (ilos.Instance, ilos.Instance) { - ret, err := Apply(local, global, function, obj...) - return ret, err + obj = append(obj, Nil) + return Apply(local, global, function, obj...) } diff --git a/runtime/functions_test.go b/runtime/functions_test.go new file mode 100644 index 0000000..2349b51 --- /dev/null +++ b/runtime/functions_test.go @@ -0,0 +1,186 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package runtime + +import ( + "testing" +) + +func TestFunctionp(t *testing.T) { + defun(Car) + defspecial(Function) + defun(Functionp) + defglobal("T", T) + tests := []test{ + { + exp: `(functionp (function car))`, + want: `T`, + wantErr: false, + }, + } + execTests(t, Functionp, tests) +} + +func TestFunction(t *testing.T) { + defun2("-", Substruct) + defspecial(Function) + defspecial(Quote) + defun(Funcall) + defun(Apply) + tests := []test{ + { + exp: `(funcall (function -) 3)`, + want: `-3`, + wantErr: false, + }, + { + exp: `(apply #'- '(4 3))`, + want: `1`, + wantErr: false, + }, + } + execTests(t, Function, tests) +} + +func TestLambda(t *testing.T) { + defun2("*", Multiply) + defun2("+", Add) + defspecial(Lambda) + defspecial(Quote) + defun(Funcall) + defun2("-", Substruct) + tests := []test{ + { + exp: `((lambda (x y) (+ (* x x) (* y y))) 3 4)`, + want: `25`, + wantErr: false, + }, + { + exp: `((lambda (x y &rest z) z) 3 4 5 6)`, + want: `'(5 6)`, + wantErr: false, + }, + { + exp: `((lambda (x y :rest z) z) 3 4 5 6)`, + want: `'(5 6)`, + wantErr: false, + }, + { + exp: `(funcall (lambda (x y) (- y (* x y))) 7 3)`, + want: `-18`, + wantErr: false, + }, + } + execTests(t, Lambda, tests) +} + +func TestLabels(t *testing.T) { + defspecial(If) + defspecial(Labels) + defglobal("NIL", Nil) + defglobal("T", T) + defun2("=", NumberEqual) + defun2("-", Substruct) + tests := []test{ + { + exp: `(labels ((evenp (n) + (if (= n 0) + t + (oddp (- n 1)))) + (oddp (n) + (if (= n 0) + nil + (evenp (- n 1))))) + (evenp 88))`, + want: `T`, + wantErr: false, + }, + } + execTests(t, Labels, tests) +} + +func TestFlet(t *testing.T) { + defun2("+", Add) + defspecial(Flet) + tests := []test{ + { + exp: ` + (flet ((f (x) (+ x 3))) + (flet ((f (x) (+ x (f x)))) + (f 7))) + `, + want: `17`, + wantErr: false, + }, + } + execTests(t, Flet, tests) +} + +func TestApply(t *testing.T) { + defun2("+", Add) + defun(Apply) + defspecial(Quote) + defspecial(If) + defun2("<", NumberLessThan) + defun2("*", Multiply) + defun(Min) + defun(Max) + defun(List) + defspecial(Defun) + defspecial(Lambda) + defun(Funcall) + defspecial(Function) + defun(Sqrt) + tests := []test{ + { + exp: ` + (apply (if (< 1 2) (function max) (function min)) + 1 2 (list 3 4)) + `, + want: `4`, + wantErr: false, + }, + { + exp: ` + (defun compose (f g) + (lambda (:rest args) + (funcall f (apply g args))))) + `, + want: `'compose`, + wantErr: false, + }, + { + exp: `(funcall (compose (function sqrt) (function *)) 12 75)`, + want: `30`, + wantErr: false, + }, + } + execTests(t, Apply, tests) +} + +func TestFuncall(t *testing.T) { + defspecial(Let) + defspecial(Quote) + defun(Funcall) + defspecial(Cond) + defun(Car) + defspecial(Lambda) + defglobal("T", T) + defun(Listp) + defspecial(Function) + tests := []test{ + { + exp: ` + (let ((x '(1 2 3))) + (funcall (cond ((listp x) (function car)) + (t (lambda (x) (cons x 1)))) + x)) + `, + want: `1`, + wantErr: false, + }, + } + execTests(t, Funcall, tests) +} diff --git a/runtime/ilos/class/class.go b/runtime/ilos/class/class.go index f4c5421..3d917a4 100644 --- a/runtime/ilos/class/class.go +++ b/runtime/ilos/class/class.go @@ -56,7 +56,7 @@ var FloatingPointOnderflow = &builtinclass{[]ilos.Class{ArithmeticError}, []stri var FloatingPointUnderflow = &builtinclass{[]ilos.Class{ArithmeticError}, []string{}, ""} var ControlError = &builtinclass{[]ilos.Class{Error}, []string{}, ""} var ParseError = &builtinclass{[]ilos.Class{Error}, []string{"STRING", "EXPECTED-CLASS"}, ""} -var ProgramError = &builtinclass{[]ilos.Class{Error}, []string{}, ""} +var ProgramError = &builtinclass{[]ilos.Class{Error}, []string{"CAUSE"}, ""} var DomainError = &builtinclass{[]ilos.Class{ProgramError}, []string{"OBJECT", "EXPECTED-CLASS"}, ""} var UndefinedEntity = &builtinclass{[]ilos.Class{ProgramError}, []string{"NAME", "NAMESPACE"}, ""} var UndefinedVariable = &builtinclass{[]ilos.Class{UndefinedEntity}, []string{}, ""} diff --git a/runtime/ilos/instance/function.go b/runtime/ilos/instance/function.go index 801bd83..75eba65 100644 --- a/runtime/ilos/instance/function.go +++ b/runtime/ilos/instance/function.go @@ -14,7 +14,7 @@ import ( ) type Applicable interface { - Apply(*environment.Environment, *environment.Environment, ilos.Instance) (ilos.Instance, ilos.Instance) + Apply(*environment.Environment, *environment.Environment, ...ilos.Instance) (ilos.Instance, ilos.Instance) } type Function struct { @@ -38,18 +38,17 @@ func (f Function) String() string { return fmt.Sprintf("#%v", f.Class()) } -func (f Function) Apply(local, global *environment.Environment, arguments ilos.Instance) (ilos.Instance, ilos.Instance) { +func (f Function) Apply(local, global *environment.Environment, arguments ...ilos.Instance) (ilos.Instance, ilos.Instance) { fv := reflect.ValueOf(f.function) ft := reflect.TypeOf(f.function) argv := []reflect.Value{reflect.ValueOf(local), reflect.ValueOf(global)} - if !Of(class.List, arguments) { - return nil, New(class.ProgramError) - } - for _, cadr := range arguments.(List).Slice() { + for _, cadr := range arguments { argv = append(argv, reflect.ValueOf(cadr)) } if ft.NumIn() != len(argv) && (!ft.IsVariadic() || ft.NumIn()-2 >= len(argv)) { - return nil, New(class.ProgramError) + return nil, New(class.ProgramError, map[string]ilos.Instance{ + "CAUSE": New(class.String, fmt.Sprintf("ARITY-ERROR in %v", f.name)), + }) } rets := fv.Call(argv) a, _ := rets[0].Interface().(ilos.Instance) diff --git a/runtime/iteration.go b/runtime/iteration.go index 7e3aa5a..ec7077b 100644 --- a/runtime/iteration.go +++ b/runtime/iteration.go @@ -69,10 +69,10 @@ func For(local, global *environment.Environment, iterationSpecs, endTestAndResul var1 := i[0] init := i[1] if !local.Variable.Define(var1, init) { - return nil, instance.New(class.ProgramError) + return ProgramError("IMMUTABLE-BINDING") } default: - return nil, instance.New(class.ProgramError) + return ProgramError("ARITY-ERROR") } } if err := ensure(class.List, endTestAndResults); err != nil { @@ -104,10 +104,10 @@ func For(local, global *environment.Environment, iterationSpecs, endTestAndResul var1 := i[0] step := i[2] if local.Variable.Set(var1, step) { - return nil, instance.New(class.ProgramError) + return ProgramError("IMMUTABLE-BINDING") } default: - return nil, instance.New(class.ProgramError) + return ProgramError("ARITY-ERROR") } } test, err = Eval(local, global, endTest) diff --git a/runtime/list_operations.go b/runtime/list_operations.go index b427e66..46646c5 100644 --- a/runtime/list_operations.go +++ b/runtime/list_operations.go @@ -32,7 +32,7 @@ func CreateList(_, _ *environment.Environment, i ilos.Instance, initialElement . return nil, err } if len(initialElement) > 1 { - return nil, instance.New(class.ProgramError) + return ProgramError("ARITY-ERROR") } elm := Nil if len(initialElement) == 1 { @@ -158,11 +158,7 @@ func Mapcar(local, global *environment.Environment, function, list1 ilos.Instanc for j, list := range lists { arguments[j] = list.(instance.List).Slice()[i] } - args, err := List(nil, nil, arguments...) - if err != nil { - return nil, err - } - ret, err := function.(instance.Function).Apply(local, global, args) + ret, err := function.(instance.Function).Apply(local, global, arguments...) if err != nil { return nil, err } @@ -190,11 +186,7 @@ func Mapc(local, global *environment.Environment, function, list1 ilos.Instance, for j, list := range lists { arguments[j] = list.(instance.List).Slice()[i] } - args, err := List(nil, nil, arguments...) - if err != nil { - return nil, err - } - if _, err = function.(instance.Function).Apply(local, global, args); err != nil { + if _, err := function.(instance.Function).Apply(local, global, arguments...); err != nil { return nil, err } } @@ -222,11 +214,7 @@ func Mapcan(local, global *environment.Environment, function, list1 ilos.Instanc for j, list := range lists { arguments[j] = list.(instance.List).Slice()[i] } - args, err := List(nil, nil, arguments...) - if err != nil { - return nil, err - } - ret, err := function.(instance.Function).Apply(local, global, args) + ret, err := function.(instance.Function).Apply(local, global, arguments...) if err != nil { return nil, err } @@ -260,11 +248,7 @@ func Maplist(local, global *environment.Environment, function, list1 ilos.Instan return nil, err } } - args, err := List(nil, nil, arguments...) - if err != nil { - return nil, err - } - ret, err := function.(instance.Function).Apply(local, global, args) + ret, err := function.(instance.Function).Apply(local, global, arguments...) if err != nil { return nil, err } @@ -296,11 +280,7 @@ func Mapl(local, global *environment.Environment, function, list1 ilos.Instance, return nil, err } } - args, err := List(nil, nil, arguments...) - if err != nil { - return nil, err - } - if _, err := function.(instance.Function).Apply(local, global, args); err != nil { + if _, err := function.(instance.Function).Apply(local, global, arguments...); err != nil { return nil, err } } @@ -332,11 +312,7 @@ func Mapcon(local, global *environment.Environment, function, list1 ilos.Instanc return nil, err } } - args, err := List(nil, nil, arguments...) - if err != nil { - return nil, err - } - ret, err := function.(instance.Function).Apply(local, global, args) + ret, err := function.(instance.Function).Apply(local, global, arguments...) if err != nil { return nil, err } diff --git a/runtime/namedfunc.go b/runtime/namedfunc.go index 594b3d8..23dd9f0 100644 --- a/runtime/namedfunc.go +++ b/runtime/namedfunc.go @@ -17,12 +17,13 @@ func checkLambdaList(lambdaList ilos.Instance) ilos.Instance { } cdr := lambdaList.(instance.List).Slice() for i, cadr := range cdr { - if !instance.Of(class.Symbol, cadr) { - return instance.New(class.ProgramError) + if err := ensure(class.Symbol, cadr); err != nil { + return err } if cadr == instance.New(class.Symbol, ":REST") || cadr == instance.New(class.Symbol, "&REST") { if len(cdr) != i+2 { - return instance.New(class.ProgramError) + _, err := ProgramError("ARITY-ERROR") + return err } } } @@ -45,28 +46,24 @@ func newNamedFunction(local, global *environment.Environment, functionName, lamb return instance.New(class.Function, functionName, func(local, global *environment.Environment, arguments ...ilos.Instance) (ilos.Instance, ilos.Instance) { local.Merge(lexical) if (variadic && len(parameters)-2 > len(arguments)) || (!variadic && len(parameters) != len(arguments)) { - v := Nil - for i := len(arguments) - 1; i >= 0; i-- { - v = instance.New(class.Cons, arguments[i], v) - } - return nil, instance.New(class.ProgramError) + return ProgramError("ARITY-ERROR") } for idx := range parameters { key := parameters[idx] if key == instance.New(class.Symbol, ":REST") || key == instance.New(class.Symbol, "&REST") { key := parameters[idx+1] - value := Nil - for i := len(arguments) - 1; i >= idx; i-- { - value = instance.New(class.Cons, arguments[i], value) + value, err := List(nil, nil, arguments[idx:]...) + if err != nil { + return nil, err } if !local.Variable.Define(key, value) { - return nil, instance.New(class.ProgramError) + return ProgramError("IMMUTABLE-BINDING") } break } value := arguments[idx] if !local.Variable.Define(key, value) { - return nil, instance.New(class.ProgramError) + return ProgramError("IMMUTABLE-BINDING") } } return Progn(local, global, forms...) diff --git a/runtime/non-local_exits.go b/runtime/non-local_exits.go index 3c63368..5ab64f5 100644 --- a/runtime/non-local_exits.go +++ b/runtime/non-local_exits.go @@ -51,7 +51,7 @@ func Block(local, global *environment.Environment, tag ilos.Instance, body ...il }) } if !local.BlockTag.Define(tag, nil) { - return nil, instance.New(class.ProgramError) + return ProgramError("IMMUTABLE-BINDING") } var fail ilos.Instance sucess := Nil @@ -109,7 +109,7 @@ func Catch(local, global *environment.Environment, tag ilos.Instance, body ...il return nil, instance.New(class.DomainError, tag, class.Object) } if !local.CatchTag.Define(tag, nil) { - return nil, instance.New(class.ProgramError) + return ProgramError("IMMUTABLE-BINDING") } var fail ilos.Instance sucess := Nil @@ -162,7 +162,7 @@ func Tagbody(local, global *environment.Environment, body ...ilos.Instance) (ilo cddr := instance.New(class.GeneralVector, body[idx+1:]) if !instance.Of(class.Cons, cadr) { if !local.TagbodyTag.Define(cadr, cddr) { - return nil, instance.New(class.ProgramError) + return ProgramError("IMMUTABLE-BINDING") } } } diff --git a/runtime/number_class.go b/runtime/number_class.go index faf98a5..f08a72a 100644 --- a/runtime/number_class.go +++ b/runtime/number_class.go @@ -359,6 +359,9 @@ func Sqrt(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos.I "EXPECTED-CLASS": class.Number, }) } + if math.Ceil(math.Sqrt(a)) == math.Sqrt(a) { + return instance.New(class.Integer, int(math.Sqrt(a))), nil + } return instance.New(class.Float, math.Sqrt(a)), nil } diff --git a/runtime/sequence_functions.go b/runtime/sequence_functions.go index 1e4aea5..293d690 100644 --- a/runtime/sequence_functions.go +++ b/runtime/sequence_functions.go @@ -56,21 +56,21 @@ func Elt(_, _ *environment.Environment, sequence, z ilos.Instance) (ilos.Instanc seq := sequence.(instance.String) idx := int(z.(instance.Integer)) if idx > 0 && len(seq) <= idx { - return nil, instance.New(class.ProgramError) + return ProgramError("INDEX-OUT-OF-RANGE") } return instance.New(class.Character, seq[idx]), nil case instance.Of(class.GeneralVector, sequence): seq := sequence.(instance.GeneralVector) idx := int(z.(instance.Integer)) if idx > 0 && len(seq) <= idx { - return nil, instance.New(class.ProgramError) + return ProgramError("INDEX-OUT-OF-RANGE") } return seq[idx], nil case instance.Of(class.List, sequence): seq := sequence.(instance.List).Slice() idx := int(z.(instance.Integer)) if idx > 0 && len(seq) <= idx { - return nil, instance.New(class.ProgramError) + return ProgramError("INDEX-OUT-OF-RANGE") } return seq[idx], nil } @@ -94,7 +94,7 @@ func SetElt(_, _ *environment.Environment, obj, sequence, z ilos.Instance) (ilos seq := sequence.(instance.String) idx := int(z.(instance.Integer)) if idx > 0 && len(seq) <= idx { - return nil, instance.New(class.ProgramError) + return ProgramError("INDEX-OUT-OF-RANGE") } if err := ensure(class.Character, obj); err != nil { return nil, err @@ -105,7 +105,7 @@ func SetElt(_, _ *environment.Environment, obj, sequence, z ilos.Instance) (ilos seq := sequence.(instance.GeneralVector) idx := int(z.(instance.Integer)) if idx > 0 && len(seq) <= idx { - return nil, instance.New(class.ProgramError) + return ProgramError("INDEX-OUT-OF-RANGE") } seq[idx] = obj return obj, nil @@ -113,7 +113,7 @@ func SetElt(_, _ *environment.Environment, obj, sequence, z ilos.Instance) (ilos seq := sequence.(instance.List).Slice() idx := int(z.(instance.Integer)) if idx > 0 && len(seq) <= idx { - return nil, instance.New(class.ProgramError) + return ProgramError("INDEX-OUT-OF-RANGE") } for idx != 0 && instance.Of(class.Cons, sequence) { idx-- @@ -148,19 +148,19 @@ func Subseq(_, _ *environment.Environment, sequence, z1, z2 ilos.Instance) (ilos case instance.Of(class.String, sequence): seq := sequence.(instance.String) if !(0 <= start && start < len(seq) && 0 <= end && end < len(seq) && start <= end) { - return nil, instance.New(class.ProgramError) + return ProgramError("INDEX-OUT-OF-RANGE") } return seq[start:end], nil case instance.Of(class.GeneralVector, sequence): seq := sequence.(instance.GeneralVector) if !(0 <= start && start < len(seq) && 0 <= end && end < len(seq) && start <= end) { - return nil, instance.New(class.ProgramError) + return ProgramError("INDEX-OUT-OF-RANGE") } return seq[start:end], nil case instance.Of(class.List, sequence): seq := sequence.(instance.List).Slice() if !(0 < start && start < len(seq) && 0 < end && end < len(seq) && start <= end) { - return nil, instance.New(class.ProgramError) + return ProgramError("INDEX-OUT-OF-RANGE") } return List(nil, nil, seq[start:end]...) } @@ -215,11 +215,7 @@ func mapInto(local, global *environment.Environment, destination, function ilos. return nil, err } } - args, err := List(nil, nil, arguments...) - if err != nil { - return nil, err - } - ret, err := function.(instance.Function).Apply(local, global, args) + ret, err := function.(instance.Function).Apply(local, global, arguments...) if err != nil { return nil, err } diff --git a/runtime/string_class.go b/runtime/string_class.go index 6b962ec..43836a2 100644 --- a/runtime/string_class.go +++ b/runtime/string_class.go @@ -34,7 +34,7 @@ func CreateString(_, _ *environment.Environment, i ilos.Instance, initialElement }) } if len(initialElement) > 1 { - return nil, instance.New(class.ProgramError) + return ProgramError("ARITY-ERROR") } n := int(i.(instance.Integer)) v := make([]ilos.Instance, n) @@ -130,7 +130,7 @@ func CharIndex(_, _ *environment.Environment, char, str ilos.Instance, startPosi return nil, err } if len(startPosition) > 1 { - return nil, instance.New(class.ProgramError) + return ProgramError("ARITY-ERROR") } n := 0 if len(startPosition) == 1 { @@ -163,7 +163,7 @@ func StringIndex(_, _ *environment.Environment, sub, str ilos.Instance, startPos return nil, err } if len(startPosition) > 1 { - return nil, instance.New(class.ProgramError) + return ProgramError("ARITY-ERROR") } n := 0 if len(startPosition) == 1 { diff --git a/runtime/symbol_class.go b/runtime/symbol_class.go index 863a2e7..3a0ed32 100644 --- a/runtime/symbol_class.go +++ b/runtime/symbol_class.go @@ -35,7 +35,7 @@ func Property(local, global *environment.Environment, symbol, propertyName ilos. return nil, err } if len(obj) > 1 { - return nil, instance.New(class.ProgramError) + return ProgramError("ARITY-ERROR") } ret, ok := global.Property.Get(symbol, propertyName) if ok { diff --git a/runtime/test.go b/runtime/test.go new file mode 100644 index 0000000..33bc7e8 --- /dev/null +++ b/runtime/test.go @@ -0,0 +1,41 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package runtime + +import ( + "reflect" + "regexp" + "runtime" + "testing" + + "github.com/k0kubun/pp" + "github.com/ta2gch/iris/runtime/environment" +) + +type test struct { + exp string + want string + wantErr bool +} + +func execTests(t *testing.T, function interface{}, tests []test) { + name := runtime.FuncForPC(reflect.ValueOf(function).Pointer()).Name() + name = regexp.MustCompile(`.*\.`).ReplaceAllString(name, "") + local := environment.New() + global := environment.TopLevel + for _, tt := range tests { + t.Run(tt.exp, func(t *testing.T) { + got, err := Eval(local, global, readFromString(tt.exp)) + want, _ := Eval(local, global, readFromString(tt.want)) + if !reflect.DeepEqual(got, want) { + pp.Println(got, want) + t.Errorf("%v() got = %v, want %v", name, got, want) + } + if (err != nil) != tt.wantErr { + t.Errorf("%v() err = %v, wantErr %v", name, err, tt.wantErr) + } + }) + } +} diff --git a/runtime/util.go b/runtime/util.go index 38afd09..416790e 100644 --- a/runtime/util.go +++ b/runtime/util.go @@ -5,6 +5,10 @@ package runtime import ( + "fmt" + "reflect" + "regexp" + "runtime" "strings" "github.com/ta2gch/iris/runtime/environment" @@ -44,18 +48,35 @@ func readFromString(s string) ilos.Instance { e, _ := parser.Parse(tokenizer.New(strings.NewReader(s))) return e } - -func defspecial(name string, macro interface{}) { +func evalString(local, global *environment.Environment, s string) ilos.Instance { + e, _ := Eval(local, global, readFromString(s)) + return e +} +func defspecial(function interface{}) { + name := runtime.FuncForPC(reflect.ValueOf(function).Pointer()).Name() + name = regexp.MustCompile(`.*\.`).ReplaceAllString(name, "") + name = regexp.MustCompile(`(.)([A-Z])`).ReplaceAllString(name, "$1-$2") + name = strings.ToUpper(name) symbol := instance.New(class.Symbol, name) - environment.TopLevel.Special.Define(symbol, instance.New(class.Function, symbol, macro)) + environment.TopLevel.Special.Define(symbol, instance.New(class.Function, symbol, function)) } - -func defmacro(name string, macro interface{}) { +func defmacro(function interface{}) { + name := runtime.FuncForPC(reflect.ValueOf(function).Pointer()).Name() + name = regexp.MustCompile(`.*\.`).ReplaceAllString(name, "") + name = regexp.MustCompile(`(.)([A-Z])`).ReplaceAllString(name, "$1-$2") + name = strings.ToUpper(name) symbol := instance.New(class.Symbol, name) - environment.TopLevel.Macro.Define(symbol, instance.New(class.Function, symbol, macro)) + environment.TopLevel.Macro.Define(symbol, instance.New(class.Function, symbol, function)) } - -func defun(name string, function interface{}) { +func defun(function interface{}) { + name := runtime.FuncForPC(reflect.ValueOf(function).Pointer()).Name() + name = regexp.MustCompile(`.*\.`).ReplaceAllString(name, "") + name = regexp.MustCompile(`(.)([A-Z])`).ReplaceAllString(name, "$1-$2") + name = strings.ToUpper(name) + symbol := instance.New(class.Symbol, name) + environment.TopLevel.Function.Define(symbol, instance.New(class.Function, symbol, function)) +} +func defun2(name, function interface{}) { symbol := instance.New(class.Symbol, name) environment.TopLevel.Function.Define(symbol, instance.New(class.Function, symbol, function)) } @@ -74,3 +95,12 @@ func ensure(c ilos.Class, i ...ilos.Instance) ilos.Instance { } return nil } +func ProgramError(cause string) (ilos.Instance, ilos.Instance) { + pc := make([]uintptr, 10) // at least 1 entry needed + runtime.Callers(2, pc) + f := runtime.FuncForPC(pc[0]) + file, line := f.FileLine(pc[0]) + return nil, instance.New(class.ProgramError, map[string]ilos.Instance{ + "CAUSE": instance.New(class.String, cause+fmt.Sprintf("(%s:%d %s)", file, line, f.Name())), + }) +} diff --git a/runtime/variables.go b/runtime/variables.go index d6c9281..09b3b62 100644 --- a/runtime/variables.go +++ b/runtime/variables.go @@ -61,7 +61,7 @@ func Let(local, global *environment.Environment, varForm ilos.Instance, bodyForm } s := cadr.(instance.List).Slice() if len(s) != 2 { - return nil, instance.New(class.ProgramError) + return ProgramError("ARITY-ERROR") } f, err := Eval(local, global, s[1]) if err != nil { @@ -71,7 +71,7 @@ func Let(local, global *environment.Environment, varForm ilos.Instance, bodyForm } for v, f := range vfs { if !local.Variable.Define(v, f) { - return nil, instance.New(class.ProgramError) + return ProgramError("IMMUTABLE-BINDING") } } return Progn(local, global, bodyForm...) @@ -101,14 +101,14 @@ func LetStar(local, global *environment.Environment, varForm ilos.Instance, body } s := cadr.(instance.List).Slice() if len(s) != 2 { - return nil, instance.New(class.ProgramError) + return ProgramError("ARITY-ERROR") } f, err := Eval(local, global, s[1]) if err != nil { return nil, err } if !local.Variable.Define(s[0], f) { - return nil, instance.New(class.ProgramError) + return ProgramError("IMMUTABLE-BINDING") } } return Progn(local, global, bodyForm...) diff --git a/runtime/vectors.go b/runtime/vectors.go index 491ca5b..03c26a1 100644 --- a/runtime/vectors.go +++ b/runtime/vectors.go @@ -43,7 +43,7 @@ func CreateVector(_, _ *environment.Environment, i ilos.Instance, initialElement }) } if len(initialElement) > 1 { - return nil, instance.New(class.ProgramError) + return ProgramError("ARITY-ERROR") } n := int(i.(instance.Integer)) v := make([]ilos.Instance, n) From fe8c948d65eab411d34187be623b32f8e9bf8319 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Tue, 15 Aug 2017 19:24:21 +0900 Subject: [PATCH 178/228] refactor --- reader/parser/parser.go | 38 ++++++++++---------- reader/parser/parser_test.go | 32 ++++++++--------- reader/tokenizer/tokenizer.go | 2 +- runtime/array_operations.go | 8 ++--- runtime/boolean_values.go | 2 +- runtime/dynamic_variables.go | 4 +-- runtime/eval.go | 6 ++-- runtime/float_class.go | 14 ++++---- runtime/functions.go | 4 +-- runtime/ilos/instance/instance.go | 14 -------- runtime/integer_class.go | 14 ++++---- runtime/namedfunc.go | 6 ++-- runtime/non-local_exits.go | 18 +++++----- runtime/number_class.go | 60 +++++++++++++++---------------- runtime/sequence_functions.go | 12 +++---- runtime/string_class.go | 8 ++--- runtime/symbol_class.go | 2 +- runtime/util.go | 21 ++++++----- runtime/variables.go | 2 +- runtime/vectors.go | 4 +-- 20 files changed, 130 insertions(+), 141 deletions(-) diff --git a/reader/parser/parser.go b/reader/parser/parser.go index 37357cc..369349a 100644 --- a/reader/parser/parser.go +++ b/reader/parser/parser.go @@ -16,8 +16,8 @@ import ( "github.com/ta2gch/iris/runtime/ilos/instance" ) -var eop = instance.New(class.Symbol, "End Of Parentheses") -var bod = instance.New(class.Symbol, "Begin Of Dot") +var eop = instance.Symbol("End Of Parentheses") +var bod = instance.Symbol("Begin Of Dot") func ParseAtom(tok string) (ilos.Instance, ilos.Instance) { // @@ -25,49 +25,49 @@ func ParseAtom(tok string) (ilos.Instance, ilos.Instance) { // if m, _ := regexp.MatchString("^[-+]?[[:digit:]]+$", tok); m { n, _ := strconv.ParseInt(tok, 10, 64) - return instance.New(class.Integer, int(n)), nil + return instance.Integer(int(n)), nil } if r := regexp.MustCompile("^#[bB]([-+]?[01]+)$").FindStringSubmatch(tok); len(r) >= 2 { n, _ := strconv.ParseInt(r[1], 2, 64) - return instance.New(class.Integer, int(n)), nil + return instance.Integer(int(n)), nil } if r := regexp.MustCompile("^#[oO]([-+]?[0-7]+)$").FindStringSubmatch(tok); len(r) >= 2 { n, _ := strconv.ParseInt(r[1], 8, 64) - return instance.New(class.Integer, int(n)), nil + return instance.Integer(int(n)), nil } if r := regexp.MustCompile("^#[xX]([-+]?[[:xdigit:]]+)$").FindStringSubmatch(tok); len(r) >= 2 { n, _ := strconv.ParseInt(r[1], 16, 64) - return instance.New(class.Integer, int(n)), nil + return instance.Integer(int(n)), nil } // // float // if m, _ := regexp.MatchString("^[-+]?[[:digit:]]+\\.[[:digit:]]+$", tok); m { n, _ := strconv.ParseFloat(tok, 64) - return instance.New(class.Float, n), nil + return instance.Float(n), nil } if r := regexp.MustCompile("^([-+]?[[:digit:]]+(?:\\.[[:digit:]]+)?)[eE]([-+]?[[:digit:]]+)$").FindStringSubmatch(tok); len(r) >= 3 { n, _ := strconv.ParseFloat(r[1], 64) e, _ := strconv.ParseInt(r[2], 10, 64) - return instance.New(class.Float, n*math.Pow10(int(e))), nil + return instance.Float(n * math.Pow10(int(e))), nil } // // character // if m, _ := regexp.MatchString("^#\\\\newline$", tok); m { - return instance.New(class.Character, '\n'), nil + return instance.Character('\n'), nil } if m, _ := regexp.MatchString("^#\\\\space$", tok); m { - return instance.New(class.Character, ' '), nil + return instance.Character(' '), nil } if r := regexp.MustCompile("^#\\\\([[:graph:]])$").FindStringSubmatch(tok); len(r) >= 2 { - return instance.New(class.Character, rune(r[1][0])), nil + return instance.Character(rune(r[1][0])), nil } // // string // if m, _ := regexp.MatchString("^\".*\"$", tok); m { - return instance.New(class.String, tok), nil + return instance.String(tok), nil } // // symbol @@ -82,10 +82,10 @@ func ParseAtom(tok string) (ilos.Instance, ilos.Instance) { str += `[a-zA-Z<>/*=?_!$%[\]^{}~][-a-zA-Z0-9+<>/*=?_!$%[\]^{}~]*|` str += ")$" if m, _ := regexp.MatchString(str, tok); m { - return instance.New(class.Symbol, strings.ToUpper(tok)), nil + return instance.Symbol(strings.ToUpper(tok)), nil } return nil, instance.New(class.ParseError, map[string]ilos.Instance{ - "STRING": instance.New(class.String, tok), + "STRING": instance.String(tok), "EXPECTED-CLASS": class.Object, }) } @@ -97,17 +97,17 @@ func parseMacro(tok string, t *tokenizer.Tokenizer) (ilos.Instance, ilos.Instanc } n := tok if m, _ := regexp.MatchString("#[[:digit:]]*[aA]", tok); m { - s := instance.New(class.Symbol, "array") + s := instance.Symbol("array") i := strings.IndexRune(strings.ToLower(tok), 'a') if i == 1 { - d := instance.New(class.Integer, 1) + d := instance.Integer(1) return instance.New(class.Cons, s, instance.New(class.Cons, d, instance.New(class.Cons, cdr, instance.New(class.Null)))), nil } v, err := strconv.ParseInt(tok[1:i], 10, 32) if err != nil { - return nil, instance.New(class.ParseError, instance.New(class.String, tok), class.Integer) + return nil, instance.New(class.ParseError, instance.String(tok), class.Integer) } - d := instance.New(class.Integer, int(v)) + d := instance.Integer(int(v)) return instance.New(class.Cons, s, instance.New(class.Cons, d, instance.New(class.Cons, cdr, instance.New(class.Null)))), nil } switch tok { @@ -122,7 +122,7 @@ func parseMacro(tok string, t *tokenizer.Tokenizer) (ilos.Instance, ilos.Instanc case "`": n = "BACKQUOTE" } - m := instance.New(class.Symbol, n) + m := instance.Symbol(n) return instance.New(class.Cons, m, instance.New(class.Cons, cdr, instance.New(class.Null))), nil } func parseCons(t *tokenizer.Tokenizer) (ilos.Instance, ilos.Instance) { diff --git a/reader/parser/parser_test.go b/reader/parser/parser_test.go index a85439a..38529de 100644 --- a/reader/parser/parser_test.go +++ b/reader/parser/parser_test.go @@ -29,31 +29,31 @@ func Test_parseAtom(t *testing.T) { { name: "default", arguments: arguments{"3.14"}, - want: instance.New(class.Float, 3.14), + want: instance.Float(3.14), wantErr: false, }, { name: "signed", arguments: arguments{"-5.0"}, - want: instance.New(class.Float, -5.0), + want: instance.Float(-5.0), wantErr: false, }, { name: "exponential", arguments: arguments{"-5.0E3"}, - want: instance.New(class.Float, -5.0*1000), + want: instance.Float(-5.0 * 1000), wantErr: false, }, { name: "signed exponential", arguments: arguments{"5.0E-3"}, - want: instance.New(class.Float, 5.0*1.0/1000.0), + want: instance.Float(5.0 * 1.0 / 1000.0), wantErr: false, }, { name: "without point", arguments: arguments{"5E-3"}, - want: instance.New(class.Float, 5.0*1.0/1000.0), + want: instance.Float(5.0 * 1.0 / 1000.0), wantErr: false, }, { @@ -74,49 +74,49 @@ func Test_parseAtom(t *testing.T) { { name: "default", arguments: arguments{"5"}, - want: instance.New(class.Integer, 5), + want: instance.Integer(5), wantErr: false, }, { name: "signed", arguments: arguments{"-5"}, - want: instance.New(class.Integer, -5), + want: instance.Integer(-5), wantErr: false, }, { name: "binary", arguments: arguments{"#B00101"}, - want: instance.New(class.Integer, 5), + want: instance.Integer(5), wantErr: false, }, { name: "signed binary", arguments: arguments{"#b+00101"}, - want: instance.New(class.Integer, 5), + want: instance.Integer(5), wantErr: false, }, { name: "octal", arguments: arguments{"#o00101"}, - want: instance.New(class.Integer, 65), + want: instance.Integer(65), wantErr: false, }, { name: "signed octal", arguments: arguments{"#O-00101"}, - want: instance.New(class.Integer, -65), + want: instance.Integer(-65), wantErr: false, }, { name: "hexadecimal", arguments: arguments{"#X00101"}, - want: instance.New(class.Integer, 257), + want: instance.Integer(257), wantErr: false, }, { name: "signed hexadecimal", arguments: arguments{"#x-00101"}, - want: instance.New(class.Integer, -257), + want: instance.Integer(-257), wantErr: false, }, { @@ -131,19 +131,19 @@ func Test_parseAtom(t *testing.T) { { name: "default", arguments: arguments{"#\\a"}, - want: instance.New(class.Character, 'a'), + want: instance.Character('a'), wantErr: false, }, { name: "newline", arguments: arguments{"#\\newline"}, - want: instance.New(class.Character, '\n'), + want: instance.Character('\n'), wantErr: false, }, { name: "space", arguments: arguments{"#\\space"}, - want: instance.New(class.Character, ' '), + want: instance.Character(' '), wantErr: false, }, { diff --git a/reader/tokenizer/tokenizer.go b/reader/tokenizer/tokenizer.go index 530b159..53b30c3 100644 --- a/reader/tokenizer/tokenizer.go +++ b/reader/tokenizer/tokenizer.go @@ -50,7 +50,7 @@ func (t *Tokenizer) Next() (string, ilos.Instance) { if t.sc.Scan() { return t.sc.Text(), nil } - return "", instance.New(class.ParseError, instance.New(class.String, t.sc.Text()), class.Object) + return "", instance.New(class.ParseError, instance.String(t.sc.Text()), class.Object) } func splitter(data []byte, atEOF bool) (advance int, token []byte, err error) { diff --git a/runtime/array_operations.go b/runtime/array_operations.go index dc4df15..cc382ef 100644 --- a/runtime/array_operations.go +++ b/runtime/array_operations.go @@ -116,7 +116,7 @@ func Aref(_, _ *environment.Environment, basicArray ilos.Instance, dimensions .. if len(basicArray.(instance.String)) <= index { return ProgramError("INDEX-OUT-OF-RANGE") } - return instance.New(class.Character, basicArray.(instance.String)[index]), nil + return instance.Character(basicArray.(instance.String)[index]), nil case instance.Of(class.GeneralVector, basicArray): if len(dimensions) != 1 { return ProgramError("ARITY-ERROR") @@ -227,14 +227,14 @@ func ArrayDimensions(_, _ *environment.Environment, basicArray ilos.Instance) (i } switch { case instance.Of(class.String, basicArray): - return List(nil, nil, instance.New(class.Integer, len(basicArray.(instance.String)))) + return List(nil, nil, instance.Integer(len(basicArray.(instance.String)))) case instance.Of(class.GeneralVector, basicArray): - return List(nil, nil, instance.New(class.Integer, len(basicArray.(instance.GeneralVector)))) + return List(nil, nil, instance.Integer(len(basicArray.(instance.GeneralVector)))) default: // General Array* var array *instance.GeneralArrayStar dimensions := []ilos.Instance{} for array.Vector != nil { - dimensions = append(dimensions, instance.New(class.Integer, len(array.Vector))) + dimensions = append(dimensions, instance.Integer(len(array.Vector))) array = array.Vector[0] } return List(nil, nil, dimensions...) diff --git a/runtime/boolean_values.go b/runtime/boolean_values.go index 107b11e..c1852d4 100644 --- a/runtime/boolean_values.go +++ b/runtime/boolean_values.go @@ -31,5 +31,5 @@ import ( // nil is a named constant whose value is the symbol nil itself. var ( Nil = instance.New(class.Null) - T = instance.New(class.Symbol, "T") + T = instance.Symbol("T") ) diff --git a/runtime/dynamic_variables.go b/runtime/dynamic_variables.go index 2da9553..bd97c51 100644 --- a/runtime/dynamic_variables.go +++ b/runtime/dynamic_variables.go @@ -33,7 +33,7 @@ func Dynamic(local, global *environment.Environment, var1 ilos.Instance) (ilos.I } return nil, instance.New(class.UndefinedVariable, map[string]ilos.Instance{ "NAME": var1, - "NAMESPACE": instance.New(class.Symbol, "Variable"), + "NAMESPACE": instance.Symbol("Variable"), }) } @@ -62,7 +62,7 @@ func SetDynamic(local, global *environment.Environment, form, var1 ilos.Instance } return nil, instance.New(class.UndefinedFunction, map[string]ilos.Instance{ "NAME": var1, - "NAMESPACE": instance.New(class.Symbol, "FUNCTION"), + "NAMESPACE": instance.Symbol("FUNCTION"), }) } diff --git a/runtime/eval.go b/runtime/eval.go index 0d488ec..d4a28b0 100644 --- a/runtime/eval.go +++ b/runtime/eval.go @@ -37,7 +37,7 @@ func evalLambda(local, global *environment.Environment, car, cdr ilos.Instance) // eval if lambda form if instance.Of(class.Cons, car) { caar := car.(*instance.Cons).Car // Checked at the top of// This sentence - if caar == instance.New(class.Symbol, "LAMBDA") { + if caar == instance.Symbol("LAMBDA") { fun, err := Eval(local, global, car) if err != nil { return nil, err, true @@ -159,7 +159,7 @@ func evalCons(local, global *environment.Environment, obj ilos.Instance) (ilos.I return nil, instance.New(class.UndefinedFunction, map[string]ilos.Instance{ "NAME": car, - "NAMESPACE": instance.New(class.Symbol, "FUNCTION"), + "NAMESPACE": instance.Symbol("FUNCTION"), }) } @@ -175,7 +175,7 @@ func evalVariable(local, global *environment.Environment, obj ilos.Instance) (il } return nil, instance.New(class.UndefinedVariable, map[string]ilos.Instance{ "NAME": obj, - "NAMESPACE": instance.New(class.Symbol, "VARIABLE"), + "NAMESPACE": instance.Symbol("VARIABLE"), }) } diff --git a/runtime/float_class.go b/runtime/float_class.go index 7d0a81d..f184f2f 100644 --- a/runtime/float_class.go +++ b/runtime/float_class.go @@ -19,8 +19,8 @@ import ( // The value of MostNegativeFloat is the implementation-dependent // floating-point number closest to negative infinity. var ( - MostPositiveFloat = instance.New(class.Float, math.MaxFloat64) - MostNegativeFloat = instance.New(class.Float, -math.MaxFloat64) + MostPositiveFloat = instance.Float(math.MaxFloat64) + MostNegativeFloat = instance.Float(-math.MaxFloat64) ) // Floatp returns t if obj is a float (instance of class float); @@ -40,7 +40,7 @@ func Float(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos. if err != nil { return nil, err } - return instance.New(class.Float, f), nil + return instance.Float(f), nil } // Floor returns the greatest integer less than or equal to x . @@ -51,7 +51,7 @@ func Floor(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos. if err != nil { return nil, err } - return instance.New(class.Integer, int(math.Floor(f))), nil + return instance.Integer(int(math.Floor(f))), nil } // Ceiling Returns the smallest integer that is not smaller than x. @@ -62,7 +62,7 @@ func Ceiling(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilo if err != nil { return nil, err } - return instance.New(class.Integer, int(math.Ceil(f))), nil + return instance.Integer(int(math.Ceil(f))), nil } // Truncate returns the integer between 0 and x (inclusive) that is nearest to x. @@ -73,7 +73,7 @@ func Truncate(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, il if err != nil { return nil, err } - return instance.New(class.Integer, int(math.Trunc(f))), nil + return instance.Integer(int(math.Trunc(f))), nil } // Round returns the integer nearest to x. @@ -84,5 +84,5 @@ func Round(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos. if err != nil { return nil, err } - return instance.New(class.Integer, int(math.Floor(f+.5))), nil + return instance.Integer(int(math.Floor(f + .5))), nil } diff --git a/runtime/functions.go b/runtime/functions.go index 5a31a34..2cb16b5 100644 --- a/runtime/functions.go +++ b/runtime/functions.go @@ -44,7 +44,7 @@ func Function(local, global *environment.Environment, fun ilos.Instance) (ilos.I } return nil, instance.New(class.UndefinedFunction, map[string]ilos.Instance{ "NAME": fun, - "NAMESPACE": instance.New(class.Symbol, "FUNCTION"), + "NAMESPACE": instance.Symbol("FUNCTION"), }) } @@ -76,7 +76,7 @@ func Lambda(local, global *environment.Environment, lambdaList ilos.Instance, fo if err := checkLambdaList(lambdaList); err != nil { return nil, err } - return newNamedFunction(local, global, instance.New(class.Symbol, "ANONYMOUS-FUNCTION"), lambdaList, form...) + return newNamedFunction(local, global, instance.Symbol("ANONYMOUS-FUNCTION"), lambdaList, form...) } // Labels special form allow the definition of new identifiers in the function diff --git a/runtime/ilos/instance/instance.go b/runtime/ilos/instance/instance.go index 5b0f537..792e054 100644 --- a/runtime/ilos/instance/instance.go +++ b/runtime/ilos/instance/instance.go @@ -17,28 +17,14 @@ import ( func New(c ilos.Class, s ...interface{}) ilos.Instance { switch c { - case class.Integer: - return Integer(s[0].(int)) - case class.Float: - return Float(s[0].(float64)) - case class.String: - return String(s[0].(string)) - case class.Symbol: - return Symbol(s[0].(string)) - case class.Character: - return Character(s[0].(rune)) case class.Function: return Function{s[0].(Symbol), s[1]} case class.Cons: return &Cons{s[0].(ilos.Instance), s[1].(ilos.Instance)} case class.Null: return Null{} - case class.GeneralVector: - return GeneralVector(s[0].([]ilos.Instance)) case class.GeneralArrayStar: return &GeneralArrayStar{s[0].([]*GeneralArrayStar), s[1].(ilos.Instance)} - case class.String: - return String(s[0].(string)) default: p := []ilos.Instance{} for _, q := range c.Parents() { diff --git a/runtime/integer_class.go b/runtime/integer_class.go index d96283d..bd1c989 100644 --- a/runtime/integer_class.go +++ b/runtime/integer_class.go @@ -42,11 +42,11 @@ func Div(_, _ *environment.Environment, z1, z2 ilos.Instance) (ilos.Instance, il } if b == 0 { return nil, instance.New(class.DivisionByZero, map[string]ilos.Instance{ - "OPERATION": instance.New(class.Symbol, "DIV"), + "OPERATION": instance.Symbol("DIV"), "OPERANDS": instance.New(class.Cons, z1, instance.New(class.Cons, z2, Nil)), }) } - return instance.New(class.Integer, a/b), nil + return instance.Integer(a / b), nil } // Mod returns the remainder of the integer division of z1 by z2. @@ -66,11 +66,11 @@ func Mod(_, _ *environment.Environment, z1, z2 ilos.Instance) (ilos.Instance, il } if b == 0 { return nil, instance.New(class.DivisionByZero, map[string]ilos.Instance{ - "OPERATION": instance.New(class.Symbol, "MOD"), + "OPERATION": instance.Symbol("MOD"), "OPERANDS": instance.New(class.Cons, z1, instance.New(class.Cons, z2, Nil)), }) } - return instance.New(class.Integer, a%b), nil + return instance.Integer(a % b), nil } // Gcd returns the greatest common divisor of its integer arguments. @@ -95,7 +95,7 @@ func Gcd(_, _ *environment.Environment, z1, z2 ilos.Instance) (ilos.Instance, il if err != nil { return nil, err } - return instance.New(class.Integer, gcd(a, b)), nil + return instance.Integer(gcd(a, b)), nil } // Lcm returns the least common multiple of its integer arguments. @@ -117,7 +117,7 @@ func Lcm(_, _ *environment.Environment, z1, z2 ilos.Instance) (ilos.Instance, il if err != nil { return nil, err } - return instance.New(class.Integer, a*b/gcd(a, b)), nil + return instance.Integer(a * b / gcd(a, b)), nil } // Isqrt Returns the greatest integer less than or equal to @@ -134,5 +134,5 @@ func Isqrt(_, _ *environment.Environment, z ilos.Instance) (ilos.Instance, ilos. "EXPECTED-CLASS": class.Number, }) } - return instance.New(class.Integer, int(math.Sqrt(float64(a)))), nil + return instance.Integer(int(math.Sqrt(float64(a)))), nil } diff --git a/runtime/namedfunc.go b/runtime/namedfunc.go index 23dd9f0..5d5eee0 100644 --- a/runtime/namedfunc.go +++ b/runtime/namedfunc.go @@ -20,7 +20,7 @@ func checkLambdaList(lambdaList ilos.Instance) ilos.Instance { if err := ensure(class.Symbol, cadr); err != nil { return err } - if cadr == instance.New(class.Symbol, ":REST") || cadr == instance.New(class.Symbol, "&REST") { + if cadr == instance.Symbol(":REST") || cadr == instance.Symbol("&REST") { if len(cdr) != i+2 { _, err := ProgramError("ARITY-ERROR") return err @@ -38,7 +38,7 @@ func newNamedFunction(local, global *environment.Environment, functionName, lamb parameters := []ilos.Instance{} variadic := false for _, cadr := range lambdaList.(instance.List).Slice() { - if cadr == instance.New(class.Symbol, ":REST") || cadr == instance.New(class.Symbol, "&REST") { + if cadr == instance.Symbol(":REST") || cadr == instance.Symbol("&REST") { variadic = true } parameters = append(parameters, cadr) @@ -50,7 +50,7 @@ func newNamedFunction(local, global *environment.Environment, functionName, lamb } for idx := range parameters { key := parameters[idx] - if key == instance.New(class.Symbol, ":REST") || key == instance.New(class.Symbol, "&REST") { + if key == instance.Symbol(":REST") || key == instance.Symbol("&REST") { key := parameters[idx+1] value, err := List(nil, nil, arguments[idx:]...) if err != nil { diff --git a/runtime/non-local_exits.go b/runtime/non-local_exits.go index 5ab64f5..dc90124 100644 --- a/runtime/non-local_exits.go +++ b/runtime/non-local_exits.go @@ -59,9 +59,9 @@ func Block(local, global *environment.Environment, tag ilos.Instance, body ...il sucess, fail = Eval(local, global, cadr) if fail != nil { if instance.Of(class.BlockTag, fail) { - tag1, _ := fail.GetSlotValue(instance.New(class.Symbol, "TAG"), class.Escape) // Checked at the head of// This condition + tag1, _ := fail.GetSlotValue(instance.Symbol("TAG"), class.Escape) // Checked at the head of// This condition if tag == tag1 { - obj, _ := fail.GetSlotValue(instance.New(class.Symbol, "OBJECT"), class.BlockTag) // Checked at the head of// This condition + obj, _ := fail.GetSlotValue(instance.Symbol("OBJECT"), class.BlockTag) // Checked at the head of// This condition return obj, nil } } @@ -89,7 +89,7 @@ func ReturnFrom(local, global *environment.Environment, tag, object ilos.Instanc } if _, ok := local.BlockTag.Get(tag); !ok { return nil, instance.New(class.SimpleError, map[string]ilos.Instance{ - "FORMAT-STRING": instance.New(class.String, "%v is not defined as the tag"), + "FORMAT-STRING": instance.String("%v is not defined as the tag"), "FORMAT-ARGUMENTS": tag, }) } @@ -117,9 +117,9 @@ func Catch(local, global *environment.Environment, tag ilos.Instance, body ...il sucess, fail = Eval(local, global, cadr) if fail != nil { if instance.Of(class.CatchTag, fail) { - tag1, _ := fail.GetSlotValue(instance.New(class.Symbol, "TAG"), class.Escape) // Checked at the head of// This condition + tag1, _ := fail.GetSlotValue(instance.Symbol("TAG"), class.Escape) // Checked at the head of// This condition if tag == tag1 { - obj, _ := fail.GetSlotValue(instance.New(class.Symbol, "OBJECT"), class.CatchTag) // Checked at the head of// This condition + obj, _ := fail.GetSlotValue(instance.Symbol("OBJECT"), class.CatchTag) // Checked at the head of// This condition return obj, nil } } @@ -147,7 +147,7 @@ func Throw(local, global *environment.Environment, tag, object ilos.Instance) (i } if _, ok := local.CatchTag.Get(tag); !ok { return nil, instance.New(class.SimpleError, map[string]ilos.Instance{ - "FORMAT-STRING": instance.New(class.String, "%v is not defined as the tag"), + "FORMAT-STRING": instance.String("%v is not defined as the tag"), "FORMAT-ARGUMENTS": tag, }) } @@ -159,7 +159,7 @@ func Throw(local, global *environment.Environment, tag, object ilos.Instance) (i func Tagbody(local, global *environment.Environment, body ...ilos.Instance) (ilos.Instance, ilos.Instance) { for idx, cadr := range body { - cddr := instance.New(class.GeneralVector, body[idx+1:]) + cddr := instance.GeneralVector(body[idx+1:]) if !instance.Of(class.Cons, cadr) { if !local.TagbodyTag.Define(cadr, cddr) { return ProgramError("IMMUTABLE-BINDING") @@ -172,7 +172,7 @@ func Tagbody(local, global *environment.Environment, body ...ilos.Instance) (ilo if fail != nil { TAG: if instance.Of(class.TagbodyTag, fail) { - tag, _ := fail.GetSlotValue(instance.New(class.Symbol, "TAG"), class.Escape) // Checked at the top of// This loop + tag, _ := fail.GetSlotValue(instance.Symbol("TAG"), class.Escape) // Checked at the top of// This loop found := false for _, tag1 := range body { if tag == tag1 { @@ -204,7 +204,7 @@ func Tagbody(local, global *environment.Environment, body ...ilos.Instance) (ilo func Go(local, global *environment.Environment, tag ilos.Instance) (ilos.Instance, ilos.Instance) { if _, ok := local.TagbodyTag.Get(tag); !ok { return nil, instance.New(class.SimpleError, map[string]ilos.Instance{ - "FORMAT-STRING": instance.New(class.String, "%v is not defined as the tag"), + "FORMAT-STRING": instance.String("%v is not defined as the tag"), "FORMAT-ARGUMENTS": tag, }) } diff --git a/runtime/number_class.go b/runtime/number_class.go index f08a72a..0d22f14 100644 --- a/runtime/number_class.go +++ b/runtime/number_class.go @@ -152,9 +152,9 @@ func Add(_, _ *environment.Environment, x ...ilos.Instance) (ilos.Instance, ilos sum += f } if flt { - return instance.New(class.Float, sum), nil + return instance.Float(sum), nil } - return instance.New(class.Integer, int(sum)), nil + return instance.Integer(int(sum)), nil } // Multiply returns the product, respectively, of their arguments. If all arguments are integers, @@ -172,9 +172,9 @@ func Multiply(_, _ *environment.Environment, x ...ilos.Instance) (ilos.Instance, flt = flt || b } if flt { - return instance.New(class.Float, pdt), nil + return instance.Float(pdt), nil } - return instance.New(class.Integer, int(pdt)), nil + return instance.Integer(int(pdt)), nil } // Substruct returns its additive inverse. An error shall be signaled @@ -186,7 +186,7 @@ func Multiply(_, _ *environment.Environment, x ...ilos.Instance) (ilos.Instance, // x1 −x2 − … −xn. An error shall be signaled if any x is not a number (error-id. domain-error). func Substruct(_, _ *environment.Environment, x ilos.Instance, xs ...ilos.Instance) (ilos.Instance, ilos.Instance) { if len(xs) == 0 { - ret, err := Substruct(nil, nil, instance.New(class.Integer, 0), x) + ret, err := Substruct(nil, nil, instance.Integer(0), x) return ret, err } sub, flt, err := convFloat64(x) @@ -202,9 +202,9 @@ func Substruct(_, _ *environment.Environment, x ilos.Instance, xs ...ilos.Instan flt = flt || b } if flt { - return instance.New(class.Float, sub), nil + return instance.Float(sub), nil } - return instance.New(class.Integer, int(sub)), nil + return instance.Integer(int(sub)), nil } // Quotient returns the quotient of those numbers. The result is an integer if dividend and divisor are integers and divisor evenly divides dividend , otherwise it will be a float. @@ -228,7 +228,7 @@ func Quotient(_, _ *environment.Environment, dividend, divisor1 ilos.Instance, d arguments = instance.New(class.Cons, divisor[i], arguments) } return nil, instance.New(class.DivisionByZero, map[string]ilos.Instance{ - "OPERATION": instance.New(class.Symbol, "QUOTIENT"), + "OPERATION": instance.Symbol("QUOTIENT"), "OPERANDS": arguments, }) } @@ -238,15 +238,15 @@ func Quotient(_, _ *environment.Environment, dividend, divisor1 ilos.Instance, d quotient /= f } if flt { - return instance.New(class.Float, quotient), nil + return instance.Float(quotient), nil } - return instance.New(class.Integer, int(quotient)), nil + return instance.Integer(int(quotient)), nil } // Reciprocal returns the reciprocal of its argument x ; that is, 1/x . // An error shall be signaled if x is zero (error-id. division-by-zero). func Reciprocal(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { - return Quotient(nil, nil, instance.New(class.Integer, 1), x) + return Quotient(nil, nil, instance.Integer(1), x) } // Max returns the greatest (closest to positive infinity) of its arguments. The comparison is done by >. @@ -284,7 +284,7 @@ func Min(_, _ *environment.Environment, x ilos.Instance, xs ...ilos.Instance) (i // Abs returns the absolute value of its argument. // An error shall be signaled if x is not a number (error-id. domain-error). func Abs(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { - ret, err := NumberLessThan(nil, nil, x, instance.New(class.Integer, 0)) + ret, err := NumberLessThan(nil, nil, x, instance.Integer(0)) if err != nil { return nil, err } @@ -301,7 +301,7 @@ func Exp(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos.In if err != nil { return nil, err } - return instance.New(class.Float, math.Exp(f)), nil + return instance.Float(math.Exp(f)), nil } // Log returns the natural logarithm of x. @@ -317,7 +317,7 @@ func Log(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos.In "EXPECTED-CLASS": class.Number, }) } - return instance.New(class.Float, math.Log(f)), nil + return instance.Float(math.Log(f)), nil } // Expt returns x1 raised to the power x2. The result will be @@ -335,15 +335,15 @@ func Expt(_, _ *environment.Environment, x1, x2 ilos.Instance) (ilos.Instance, i return nil, err } if !af && !bf && b >= 0 { - return instance.New(class.Integer, int(math.Pow(a, b))), nil + return instance.Integer(int(math.Pow(a, b))), nil } if (a == 0 && b < 0) || (a == 0 && bf && b == 0) || (a < 0 && bf) { return nil, instance.New(class.ArithmeticError, map[string]ilos.Instance{ - "OPERATION": instance.New(class.Symbol, "EXPT"), + "OPERATION": instance.Symbol("EXPT"), "OPERANDS": instance.New(class.Cons, x1, instance.New(class.Cons, x2, Nil)), }) } - return instance.New(class.Float, math.Pow(a, b)), nil + return instance.Float(math.Pow(a, b)), nil } // Sqrt returns the non-negative square root of x. An error shall be signaled @@ -360,13 +360,13 @@ func Sqrt(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos.I }) } if math.Ceil(math.Sqrt(a)) == math.Sqrt(a) { - return instance.New(class.Integer, int(math.Sqrt(a))), nil + return instance.Integer(int(math.Sqrt(a))), nil } - return instance.New(class.Float, math.Sqrt(a)), nil + return instance.Float(math.Sqrt(a)), nil } // Pi is an approximation of π. -var Pi = instance.New(class.Float, 3.141592653589793) +var Pi = instance.Float(3.141592653589793) // Sin returns the sine of x . x must be given in radians. // An error shall be signaled if x is not a number (error-id. domain-error). @@ -375,7 +375,7 @@ func Sin(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos.In if err != nil { return nil, err } - return instance.New(class.Float, math.Sin(a)), nil + return instance.Float(math.Sin(a)), nil } // Cos returns the cosine of x . x must be given in radians. @@ -385,7 +385,7 @@ func Cos(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos.In if err != nil { return nil, err } - return instance.New(class.Float, math.Cos(a)), nil + return instance.Float(math.Cos(a)), nil } // Tan returns the tangent of x . x must be given in radians. @@ -395,7 +395,7 @@ func Tan(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos.In if err != nil { return nil, err } - return instance.New(class.Float, math.Tan(a)), nil + return instance.Float(math.Tan(a)), nil } // Atan returns the arc tangent of x. @@ -406,7 +406,7 @@ func Atan(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos.I if err != nil { return nil, err } - return instance.New(class.Float, math.Atan(a)), nil + return instance.Float(math.Atan(a)), nil } // Atan2 returns the phase of its representation in polar coordinates. @@ -429,11 +429,11 @@ func Atan2(_, _ *environment.Environment, x1, x2 ilos.Instance) (ilos.Instance, } if a == 0 && b == 0 { return nil, instance.New(class.ArithmeticError, map[string]ilos.Instance{ - "OPERATION": instance.New(class.Symbol, "ATAN2"), + "OPERATION": instance.Symbol("ATAN2"), "OPERANDS": instance.New(class.Cons, x1, instance.New(class.Cons, x2, Nil)), }) } - return instance.New(class.Float, math.Atan2(a, b)), nil + return instance.Float(math.Atan2(a, b)), nil } // Sinh returns the hyperbolic sine of x . x must be given in radians. @@ -443,7 +443,7 @@ func Sinh(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos.I if err != nil { return nil, err } - return instance.New(class.Float, math.Sinh(a)), nil + return instance.Float(math.Sinh(a)), nil } // Cosh returns the hyperbolic cosine of x . x must be given in radians. @@ -453,7 +453,7 @@ func Cosh(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos.I if err != nil { return nil, err } - return instance.New(class.Float, math.Cosh(a)), nil + return instance.Float(math.Cosh(a)), nil } // Tanh returns the hyperbolic tangent of x . x must be given in radians. @@ -463,7 +463,7 @@ func Tanh(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos.I if err != nil { return nil, err } - return instance.New(class.Float, math.Tanh(a)), nil + return instance.Float(math.Tanh(a)), nil } // Atanh returns the hyperbolic arc tangent of x. @@ -479,5 +479,5 @@ func Atanh(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos. "EXPECTED-CLASS": class.Number, }) } - return instance.New(class.Float, math.Atanh(a)), nil + return instance.Float(math.Atanh(a)), nil } diff --git a/runtime/sequence_functions.go b/runtime/sequence_functions.go index 293d690..c3f55f9 100644 --- a/runtime/sequence_functions.go +++ b/runtime/sequence_functions.go @@ -27,11 +27,11 @@ import ( func Length(_, _ *environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { switch { case instance.Of(class.String, obj): - return instance.New(class.Integer, len(obj.(instance.String))), nil + return instance.Integer(len(obj.(instance.String))), nil case instance.Of(class.GeneralVector, obj): - return instance.New(class.Integer, len(obj.(instance.GeneralVector))), nil + return instance.Integer(len(obj.(instance.GeneralVector))), nil case instance.Of(class.List, obj): - return instance.New(class.Integer, len(obj.(instance.List).Slice())), nil + return instance.Integer(len(obj.(instance.List).Slice())), nil } // TODO: class.Seq return nil, instance.New(class.DomainError, map[string]ilos.Instance{ @@ -58,7 +58,7 @@ func Elt(_, _ *environment.Environment, sequence, z ilos.Instance) (ilos.Instanc if idx > 0 && len(seq) <= idx { return ProgramError("INDEX-OUT-OF-RANGE") } - return instance.New(class.Character, seq[idx]), nil + return instance.Character(seq[idx]), nil case instance.Of(class.GeneralVector, sequence): seq := sequence.(instance.GeneralVector) idx := int(z.(instance.Integer)) @@ -210,7 +210,7 @@ func mapInto(local, global *environment.Environment, destination, function ilos. arguments := make([]ilos.Instance, int(max)) for _, seq := range sequences { var err ilos.Instance - arguments[i], err = Elt(nil, nil, seq, instance.New(class.Integer, i)) + arguments[i], err = Elt(nil, nil, seq, instance.Integer(i)) if err != nil { return nil, err } @@ -219,7 +219,7 @@ func mapInto(local, global *environment.Environment, destination, function ilos. if err != nil { return nil, err } - _, err = SetElt(nil, nil, ret, destination, instance.New(class.Integer, i)) + _, err = SetElt(nil, nil, ret, destination, instance.Integer(i)) if err != nil { return nil, err } diff --git a/runtime/string_class.go b/runtime/string_class.go index 43836a2..85b1dbd 100644 --- a/runtime/string_class.go +++ b/runtime/string_class.go @@ -48,7 +48,7 @@ func CreateString(_, _ *environment.Environment, i ilos.Instance, initialElement v[i] = initialElement[0] } } - return instance.New(class.GeneralVector, v), nil + return instance.GeneralVector(v), nil } // StringEqual tests whether string1 is the same string as string2. @@ -145,7 +145,7 @@ func CharIndex(_, _ *environment.Environment, char, str ilos.Instance, startPosi if i < 0 { return Nil, nil } - return instance.New(class.Integer, i), nil + return instance.Integer(i), nil } // StringIndex returns the position of the given substring within string. The search starts @@ -178,7 +178,7 @@ func StringIndex(_, _ *environment.Environment, sub, str ilos.Instance, startPos if i < 0 { return Nil, nil } - return instance.New(class.Integer, i), nil + return instance.Integer(i), nil } // StringAppend returns a single string containing a sequence of characters that results @@ -197,5 +197,5 @@ func StringAppend(_, _ *environment.Environment, str ...ilos.Instance) (ilos.Ins } ret += string(s.(instance.String)) } - return instance.New(class.String, ret), nil + return instance.String(ret), nil } diff --git a/runtime/symbol_class.go b/runtime/symbol_class.go index 3a0ed32..f6809b5 100644 --- a/runtime/symbol_class.go +++ b/runtime/symbol_class.go @@ -79,5 +79,5 @@ func RemoveProperty(local, global *environment.Environment, symbol, propertyName // It is impossible for an identifier to name an unnamed symbol. func Gensym(local, global *environment.Environment) (ilos.Instance, ilos.Instance) { global.GensymID++ - return instance.New(class.Symbol, fmt.Sprintf("IRIS:G#%v", global.GensymID)), nil + return instance.Symbol(fmt.Sprintf("IRIS:G#%v", global.GensymID)), nil } diff --git a/runtime/util.go b/runtime/util.go index 416790e..fcde475 100644 --- a/runtime/util.go +++ b/runtime/util.go @@ -57,7 +57,7 @@ func defspecial(function interface{}) { name = regexp.MustCompile(`.*\.`).ReplaceAllString(name, "") name = regexp.MustCompile(`(.)([A-Z])`).ReplaceAllString(name, "$1-$2") name = strings.ToUpper(name) - symbol := instance.New(class.Symbol, name) + symbol := instance.Symbol(name) environment.TopLevel.Special.Define(symbol, instance.New(class.Function, symbol, function)) } func defmacro(function interface{}) { @@ -65,7 +65,7 @@ func defmacro(function interface{}) { name = regexp.MustCompile(`.*\.`).ReplaceAllString(name, "") name = regexp.MustCompile(`(.)([A-Z])`).ReplaceAllString(name, "$1-$2") name = strings.ToUpper(name) - symbol := instance.New(class.Symbol, name) + symbol := instance.Symbol(name) environment.TopLevel.Macro.Define(symbol, instance.New(class.Function, symbol, function)) } func defun(function interface{}) { @@ -73,15 +73,15 @@ func defun(function interface{}) { name = regexp.MustCompile(`.*\.`).ReplaceAllString(name, "") name = regexp.MustCompile(`(.)([A-Z])`).ReplaceAllString(name, "$1-$2") name = strings.ToUpper(name) - symbol := instance.New(class.Symbol, name) + symbol := instance.Symbol(name) environment.TopLevel.Function.Define(symbol, instance.New(class.Function, symbol, function)) } -func defun2(name, function interface{}) { - symbol := instance.New(class.Symbol, name) +func defun2(name string, function interface{}) { + symbol := instance.Symbol(name) environment.TopLevel.Function.Define(symbol, instance.New(class.Function, symbol, function)) } func defglobal(name string, value ilos.Instance) { - symbol := instance.New(class.Symbol, name) + symbol := instance.Symbol(name) environment.TopLevel.Variable.Define(symbol, value) } func ensure(c ilos.Class, i ...ilos.Instance) ilos.Instance { @@ -95,12 +95,15 @@ func ensure(c ilos.Class, i ...ilos.Instance) ilos.Instance { } return nil } + func ProgramError(cause string) (ilos.Instance, ilos.Instance) { pc := make([]uintptr, 10) // at least 1 entry needed runtime.Callers(2, pc) - f := runtime.FuncForPC(pc[0]) - file, line := f.FileLine(pc[0]) + name := runtime.FuncForPC(pc[0]).Name() + name = regexp.MustCompile(`.*\.`).ReplaceAllString(name, "") + name = regexp.MustCompile(`(.)([A-Z])`).ReplaceAllString(name, "$1-$2") + name = strings.ToUpper(name) return nil, instance.New(class.ProgramError, map[string]ilos.Instance{ - "CAUSE": instance.New(class.String, cause+fmt.Sprintf("(%s:%d %s)", file, line, f.Name())), + "CAUSE": instance.String(cause + fmt.Sprintf(" in %v", name)), }) } diff --git a/runtime/variables.go b/runtime/variables.go index 09b3b62..8cc8125 100644 --- a/runtime/variables.go +++ b/runtime/variables.go @@ -32,7 +32,7 @@ func Setq(local, global *environment.Environment, var1, form ilos.Instance) (ilo } return nil, instance.New(class.UndefinedVariable, map[string]ilos.Instance{ "NAME": var1, - "NAMESPACE": instance.New(class.Symbol, "VARIABLE"), + "NAMESPACE": instance.Symbol("VARIABLE"), }) } diff --git a/runtime/vectors.go b/runtime/vectors.go index 03c26a1..99934d4 100644 --- a/runtime/vectors.go +++ b/runtime/vectors.go @@ -54,7 +54,7 @@ func CreateVector(_, _ *environment.Environment, i ilos.Instance, initialElement v[i] = initialElement[0] } } - return instance.New(class.GeneralVector, v), nil + return instance.GeneralVector(v), nil } // Vector returns a new general-vector whose elements are its obj arguments. @@ -63,5 +63,5 @@ func CreateVector(_, _ *environment.Environment, i ilos.Instance, initialElement // if the requested vector cannot be allocated (error-id. cannot-create-vector). // Each obj may be any ISLISP object. func Vector(_, _ *environment.Environment, obj ...ilos.Instance) (ilos.Instance, ilos.Instance) { - return instance.New(class.GeneralVector, obj), nil + return instance.GeneralVector(obj), nil } From b400f2e280babd3d4a8e078622955e23305bbf03 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Tue, 15 Aug 2017 20:40:04 +0900 Subject: [PATCH 179/228] Added constructors --- reader/parser/parser.go | 50 ++++++++++----------- reader/parser/parser_test.go | 32 +++++++------- reader/tokenizer/tokenizer.go | 2 +- runtime/array_operations.go | 46 +++++++++---------- runtime/boolean_values.go | 5 +-- runtime/conditional_expressions.go | 8 ++-- runtime/cons.go | 2 +- runtime/defining_operators.go | 5 ++- runtime/dynamic_variables.go | 8 ++-- runtime/eval.go | 8 ++-- runtime/float_class.go | 14 +++--- runtime/functions.go | 12 ++--- runtime/ilos/class/class.go | 2 +- runtime/ilos/instance/basic-array.go | 12 +++++ runtime/ilos/instance/character.go | 4 ++ runtime/ilos/instance/error.go | 57 ++++++++++++++++++++++++ runtime/ilos/instance/function.go | 6 ++- runtime/ilos/instance/instance.go | 27 ++++-------- runtime/ilos/instance/list.go | 8 ++++ runtime/ilos/instance/number.go | 7 +++ runtime/ilos/instance/symbol.go | 4 ++ runtime/integer_class.go | 18 ++++---- runtime/iteration.go | 8 ++-- runtime/list_operations.go | 10 ++--- runtime/namedfunc.go | 20 +++++---- runtime/non-local_exits.go | 22 +++++----- runtime/number_class.go | 66 ++++++++++++++-------------- runtime/sequence_functions.go | 30 ++++++------- runtime/string_class.go | 12 ++--- runtime/symbol_class.go | 4 +- runtime/util.go | 20 ++++----- runtime/variables.go | 10 ++--- runtime/vectors.go | 2 +- 33 files changed, 314 insertions(+), 227 deletions(-) create mode 100644 runtime/ilos/instance/error.go diff --git a/reader/parser/parser.go b/reader/parser/parser.go index 369349a..507bfbf 100644 --- a/reader/parser/parser.go +++ b/reader/parser/parser.go @@ -16,8 +16,8 @@ import ( "github.com/ta2gch/iris/runtime/ilos/instance" ) -var eop = instance.Symbol("End Of Parentheses") -var bod = instance.Symbol("Begin Of Dot") +var eop = instance.NewSymbol("End Of Parentheses") +var bod = instance.NewSymbol("Begin Of Dot") func ParseAtom(tok string) (ilos.Instance, ilos.Instance) { // @@ -25,55 +25,55 @@ func ParseAtom(tok string) (ilos.Instance, ilos.Instance) { // if m, _ := regexp.MatchString("^[-+]?[[:digit:]]+$", tok); m { n, _ := strconv.ParseInt(tok, 10, 64) - return instance.Integer(int(n)), nil + return instance.NewInteger(int(n)), nil } if r := regexp.MustCompile("^#[bB]([-+]?[01]+)$").FindStringSubmatch(tok); len(r) >= 2 { n, _ := strconv.ParseInt(r[1], 2, 64) - return instance.Integer(int(n)), nil + return instance.NewInteger(int(n)), nil } if r := regexp.MustCompile("^#[oO]([-+]?[0-7]+)$").FindStringSubmatch(tok); len(r) >= 2 { n, _ := strconv.ParseInt(r[1], 8, 64) - return instance.Integer(int(n)), nil + return instance.NewInteger(int(n)), nil } if r := regexp.MustCompile("^#[xX]([-+]?[[:xdigit:]]+)$").FindStringSubmatch(tok); len(r) >= 2 { n, _ := strconv.ParseInt(r[1], 16, 64) - return instance.Integer(int(n)), nil + return instance.NewInteger(int(n)), nil } // // float // if m, _ := regexp.MatchString("^[-+]?[[:digit:]]+\\.[[:digit:]]+$", tok); m { n, _ := strconv.ParseFloat(tok, 64) - return instance.Float(n), nil + return instance.NewFloat(n), nil } if r := regexp.MustCompile("^([-+]?[[:digit:]]+(?:\\.[[:digit:]]+)?)[eE]([-+]?[[:digit:]]+)$").FindStringSubmatch(tok); len(r) >= 3 { n, _ := strconv.ParseFloat(r[1], 64) e, _ := strconv.ParseInt(r[2], 10, 64) - return instance.Float(n * math.Pow10(int(e))), nil + return instance.NewFloat(n * math.Pow10(int(e))), nil } // // character // if m, _ := regexp.MatchString("^#\\\\newline$", tok); m { - return instance.Character('\n'), nil + return instance.NewCharacter('\n'), nil } if m, _ := regexp.MatchString("^#\\\\space$", tok); m { - return instance.Character(' '), nil + return instance.NewCharacter(' '), nil } if r := regexp.MustCompile("^#\\\\([[:graph:]])$").FindStringSubmatch(tok); len(r) >= 2 { - return instance.Character(rune(r[1][0])), nil + return instance.NewCharacter(rune(r[1][0])), nil } // // string // if m, _ := regexp.MatchString("^\".*\"$", tok); m { - return instance.String(tok), nil + return instance.NewString(tok), nil } // // symbol // if "nil" == tok { - return instance.New(class.Null), nil + return instance.NewNull(), nil } str := `^(` str += `[:&][a-zA-Z]+|` @@ -82,10 +82,10 @@ func ParseAtom(tok string) (ilos.Instance, ilos.Instance) { str += `[a-zA-Z<>/*=?_!$%[\]^{}~][-a-zA-Z0-9+<>/*=?_!$%[\]^{}~]*|` str += ")$" if m, _ := regexp.MatchString(str, tok); m { - return instance.Symbol(strings.ToUpper(tok)), nil + return instance.NewSymbol(strings.ToUpper(tok)), nil } return nil, instance.New(class.ParseError, map[string]ilos.Instance{ - "STRING": instance.String(tok), + "STRING": instance.NewString(tok), "EXPECTED-CLASS": class.Object, }) } @@ -97,18 +97,18 @@ func parseMacro(tok string, t *tokenizer.Tokenizer) (ilos.Instance, ilos.Instanc } n := tok if m, _ := regexp.MatchString("#[[:digit:]]*[aA]", tok); m { - s := instance.Symbol("array") + s := instance.NewSymbol("array") i := strings.IndexRune(strings.ToLower(tok), 'a') if i == 1 { - d := instance.Integer(1) - return instance.New(class.Cons, s, instance.New(class.Cons, d, instance.New(class.Cons, cdr, instance.New(class.Null)))), nil + d := instance.NewInteger(1) + return instance.NewCons(s, instance.NewCons(d, instance.NewCons(cdr, instance.NewNull()))), nil } v, err := strconv.ParseInt(tok[1:i], 10, 32) if err != nil { - return nil, instance.New(class.ParseError, instance.String(tok), class.Integer) + return nil, instance.New(class.ParseError, instance.NewString(tok), class.Integer) } - d := instance.Integer(int(v)) - return instance.New(class.Cons, s, instance.New(class.Cons, d, instance.New(class.Cons, cdr, instance.New(class.Null)))), nil + d := instance.NewInteger(int(v)) + return instance.NewCons(s, instance.NewCons(d, instance.NewCons(cdr, instance.NewNull()))), nil } switch tok { case "#'": @@ -122,13 +122,13 @@ func parseMacro(tok string, t *tokenizer.Tokenizer) (ilos.Instance, ilos.Instanc case "`": n = "BACKQUOTE" } - m := instance.Symbol(n) - return instance.New(class.Cons, m, instance.New(class.Cons, cdr, instance.New(class.Null))), nil + m := instance.NewSymbol(n) + return instance.NewCons(m, instance.NewCons(cdr, instance.NewNull())), nil } func parseCons(t *tokenizer.Tokenizer) (ilos.Instance, ilos.Instance) { car, err := Parse(t) if err == eop { - return instance.New(class.Null), nil + return instance.NewNull(), nil } if err == bod { cdr, err := Parse(t) @@ -147,7 +147,7 @@ func parseCons(t *tokenizer.Tokenizer) (ilos.Instance, ilos.Instance) { if err != nil { return nil, err } - return instance.New(class.Cons, car, cdr), nil + return instance.NewCons(car, cdr), nil } // Parse builds a internal expression from tokens diff --git a/reader/parser/parser_test.go b/reader/parser/parser_test.go index 38529de..49b15a9 100644 --- a/reader/parser/parser_test.go +++ b/reader/parser/parser_test.go @@ -29,31 +29,31 @@ func Test_parseAtom(t *testing.T) { { name: "default", arguments: arguments{"3.14"}, - want: instance.Float(3.14), + want: instance.NewFloat(3.14), wantErr: false, }, { name: "signed", arguments: arguments{"-5.0"}, - want: instance.Float(-5.0), + want: instance.NewFloat(-5.0), wantErr: false, }, { name: "exponential", arguments: arguments{"-5.0E3"}, - want: instance.Float(-5.0 * 1000), + want: instance.NewFloat(-5.0 * 1000), wantErr: false, }, { name: "signed exponential", arguments: arguments{"5.0E-3"}, - want: instance.Float(5.0 * 1.0 / 1000.0), + want: instance.NewFloat(5.0 * 1.0 / 1000.0), wantErr: false, }, { name: "without point", arguments: arguments{"5E-3"}, - want: instance.Float(5.0 * 1.0 / 1000.0), + want: instance.NewFloat(5.0 * 1.0 / 1000.0), wantErr: false, }, { @@ -74,49 +74,49 @@ func Test_parseAtom(t *testing.T) { { name: "default", arguments: arguments{"5"}, - want: instance.Integer(5), + want: instance.NewInteger(5), wantErr: false, }, { name: "signed", arguments: arguments{"-5"}, - want: instance.Integer(-5), + want: instance.NewInteger(-5), wantErr: false, }, { name: "binary", arguments: arguments{"#B00101"}, - want: instance.Integer(5), + want: instance.NewInteger(5), wantErr: false, }, { name: "signed binary", arguments: arguments{"#b+00101"}, - want: instance.Integer(5), + want: instance.NewInteger(5), wantErr: false, }, { name: "octal", arguments: arguments{"#o00101"}, - want: instance.Integer(65), + want: instance.NewInteger(65), wantErr: false, }, { name: "signed octal", arguments: arguments{"#O-00101"}, - want: instance.Integer(-65), + want: instance.NewInteger(-65), wantErr: false, }, { name: "hexadecimal", arguments: arguments{"#X00101"}, - want: instance.Integer(257), + want: instance.NewInteger(257), wantErr: false, }, { name: "signed hexadecimal", arguments: arguments{"#x-00101"}, - want: instance.Integer(-257), + want: instance.NewInteger(-257), wantErr: false, }, { @@ -131,19 +131,19 @@ func Test_parseAtom(t *testing.T) { { name: "default", arguments: arguments{"#\\a"}, - want: instance.Character('a'), + want: instance.NewCharacter('a'), wantErr: false, }, { name: "newline", arguments: arguments{"#\\newline"}, - want: instance.Character('\n'), + want: instance.NewCharacter('\n'), wantErr: false, }, { name: "space", arguments: arguments{"#\\space"}, - want: instance.Character(' '), + want: instance.NewCharacter(' '), wantErr: false, }, { diff --git a/reader/tokenizer/tokenizer.go b/reader/tokenizer/tokenizer.go index 53b30c3..7336e2c 100644 --- a/reader/tokenizer/tokenizer.go +++ b/reader/tokenizer/tokenizer.go @@ -50,7 +50,7 @@ func (t *Tokenizer) Next() (string, ilos.Instance) { if t.sc.Scan() { return t.sc.Text(), nil } - return "", instance.New(class.ParseError, instance.String(t.sc.Text()), class.Object) + return "", instance.New(class.ParseError, instance.NewString(t.sc.Text()), class.Object) } func splitter(data []byte, atEOF bool) (advance int, token []byte, err error) { diff --git a/runtime/array_operations.go b/runtime/array_operations.go index cc382ef..12e43a2 100644 --- a/runtime/array_operations.go +++ b/runtime/array_operations.go @@ -62,33 +62,33 @@ func CreateArray(_, _ *environment.Environment, dimensions ilos.Instance, initia dim := dimensions.(instance.List).Slice() elt := Nil if len(initialElement) > 1 { - return ProgramError("ARITY-ERROR") + return nil, instance.NewArityError() } if len(initialElement) == 1 { elt = initialElement[0] } switch len(dim) { case 0: - return instance.New(class.GeneralArrayStar, nil, elt), nil + return instance.NewGeneralArrayStar(nil, elt), nil case 1: array := make([]*instance.GeneralArrayStar, int(dim[0].(instance.Integer))) for i := range array { - array[i] = instance.New(class.GeneralArrayStar, nil, elt).(*instance.GeneralArrayStar) + array[i] = instance.NewGeneralArrayStar(nil, elt).(*instance.GeneralArrayStar) } - return instance.New(class.GeneralArrayStar, array, nil), nil + return instance.NewGeneralArrayStar(array, nil), nil default: array := make([]*instance.GeneralArrayStar, int(dim[len(dim)-1].(instance.Integer))) for i := range array { - array[i] = instance.New(class.GeneralArrayStar, nil, elt).(*instance.GeneralArrayStar) + array[i] = instance.NewGeneralArrayStar(nil, elt).(*instance.GeneralArrayStar) } for i := len(dim) - 2; i >= 0; i-- { elt := array array := make([]*instance.GeneralArrayStar, int(dim[i].(instance.Integer))) for i := range array { - array[i] = instance.New(class.GeneralArrayStar, elt, nil).(*instance.GeneralArrayStar) + array[i] = instance.NewGeneralArrayStar(elt, nil).(*instance.GeneralArrayStar) } } - return instance.New(class.GeneralArrayStar, array, nil), nil + return instance.NewGeneralArrayStar(array, nil), nil } } @@ -110,20 +110,20 @@ func Aref(_, _ *environment.Environment, basicArray ilos.Instance, dimensions .. switch { case instance.Of(class.String, basicArray): if len(dimensions) != 1 { - return ProgramError("ARITY-ERROR") + return nil, instance.NewArityError() } index := int(dimensions[0].(instance.Integer)) if len(basicArray.(instance.String)) <= index { - return ProgramError("INDEX-OUT-OF-RANGE") + return nil, instance.NewIndexOutOfRange() } - return instance.Character(basicArray.(instance.String)[index]), nil + return instance.NewCharacter(basicArray.(instance.String)[index]), nil case instance.Of(class.GeneralVector, basicArray): if len(dimensions) != 1 { - return ProgramError("ARITY-ERROR") + return nil, instance.NewArityError() } index := int(dimensions[0].(instance.Integer)) if len(basicArray.(instance.GeneralVector)) <= index { - return ProgramError("INDEX-OUT-OF-RANGE") + return nil, instance.NewIndexOutOfRange() } return basicArray.(instance.GeneralVector)[index], nil default: // General Array* @@ -144,12 +144,12 @@ func Garef(_, _ *environment.Environment, generalArray ilos.Instance, dimensions for _, dim := range dimensions { index := int(dim.(instance.Integer)) if array.Vector == nil || len(array.Vector) <= index { - return ProgramError("INDEX-OUT-OF-RANGE") + return nil, instance.NewIndexOutOfRange() } array = array.Vector[index] } if array.Scalar == nil { - return ProgramError("INDEX-OUT-OF-RANGE") + return nil, instance.NewIndexOutOfRange() } return array.Scalar, nil } @@ -170,21 +170,21 @@ func SetAref(_, _ *environment.Environment, obj, basicArray ilos.Instance, dimen return nil, err } if len(dimensions) != 1 { - return ProgramError("ARITY-ERROR") + return nil, instance.NewArityError() } index := int(dimensions[0].(instance.Integer)) if len(basicArray.(instance.String)) <= index { - return ProgramError("INDEX-OUT-OF-RANGE") + return nil, instance.NewIndexOutOfRange() } basicArray.(instance.String)[index] = rune(obj.(instance.Character)) return obj, nil case instance.Of(class.GeneralVector, basicArray): if len(dimensions) != 1 { - return ProgramError("ARITY-ERROR") + return nil, instance.NewArityError() } index := int(dimensions[0].(instance.Integer)) if len(basicArray.(instance.GeneralVector)) <= index { - return ProgramError("INDEX-OUT-OF-RANGE") + return nil, instance.NewIndexOutOfRange() } basicArray.(instance.GeneralVector)[index] = obj return obj, nil @@ -207,12 +207,12 @@ func SetGaref(_, _ *environment.Environment, obj, generalArray ilos.Instance, di for _, dim := range dimensions { index := int(dim.(instance.Integer)) if array.Vector == nil || len(array.Vector) <= index { - return ProgramError("INDEX-OUT-OF-RANGE") + return nil, instance.NewIndexOutOfRange() } array = array.Vector[index] } if array.Scalar == nil { - return ProgramError("INDEX-OUT-OF-RANGE") + return nil, instance.NewIndexOutOfRange() } array.Scalar = obj return obj, nil @@ -227,14 +227,14 @@ func ArrayDimensions(_, _ *environment.Environment, basicArray ilos.Instance) (i } switch { case instance.Of(class.String, basicArray): - return List(nil, nil, instance.Integer(len(basicArray.(instance.String)))) + return List(nil, nil, instance.NewInteger(len(basicArray.(instance.String)))) case instance.Of(class.GeneralVector, basicArray): - return List(nil, nil, instance.Integer(len(basicArray.(instance.GeneralVector)))) + return List(nil, nil, instance.NewInteger(len(basicArray.(instance.GeneralVector)))) default: // General Array* var array *instance.GeneralArrayStar dimensions := []ilos.Instance{} for array.Vector != nil { - dimensions = append(dimensions, instance.Integer(len(array.Vector))) + dimensions = append(dimensions, instance.NewInteger(len(array.Vector))) array = array.Vector[0] } return List(nil, nil, dimensions...) diff --git a/runtime/boolean_values.go b/runtime/boolean_values.go index c1852d4..3cc4aac 100644 --- a/runtime/boolean_values.go +++ b/runtime/boolean_values.go @@ -5,7 +5,6 @@ package runtime import ( - "github.com/ta2gch/iris/runtime/ilos/class" "github.com/ta2gch/iris/runtime/ilos/instance" ) @@ -30,6 +29,6 @@ import ( // t is a named constant whose value is the symbol t itself. // nil is a named constant whose value is the symbol nil itself. var ( - Nil = instance.New(class.Null) - T = instance.Symbol("T") + Nil = instance.NewNull() + T = instance.NewSymbol("T") ) diff --git a/runtime/conditional_expressions.go b/runtime/conditional_expressions.go index ebc672f..6d8422b 100644 --- a/runtime/conditional_expressions.go +++ b/runtime/conditional_expressions.go @@ -27,7 +27,7 @@ func If(local, global *environment.Environment, testForm, thenForm ilos.Instance return Eval(local, global, thenForm) } if len(elseForm) > 1 { - return ProgramError("ARITY-ERROR") + return nil, instance.NewArityError() } if len(elseForm) == 0 { return Nil, nil @@ -48,7 +48,7 @@ func Cond(local, global *environment.Environment, testFrom ...ilos.Instance) (il } s := tf.(instance.List).Slice() if len(s) == 0 { - return ProgramError("ARITY-ERROR") + return nil, instance.NewArityError() } ret, err := Eval(local, global, s[0]) if err != nil { @@ -85,7 +85,7 @@ func Case(local, global *environment.Environment, key ilos.Instance, pattern ... } form := pat.(instance.List).Slice() if len(form) < 1 { - return ProgramError("ARITY-ERROR") + return nil, instance.NewArityError() } if idx == len(pattern)-1 && form[0] == T { return Progn(local, global, form[1:]...) @@ -132,7 +132,7 @@ func CaseUsing(local, global *environment.Environment, key, pred ilos.Instance, } form := pat.(instance.List).Slice() if len(form) < 1 { - return ProgramError("ARITY-ERROR") + return nil, instance.NewArityError() } if idx == len(pattern)-1 && form[0] == T { return Progn(local, global, form[1:]...) diff --git a/runtime/cons.go b/runtime/cons.go index b5b1f56..1ef4325 100644 --- a/runtime/cons.go +++ b/runtime/cons.go @@ -26,7 +26,7 @@ func Consp(_, _ *environment.Environment, obj ilos.Instance) (ilos.Instance, ilo // be allocated (error-id. cannot-create-cons). Both obj1 // and obj2 may be any ISLISP object. func Cons(_, _ *environment.Environment, obj1, obj2 ilos.Instance) (ilos.Instance, ilos.Instance) { - return instance.New(class.Cons, obj1, obj2), nil + return instance.NewCons(obj1, obj2), nil } // Car returns the left component of the cons. diff --git a/runtime/defining_operators.go b/runtime/defining_operators.go index a5a27e3..66239ee 100644 --- a/runtime/defining_operators.go +++ b/runtime/defining_operators.go @@ -8,6 +8,7 @@ import ( "github.com/ta2gch/iris/runtime/environment" "github.com/ta2gch/iris/runtime/ilos" "github.com/ta2gch/iris/runtime/ilos/class" + "github.com/ta2gch/iris/runtime/ilos/instance" ) // Defconstant is used to define a named constant in the variable namespace of the current toplevel @@ -45,7 +46,7 @@ func Defglobal(local, global *environment.Environment, name, form ilos.Instance) return nil, err } if _, ok := global.Constant.Get(name); ok { - return ProgramError("IMMUTABLE-BIDING") + return nil, instance.NewImmutableBinding() } ret, err := Eval(local, global, form) if err != nil { @@ -64,7 +65,7 @@ func Defdynamic(local, global *environment.Environment, name, form ilos.Instance return nil, err } if _, ok := global.Constant.Get(name); ok { - return ProgramError("IMMUTABLE-BIDING") + return nil, instance.NewImmutableBinding() } ret, err := Eval(local, global, form) if err != nil { diff --git a/runtime/dynamic_variables.go b/runtime/dynamic_variables.go index bd97c51..24052d2 100644 --- a/runtime/dynamic_variables.go +++ b/runtime/dynamic_variables.go @@ -33,7 +33,7 @@ func Dynamic(local, global *environment.Environment, var1 ilos.Instance) (ilos.I } return nil, instance.New(class.UndefinedVariable, map[string]ilos.Instance{ "NAME": var1, - "NAMESPACE": instance.Symbol("Variable"), + "NAMESPACE": instance.NewSymbol("Variable"), }) } @@ -62,7 +62,7 @@ func SetDynamic(local, global *environment.Environment, form, var1 ilos.Instance } return nil, instance.New(class.UndefinedFunction, map[string]ilos.Instance{ "NAME": var1, - "NAMESPACE": instance.Symbol("FUNCTION"), + "NAMESPACE": instance.NewSymbol("FUNCTION"), }) } @@ -94,7 +94,7 @@ func DyamicLet(local, global *environment.Environment, varForm ilos.Instance, bo } s := cadr.(instance.List).Slice() if len(s) != 2 { - return ProgramError("ARITY-ERROR") + return nil, instance.NewArityError() } f, err := Eval(local, global, s[1]) if err != nil { @@ -104,7 +104,7 @@ func DyamicLet(local, global *environment.Environment, varForm ilos.Instance, bo } for v, f := range vfs { if !local.DynamicVariable.Define(v, f) { - return ProgramError("IMMUTABLE-BINDING") + return nil, instance.NewImmutableBinding() } } return Progn(local, global, bodyForm...) diff --git a/runtime/eval.go b/runtime/eval.go index d4a28b0..6f97ae0 100644 --- a/runtime/eval.go +++ b/runtime/eval.go @@ -29,7 +29,7 @@ func evalArguments(local, global *environment.Environment, arguments ilos.Instan if err != nil { return nil, err } - return instance.New(class.Cons, a, b), nil + return instance.NewCons(a, b), nil } @@ -37,7 +37,7 @@ func evalLambda(local, global *environment.Environment, car, cdr ilos.Instance) // eval if lambda form if instance.Of(class.Cons, car) { caar := car.(*instance.Cons).Car // Checked at the top of// This sentence - if caar == instance.Symbol("LAMBDA") { + if caar == instance.NewSymbol("LAMBDA") { fun, err := Eval(local, global, car) if err != nil { return nil, err, true @@ -159,7 +159,7 @@ func evalCons(local, global *environment.Environment, obj ilos.Instance) (ilos.I return nil, instance.New(class.UndefinedFunction, map[string]ilos.Instance{ "NAME": car, - "NAMESPACE": instance.Symbol("FUNCTION"), + "NAMESPACE": instance.NewSymbol("FUNCTION"), }) } @@ -175,7 +175,7 @@ func evalVariable(local, global *environment.Environment, obj ilos.Instance) (il } return nil, instance.New(class.UndefinedVariable, map[string]ilos.Instance{ "NAME": obj, - "NAMESPACE": instance.Symbol("VARIABLE"), + "NAMESPACE": instance.NewSymbol("VARIABLE"), }) } diff --git a/runtime/float_class.go b/runtime/float_class.go index f184f2f..5004e75 100644 --- a/runtime/float_class.go +++ b/runtime/float_class.go @@ -19,8 +19,8 @@ import ( // The value of MostNegativeFloat is the implementation-dependent // floating-point number closest to negative infinity. var ( - MostPositiveFloat = instance.Float(math.MaxFloat64) - MostNegativeFloat = instance.Float(-math.MaxFloat64) + MostPositiveFloat = instance.NewFloat(math.MaxFloat64) + MostNegativeFloat = instance.NewFloat(-math.MaxFloat64) ) // Floatp returns t if obj is a float (instance of class float); @@ -40,7 +40,7 @@ func Float(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos. if err != nil { return nil, err } - return instance.Float(f), nil + return instance.NewFloat(f), nil } // Floor returns the greatest integer less than or equal to x . @@ -51,7 +51,7 @@ func Floor(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos. if err != nil { return nil, err } - return instance.Integer(int(math.Floor(f))), nil + return instance.NewInteger(int(math.Floor(f))), nil } // Ceiling Returns the smallest integer that is not smaller than x. @@ -62,7 +62,7 @@ func Ceiling(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilo if err != nil { return nil, err } - return instance.Integer(int(math.Ceil(f))), nil + return instance.NewInteger(int(math.Ceil(f))), nil } // Truncate returns the integer between 0 and x (inclusive) that is nearest to x. @@ -73,7 +73,7 @@ func Truncate(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, il if err != nil { return nil, err } - return instance.Integer(int(math.Trunc(f))), nil + return instance.NewInteger(int(math.Trunc(f))), nil } // Round returns the integer nearest to x. @@ -84,5 +84,5 @@ func Round(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos. if err != nil { return nil, err } - return instance.Integer(int(math.Floor(f + .5))), nil + return instance.NewInteger(int(math.Floor(f + .5))), nil } diff --git a/runtime/functions.go b/runtime/functions.go index 2cb16b5..d7d1166 100644 --- a/runtime/functions.go +++ b/runtime/functions.go @@ -44,7 +44,7 @@ func Function(local, global *environment.Environment, fun ilos.Instance) (ilos.I } return nil, instance.New(class.UndefinedFunction, map[string]ilos.Instance{ "NAME": fun, - "NAMESPACE": instance.Symbol("FUNCTION"), + "NAMESPACE": instance.NewSymbol("FUNCTION"), }) } @@ -76,7 +76,7 @@ func Lambda(local, global *environment.Environment, lambdaList ilos.Instance, fo if err := checkLambdaList(lambdaList); err != nil { return nil, err } - return newNamedFunction(local, global, instance.Symbol("ANONYMOUS-FUNCTION"), lambdaList, form...) + return newNamedFunction(local, global, instance.NewSymbol("ANONYMOUS-FUNCTION"), lambdaList, form...) } // Labels special form allow the definition of new identifiers in the function @@ -112,7 +112,7 @@ func Labels(local, global *environment.Environment, functions ilos.Instance, bod } definition := function.(instance.List).Slice() if len(definition) < 2 { - return ProgramError("ARITY-ERROR") + return nil, instance.NewArityError() } functionName := definition[0] lambdaList := definition[1] @@ -122,7 +122,7 @@ func Labels(local, global *environment.Environment, functions ilos.Instance, bod return nil, err } if !local.Function.Define(functionName, fun) { - return ProgramError("IMMUTABLE-BINDING") + return nil, instance.NewImmutableBinding() } } return Progn(local, global, bodyForm...) @@ -141,7 +141,7 @@ func Flet(local, global *environment.Environment, functions ilos.Instance, bodyF } definition := function.(instance.List).Slice() if len(definition) < 2 { - return ProgramError("ARITY-ERROR") + return nil, instance.NewArityError() } functionName := definition[0] lambdaList := definition[1] @@ -151,7 +151,7 @@ func Flet(local, global *environment.Environment, functions ilos.Instance, bodyF return nil, err } if !env.Function.Define(functionName, fun) { - return ProgramError("IMMUTABLE-BIDING") + return nil, instance.NewImmutableBinding() } } return Progn(env, global, bodyForm...) diff --git a/runtime/ilos/class/class.go b/runtime/ilos/class/class.go index 3d917a4..f4c5421 100644 --- a/runtime/ilos/class/class.go +++ b/runtime/ilos/class/class.go @@ -56,7 +56,7 @@ var FloatingPointOnderflow = &builtinclass{[]ilos.Class{ArithmeticError}, []stri var FloatingPointUnderflow = &builtinclass{[]ilos.Class{ArithmeticError}, []string{}, ""} var ControlError = &builtinclass{[]ilos.Class{Error}, []string{}, ""} var ParseError = &builtinclass{[]ilos.Class{Error}, []string{"STRING", "EXPECTED-CLASS"}, ""} -var ProgramError = &builtinclass{[]ilos.Class{Error}, []string{"CAUSE"}, ""} +var ProgramError = &builtinclass{[]ilos.Class{Error}, []string{}, ""} var DomainError = &builtinclass{[]ilos.Class{ProgramError}, []string{"OBJECT", "EXPECTED-CLASS"}, ""} var UndefinedEntity = &builtinclass{[]ilos.Class{ProgramError}, []string{"NAME", "NAMESPACE"}, ""} var UndefinedVariable = &builtinclass{[]ilos.Class{UndefinedEntity}, []string{}, ""} diff --git a/runtime/ilos/instance/basic-array.go b/runtime/ilos/instance/basic-array.go index 60081bd..426fe3f 100644 --- a/runtime/ilos/instance/basic-array.go +++ b/runtime/ilos/instance/basic-array.go @@ -19,6 +19,10 @@ type GeneralArrayStar struct { Scalar ilos.Instance } +func NewGeneralArrayStar(vector []*GeneralArrayStar, scalar ilos.Instance) ilos.Instance { + return GeneralArrayStar{vector, scalar} +} + func (GeneralArrayStar) Class() ilos.Class { return class.GeneralArrayStar } @@ -41,6 +45,10 @@ func (i GeneralArrayStar) String() string { type GeneralVector []ilos.Instance +func NewGeneralVector(v []ilos.Instance) ilos.Instance { + return GeneralVector(v) +} + func (GeneralVector) Class() ilos.Class { return class.GeneralVector } @@ -63,6 +71,10 @@ func (i GeneralVector) String() string { type String []rune +func NewString(s string) ilos.Instance { + return String(s) +} + func (String) Class() ilos.Class { return class.String } diff --git a/runtime/ilos/instance/character.go b/runtime/ilos/instance/character.go index 5fb6251..dac8824 100644 --- a/runtime/ilos/instance/character.go +++ b/runtime/ilos/instance/character.go @@ -15,6 +15,10 @@ import ( type Character rune +func NewCharacter(r rune) ilos.Instance { + return Character(r) +} + func (Character) Class() ilos.Class { return class.Character } diff --git a/runtime/ilos/instance/error.go b/runtime/ilos/instance/error.go new file mode 100644 index 0000000..e147d97 --- /dev/null +++ b/runtime/ilos/instance/error.go @@ -0,0 +1,57 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package instance + +import ( + "github.com/ta2gch/iris/runtime/ilos" + "github.com/ta2gch/iris/runtime/ilos/class" +) + +func NewArithmeticError(operation, operands ilos.Instance) ilos.Instance { + return New(class.ArithmeticError, map[string]ilos.Instance{ + "OPERATION": operation, + "OPERANDS": operands, + }) +} + +func NewParseError(str, expectedClass ilos.Instance) ilos.Instance { + return New(class.ParseError, map[string]ilos.Instance{ + "STRING": str, + "EXPECTED-CLASSS": expectedClass, + }) +} + +func NewDomainError(object, expectedClass ilos.Instance) ilos.Instance { + return New(class.DomainError, map[string]ilos.Instance{"CAUSE": Symbol("DOMAIN-ERROR"), + "OBJECT": object, + "EXPECTED-CLASSS": expectedClass, + }) +} + +func NewUndefinedFunction(name ilos.Instance) ilos.Instance { + return New(class.UndefinedFunction, map[string]ilos.Instance{ + "NAME": name, + "NAMESPACE": Symbol("FUNCTION"), + }) +} + +func NewUndefinedVariable(name ilos.Instance) ilos.Instance { + return New(class.UndefinedVariable, map[string]ilos.Instance{ + "NAME": name, + "NAMESPACE": Symbol("VARIABLE"), + }) +} + +func NewArityError() ilos.Instance { + return New(class.ProgramError, map[string]ilos.Instance{}) +} + +func NewIndexOutOfRange() ilos.Instance { + return New(class.ProgramError, map[string]ilos.Instance{}) +} + +func NewImmutableBinding() ilos.Instance { + return New(class.ProgramError, map[string]ilos.Instance{}) +} diff --git a/runtime/ilos/instance/function.go b/runtime/ilos/instance/function.go index 75eba65..3973a18 100644 --- a/runtime/ilos/instance/function.go +++ b/runtime/ilos/instance/function.go @@ -18,10 +18,14 @@ type Applicable interface { } type Function struct { - name Symbol + name ilos.Instance function interface{} } +func NewFunction(name ilos.Instance, function interface{}) ilos.Instance { + return Function{name, function} +} + func (Function) Class() ilos.Class { return class.Function } diff --git a/runtime/ilos/instance/instance.go b/runtime/ilos/instance/instance.go index 792e054..20369e4 100644 --- a/runtime/ilos/instance/instance.go +++ b/runtime/ilos/instance/instance.go @@ -16,26 +16,15 @@ import ( // func New(c ilos.Class, s ...interface{}) ilos.Instance { - switch c { - case class.Function: - return Function{s[0].(Symbol), s[1]} - case class.Cons: - return &Cons{s[0].(ilos.Instance), s[1].(ilos.Instance)} - case class.Null: - return Null{} - case class.GeneralArrayStar: - return &GeneralArrayStar{s[0].([]*GeneralArrayStar), s[1].(ilos.Instance)} - default: - p := []ilos.Instance{} - for _, q := range c.Parents() { - p = append(p, New(q, s...)) - } - t := map[string]ilos.Instance{} - for _, n := range c.Slots() { - t[n] = s[0].(map[string]ilos.Instance)[n] - } - return &instance{c, p, t} + p := []ilos.Instance{} + for _, q := range c.Parents() { + p = append(p, New(q, s...)) + } + t := map[string]ilos.Instance{} + for _, n := range c.Slots() { + t[n] = s[0].(map[string]ilos.Instance)[n] } + return &instance{c, p, t} } func Of(p ilos.Class, i ilos.Instance) bool { diff --git a/runtime/ilos/instance/list.go b/runtime/ilos/instance/list.go index 7e8c258..3934606 100644 --- a/runtime/ilos/instance/list.go +++ b/runtime/ilos/instance/list.go @@ -24,6 +24,10 @@ type Cons struct { Cdr ilos.Instance } +func NewCons(car, cdr ilos.Instance) ilos.Instance { + return &Cons{car, cdr} +} + func (*Cons) Class() ilos.Class { return class.Cons } @@ -85,6 +89,10 @@ func (i *Cons) Slice() []ilos.Instance { type Null struct{} +func NewNull() ilos.Instance { + return Null{} +} + func (Null) Class() ilos.Class { return class.Null } diff --git a/runtime/ilos/instance/number.go b/runtime/ilos/instance/number.go index 122002a..7ae1737 100644 --- a/runtime/ilos/instance/number.go +++ b/runtime/ilos/instance/number.go @@ -17,6 +17,9 @@ import ( type Integer int +func NewInteger(i int) ilos.Instance { + return Integer(i) +} func (Integer) Class() ilos.Class { return class.Integer } @@ -39,6 +42,10 @@ func (i Integer) String() string { type Float float64 +func NewFloat(i float64) ilos.Instance { + return Float(i) +} + func (Float) Class() ilos.Class { return class.Float } diff --git a/runtime/ilos/instance/symbol.go b/runtime/ilos/instance/symbol.go index 2bc4983..53a95c6 100644 --- a/runtime/ilos/instance/symbol.go +++ b/runtime/ilos/instance/symbol.go @@ -15,6 +15,10 @@ import ( type Symbol string +func NewSymbol(s string) ilos.Instance { + return Symbol(s) +} + func (Symbol) Class() ilos.Class { return class.Symbol } diff --git a/runtime/integer_class.go b/runtime/integer_class.go index bd1c989..ce19d71 100644 --- a/runtime/integer_class.go +++ b/runtime/integer_class.go @@ -42,11 +42,11 @@ func Div(_, _ *environment.Environment, z1, z2 ilos.Instance) (ilos.Instance, il } if b == 0 { return nil, instance.New(class.DivisionByZero, map[string]ilos.Instance{ - "OPERATION": instance.Symbol("DIV"), - "OPERANDS": instance.New(class.Cons, z1, instance.New(class.Cons, z2, Nil)), + "OPERATION": instance.NewSymbol("DIV"), + "OPERANDS": instance.NewCons(z1, instance.NewCons(z2, Nil)), }) } - return instance.Integer(a / b), nil + return instance.NewInteger(a / b), nil } // Mod returns the remainder of the integer division of z1 by z2. @@ -66,11 +66,11 @@ func Mod(_, _ *environment.Environment, z1, z2 ilos.Instance) (ilos.Instance, il } if b == 0 { return nil, instance.New(class.DivisionByZero, map[string]ilos.Instance{ - "OPERATION": instance.Symbol("MOD"), - "OPERANDS": instance.New(class.Cons, z1, instance.New(class.Cons, z2, Nil)), + "OPERATION": instance.NewSymbol("MOD"), + "OPERANDS": instance.NewCons(z1, instance.NewCons(z2, Nil)), }) } - return instance.Integer(a % b), nil + return instance.NewInteger(a % b), nil } // Gcd returns the greatest common divisor of its integer arguments. @@ -95,7 +95,7 @@ func Gcd(_, _ *environment.Environment, z1, z2 ilos.Instance) (ilos.Instance, il if err != nil { return nil, err } - return instance.Integer(gcd(a, b)), nil + return instance.NewInteger(gcd(a, b)), nil } // Lcm returns the least common multiple of its integer arguments. @@ -117,7 +117,7 @@ func Lcm(_, _ *environment.Environment, z1, z2 ilos.Instance) (ilos.Instance, il if err != nil { return nil, err } - return instance.Integer(a * b / gcd(a, b)), nil + return instance.NewInteger(a * b / gcd(a, b)), nil } // Isqrt Returns the greatest integer less than or equal to @@ -134,5 +134,5 @@ func Isqrt(_, _ *environment.Environment, z ilos.Instance) (ilos.Instance, ilos. "EXPECTED-CLASS": class.Number, }) } - return instance.Integer(int(math.Sqrt(float64(a)))), nil + return instance.NewInteger(int(math.Sqrt(float64(a)))), nil } diff --git a/runtime/iteration.go b/runtime/iteration.go index ec7077b..a31ec66 100644 --- a/runtime/iteration.go +++ b/runtime/iteration.go @@ -69,10 +69,10 @@ func For(local, global *environment.Environment, iterationSpecs, endTestAndResul var1 := i[0] init := i[1] if !local.Variable.Define(var1, init) { - return ProgramError("IMMUTABLE-BINDING") + return nil, instance.NewImmutableBinding() } default: - return ProgramError("ARITY-ERROR") + return nil, instance.NewArityError() } } if err := ensure(class.List, endTestAndResults); err != nil { @@ -104,10 +104,10 @@ func For(local, global *environment.Environment, iterationSpecs, endTestAndResul var1 := i[0] step := i[2] if local.Variable.Set(var1, step) { - return ProgramError("IMMUTABLE-BINDING") + return nil, instance.NewImmutableBinding() } default: - return ProgramError("ARITY-ERROR") + return nil, instance.NewArityError() } } test, err = Eval(local, global, endTest) diff --git a/runtime/list_operations.go b/runtime/list_operations.go index 46646c5..a12e7b7 100644 --- a/runtime/list_operations.go +++ b/runtime/list_operations.go @@ -32,7 +32,7 @@ func CreateList(_, _ *environment.Environment, i ilos.Instance, initialElement . return nil, err } if len(initialElement) > 1 { - return ProgramError("ARITY-ERROR") + return nil, instance.NewArityError() } elm := Nil if len(initialElement) == 1 { @@ -40,7 +40,7 @@ func CreateList(_, _ *environment.Environment, i ilos.Instance, initialElement . } cons := Nil for j := 0; j < int(i.(instance.Integer)); j++ { - cons = instance.New(class.Cons, elm, cons) + cons = instance.NewCons(elm, cons) } return cons, nil } @@ -51,7 +51,7 @@ func CreateList(_, _ *environment.Environment, i ilos.Instance, initialElement . func List(_, _ *environment.Environment, objs ...ilos.Instance) (ilos.Instance, ilos.Instance) { cons := Nil for i := len(objs) - 1; i >= 0; i-- { - cons = instance.New(class.Cons, objs[i], cons) + cons = instance.NewCons(objs[i], cons) } return cons, nil } @@ -67,7 +67,7 @@ func Reverse(_, _ *environment.Environment, list ilos.Instance) (ilos.Instance, } cons := Nil for _, car := range list.(instance.List).Slice() { - cons = instance.New(class.Cons, car, cons) + cons = instance.NewCons(car, cons) } return cons, nil } @@ -85,7 +85,7 @@ func Nreverse(_, _ *environment.Environment, list ilos.Instance) (ilos.Instance, } cons := Nil for _, car := range list.(instance.List).Slice() { - cons = instance.New(class.Cons, car, cons) + cons = instance.NewCons(car, cons) } return cons, nil } diff --git a/runtime/namedfunc.go b/runtime/namedfunc.go index 5d5eee0..a985bd7 100644 --- a/runtime/namedfunc.go +++ b/runtime/namedfunc.go @@ -20,10 +20,9 @@ func checkLambdaList(lambdaList ilos.Instance) ilos.Instance { if err := ensure(class.Symbol, cadr); err != nil { return err } - if cadr == instance.Symbol(":REST") || cadr == instance.Symbol("&REST") { + if cadr == instance.NewSymbol(":REST") || cadr == instance.NewSymbol("&REST") { if len(cdr) != i+2 { - _, err := ProgramError("ARITY-ERROR") - return err + return instance.NewArityError() } } } @@ -32,38 +31,41 @@ func checkLambdaList(lambdaList ilos.Instance) ilos.Instance { func newNamedFunction(local, global *environment.Environment, functionName, lambdaList ilos.Instance, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { lexical := local + if err := ensure(class.Symbol, functionName); err != nil { + return nil, err + } if err := checkLambdaList(lambdaList); err != nil { return nil, err } parameters := []ilos.Instance{} variadic := false for _, cadr := range lambdaList.(instance.List).Slice() { - if cadr == instance.Symbol(":REST") || cadr == instance.Symbol("&REST") { + if cadr == instance.NewSymbol(":REST") || cadr == instance.NewSymbol("&REST") { variadic = true } parameters = append(parameters, cadr) } - return instance.New(class.Function, functionName, func(local, global *environment.Environment, arguments ...ilos.Instance) (ilos.Instance, ilos.Instance) { + return instance.NewFunction(functionName.(instance.Symbol), func(local, global *environment.Environment, arguments ...ilos.Instance) (ilos.Instance, ilos.Instance) { local.Merge(lexical) if (variadic && len(parameters)-2 > len(arguments)) || (!variadic && len(parameters) != len(arguments)) { - return ProgramError("ARITY-ERROR") + return nil, instance.NewArityError() } for idx := range parameters { key := parameters[idx] - if key == instance.Symbol(":REST") || key == instance.Symbol("&REST") { + if key == instance.NewSymbol(":REST") || key == instance.NewSymbol("&REST") { key := parameters[idx+1] value, err := List(nil, nil, arguments[idx:]...) if err != nil { return nil, err } if !local.Variable.Define(key, value) { - return ProgramError("IMMUTABLE-BINDING") + return nil, instance.NewImmutableBinding() } break } value := arguments[idx] if !local.Variable.Define(key, value) { - return ProgramError("IMMUTABLE-BINDING") + return nil, instance.NewImmutableBinding() } } return Progn(local, global, forms...) diff --git a/runtime/non-local_exits.go b/runtime/non-local_exits.go index dc90124..53f0b4c 100644 --- a/runtime/non-local_exits.go +++ b/runtime/non-local_exits.go @@ -51,7 +51,7 @@ func Block(local, global *environment.Environment, tag ilos.Instance, body ...il }) } if !local.BlockTag.Define(tag, nil) { - return ProgramError("IMMUTABLE-BINDING") + return nil, instance.NewImmutableBinding() } var fail ilos.Instance sucess := Nil @@ -59,9 +59,9 @@ func Block(local, global *environment.Environment, tag ilos.Instance, body ...il sucess, fail = Eval(local, global, cadr) if fail != nil { if instance.Of(class.BlockTag, fail) { - tag1, _ := fail.GetSlotValue(instance.Symbol("TAG"), class.Escape) // Checked at the head of// This condition + tag1, _ := fail.GetSlotValue(instance.NewSymbol("TAG"), class.Escape) // Checked at the head of// This condition if tag == tag1 { - obj, _ := fail.GetSlotValue(instance.Symbol("OBJECT"), class.BlockTag) // Checked at the head of// This condition + obj, _ := fail.GetSlotValue(instance.NewSymbol("OBJECT"), class.BlockTag) // Checked at the head of// This condition return obj, nil } } @@ -89,7 +89,7 @@ func ReturnFrom(local, global *environment.Environment, tag, object ilos.Instanc } if _, ok := local.BlockTag.Get(tag); !ok { return nil, instance.New(class.SimpleError, map[string]ilos.Instance{ - "FORMAT-STRING": instance.String("%v is not defined as the tag"), + "FORMAT-STRING": instance.NewString("%v is not defined as the tag"), "FORMAT-ARGUMENTS": tag, }) } @@ -109,7 +109,7 @@ func Catch(local, global *environment.Environment, tag ilos.Instance, body ...il return nil, instance.New(class.DomainError, tag, class.Object) } if !local.CatchTag.Define(tag, nil) { - return ProgramError("IMMUTABLE-BINDING") + return nil, instance.NewImmutableBinding() } var fail ilos.Instance sucess := Nil @@ -117,9 +117,9 @@ func Catch(local, global *environment.Environment, tag ilos.Instance, body ...il sucess, fail = Eval(local, global, cadr) if fail != nil { if instance.Of(class.CatchTag, fail) { - tag1, _ := fail.GetSlotValue(instance.Symbol("TAG"), class.Escape) // Checked at the head of// This condition + tag1, _ := fail.GetSlotValue(instance.NewSymbol("TAG"), class.Escape) // Checked at the head of// This condition if tag == tag1 { - obj, _ := fail.GetSlotValue(instance.Symbol("OBJECT"), class.CatchTag) // Checked at the head of// This condition + obj, _ := fail.GetSlotValue(instance.NewSymbol("OBJECT"), class.CatchTag) // Checked at the head of// This condition return obj, nil } } @@ -147,7 +147,7 @@ func Throw(local, global *environment.Environment, tag, object ilos.Instance) (i } if _, ok := local.CatchTag.Get(tag); !ok { return nil, instance.New(class.SimpleError, map[string]ilos.Instance{ - "FORMAT-STRING": instance.String("%v is not defined as the tag"), + "FORMAT-STRING": instance.NewString("%v is not defined as the tag"), "FORMAT-ARGUMENTS": tag, }) } @@ -162,7 +162,7 @@ func Tagbody(local, global *environment.Environment, body ...ilos.Instance) (ilo cddr := instance.GeneralVector(body[idx+1:]) if !instance.Of(class.Cons, cadr) { if !local.TagbodyTag.Define(cadr, cddr) { - return ProgramError("IMMUTABLE-BINDING") + return nil, instance.NewImmutableBinding() } } } @@ -172,7 +172,7 @@ func Tagbody(local, global *environment.Environment, body ...ilos.Instance) (ilo if fail != nil { TAG: if instance.Of(class.TagbodyTag, fail) { - tag, _ := fail.GetSlotValue(instance.Symbol("TAG"), class.Escape) // Checked at the top of// This loop + tag, _ := fail.GetSlotValue(instance.NewSymbol("TAG"), class.Escape) // Checked at the top of// This loop found := false for _, tag1 := range body { if tag == tag1 { @@ -204,7 +204,7 @@ func Tagbody(local, global *environment.Environment, body ...ilos.Instance) (ilo func Go(local, global *environment.Environment, tag ilos.Instance) (ilos.Instance, ilos.Instance) { if _, ok := local.TagbodyTag.Get(tag); !ok { return nil, instance.New(class.SimpleError, map[string]ilos.Instance{ - "FORMAT-STRING": instance.String("%v is not defined as the tag"), + "FORMAT-STRING": instance.NewString("%v is not defined as the tag"), "FORMAT-ARGUMENTS": tag, }) } diff --git a/runtime/number_class.go b/runtime/number_class.go index 0d22f14..383074b 100644 --- a/runtime/number_class.go +++ b/runtime/number_class.go @@ -152,9 +152,9 @@ func Add(_, _ *environment.Environment, x ...ilos.Instance) (ilos.Instance, ilos sum += f } if flt { - return instance.Float(sum), nil + return instance.NewFloat(sum), nil } - return instance.Integer(int(sum)), nil + return instance.NewInteger(int(sum)), nil } // Multiply returns the product, respectively, of their arguments. If all arguments are integers, @@ -172,9 +172,9 @@ func Multiply(_, _ *environment.Environment, x ...ilos.Instance) (ilos.Instance, flt = flt || b } if flt { - return instance.Float(pdt), nil + return instance.NewFloat(pdt), nil } - return instance.Integer(int(pdt)), nil + return instance.NewInteger(int(pdt)), nil } // Substruct returns its additive inverse. An error shall be signaled @@ -186,7 +186,7 @@ func Multiply(_, _ *environment.Environment, x ...ilos.Instance) (ilos.Instance, // x1 −x2 − … −xn. An error shall be signaled if any x is not a number (error-id. domain-error). func Substruct(_, _ *environment.Environment, x ilos.Instance, xs ...ilos.Instance) (ilos.Instance, ilos.Instance) { if len(xs) == 0 { - ret, err := Substruct(nil, nil, instance.Integer(0), x) + ret, err := Substruct(nil, nil, instance.NewInteger(0), x) return ret, err } sub, flt, err := convFloat64(x) @@ -202,9 +202,9 @@ func Substruct(_, _ *environment.Environment, x ilos.Instance, xs ...ilos.Instan flt = flt || b } if flt { - return instance.Float(sub), nil + return instance.NewFloat(sub), nil } - return instance.Integer(int(sub)), nil + return instance.NewInteger(int(sub)), nil } // Quotient returns the quotient of those numbers. The result is an integer if dividend and divisor are integers and divisor evenly divides dividend , otherwise it will be a float. @@ -225,10 +225,10 @@ func Quotient(_, _ *environment.Environment, dividend, divisor1 ilos.Instance, d if f == 0.0 { arguments := Nil for i := len(divisor) - 1; i >= 0; i-- { - arguments = instance.New(class.Cons, divisor[i], arguments) + arguments = instance.NewCons(divisor[i], arguments) } return nil, instance.New(class.DivisionByZero, map[string]ilos.Instance{ - "OPERATION": instance.Symbol("QUOTIENT"), + "OPERATION": instance.NewSymbol("QUOTIENT"), "OPERANDS": arguments, }) } @@ -238,15 +238,15 @@ func Quotient(_, _ *environment.Environment, dividend, divisor1 ilos.Instance, d quotient /= f } if flt { - return instance.Float(quotient), nil + return instance.NewFloat(quotient), nil } - return instance.Integer(int(quotient)), nil + return instance.NewInteger(int(quotient)), nil } // Reciprocal returns the reciprocal of its argument x ; that is, 1/x . // An error shall be signaled if x is zero (error-id. division-by-zero). func Reciprocal(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { - return Quotient(nil, nil, instance.Integer(1), x) + return Quotient(nil, nil, instance.NewInteger(1), x) } // Max returns the greatest (closest to positive infinity) of its arguments. The comparison is done by >. @@ -284,7 +284,7 @@ func Min(_, _ *environment.Environment, x ilos.Instance, xs ...ilos.Instance) (i // Abs returns the absolute value of its argument. // An error shall be signaled if x is not a number (error-id. domain-error). func Abs(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { - ret, err := NumberLessThan(nil, nil, x, instance.Integer(0)) + ret, err := NumberLessThan(nil, nil, x, instance.NewInteger(0)) if err != nil { return nil, err } @@ -301,7 +301,7 @@ func Exp(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos.In if err != nil { return nil, err } - return instance.Float(math.Exp(f)), nil + return instance.NewFloat(math.Exp(f)), nil } // Log returns the natural logarithm of x. @@ -317,7 +317,7 @@ func Log(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos.In "EXPECTED-CLASS": class.Number, }) } - return instance.Float(math.Log(f)), nil + return instance.NewFloat(math.Log(f)), nil } // Expt returns x1 raised to the power x2. The result will be @@ -335,15 +335,15 @@ func Expt(_, _ *environment.Environment, x1, x2 ilos.Instance) (ilos.Instance, i return nil, err } if !af && !bf && b >= 0 { - return instance.Integer(int(math.Pow(a, b))), nil + return instance.NewInteger(int(math.Pow(a, b))), nil } if (a == 0 && b < 0) || (a == 0 && bf && b == 0) || (a < 0 && bf) { return nil, instance.New(class.ArithmeticError, map[string]ilos.Instance{ - "OPERATION": instance.Symbol("EXPT"), - "OPERANDS": instance.New(class.Cons, x1, instance.New(class.Cons, x2, Nil)), + "OPERATION": instance.NewSymbol("EXPT"), + "OPERANDS": instance.NewCons(x1, instance.NewCons(x2, Nil)), }) } - return instance.Float(math.Pow(a, b)), nil + return instance.NewFloat(math.Pow(a, b)), nil } // Sqrt returns the non-negative square root of x. An error shall be signaled @@ -360,13 +360,13 @@ func Sqrt(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos.I }) } if math.Ceil(math.Sqrt(a)) == math.Sqrt(a) { - return instance.Integer(int(math.Sqrt(a))), nil + return instance.NewInteger(int(math.Sqrt(a))), nil } - return instance.Float(math.Sqrt(a)), nil + return instance.NewFloat(math.Sqrt(a)), nil } // Pi is an approximation of π. -var Pi = instance.Float(3.141592653589793) +var Pi = instance.NewFloat(3.141592653589793) // Sin returns the sine of x . x must be given in radians. // An error shall be signaled if x is not a number (error-id. domain-error). @@ -375,7 +375,7 @@ func Sin(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos.In if err != nil { return nil, err } - return instance.Float(math.Sin(a)), nil + return instance.NewFloat(math.Sin(a)), nil } // Cos returns the cosine of x . x must be given in radians. @@ -385,7 +385,7 @@ func Cos(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos.In if err != nil { return nil, err } - return instance.Float(math.Cos(a)), nil + return instance.NewFloat(math.Cos(a)), nil } // Tan returns the tangent of x . x must be given in radians. @@ -395,7 +395,7 @@ func Tan(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos.In if err != nil { return nil, err } - return instance.Float(math.Tan(a)), nil + return instance.NewFloat(math.Tan(a)), nil } // Atan returns the arc tangent of x. @@ -406,7 +406,7 @@ func Atan(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos.I if err != nil { return nil, err } - return instance.Float(math.Atan(a)), nil + return instance.NewFloat(math.Atan(a)), nil } // Atan2 returns the phase of its representation in polar coordinates. @@ -429,11 +429,11 @@ func Atan2(_, _ *environment.Environment, x1, x2 ilos.Instance) (ilos.Instance, } if a == 0 && b == 0 { return nil, instance.New(class.ArithmeticError, map[string]ilos.Instance{ - "OPERATION": instance.Symbol("ATAN2"), - "OPERANDS": instance.New(class.Cons, x1, instance.New(class.Cons, x2, Nil)), + "OPERATION": instance.NewSymbol("ATAN2"), + "OPERANDS": instance.NewCons(x1, instance.NewCons(x2, Nil)), }) } - return instance.Float(math.Atan2(a, b)), nil + return instance.NewFloat(math.Atan2(a, b)), nil } // Sinh returns the hyperbolic sine of x . x must be given in radians. @@ -443,7 +443,7 @@ func Sinh(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos.I if err != nil { return nil, err } - return instance.Float(math.Sinh(a)), nil + return instance.NewFloat(math.Sinh(a)), nil } // Cosh returns the hyperbolic cosine of x . x must be given in radians. @@ -453,7 +453,7 @@ func Cosh(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos.I if err != nil { return nil, err } - return instance.Float(math.Cosh(a)), nil + return instance.NewFloat(math.Cosh(a)), nil } // Tanh returns the hyperbolic tangent of x . x must be given in radians. @@ -463,7 +463,7 @@ func Tanh(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos.I if err != nil { return nil, err } - return instance.Float(math.Tanh(a)), nil + return instance.NewFloat(math.Tanh(a)), nil } // Atanh returns the hyperbolic arc tangent of x. @@ -479,5 +479,5 @@ func Atanh(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos. "EXPECTED-CLASS": class.Number, }) } - return instance.Float(math.Atanh(a)), nil + return instance.NewFloat(math.Atanh(a)), nil } diff --git a/runtime/sequence_functions.go b/runtime/sequence_functions.go index c3f55f9..f00610a 100644 --- a/runtime/sequence_functions.go +++ b/runtime/sequence_functions.go @@ -27,11 +27,11 @@ import ( func Length(_, _ *environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { switch { case instance.Of(class.String, obj): - return instance.Integer(len(obj.(instance.String))), nil + return instance.NewInteger(len(obj.(instance.String))), nil case instance.Of(class.GeneralVector, obj): - return instance.Integer(len(obj.(instance.GeneralVector))), nil + return instance.NewInteger(len(obj.(instance.GeneralVector))), nil case instance.Of(class.List, obj): - return instance.Integer(len(obj.(instance.List).Slice())), nil + return instance.NewInteger(len(obj.(instance.List).Slice())), nil } // TODO: class.Seq return nil, instance.New(class.DomainError, map[string]ilos.Instance{ @@ -56,21 +56,21 @@ func Elt(_, _ *environment.Environment, sequence, z ilos.Instance) (ilos.Instanc seq := sequence.(instance.String) idx := int(z.(instance.Integer)) if idx > 0 && len(seq) <= idx { - return ProgramError("INDEX-OUT-OF-RANGE") + return nil, instance.NewIndexOutOfRange() } - return instance.Character(seq[idx]), nil + return instance.NewCharacter(seq[idx]), nil case instance.Of(class.GeneralVector, sequence): seq := sequence.(instance.GeneralVector) idx := int(z.(instance.Integer)) if idx > 0 && len(seq) <= idx { - return ProgramError("INDEX-OUT-OF-RANGE") + return nil, instance.NewIndexOutOfRange() } return seq[idx], nil case instance.Of(class.List, sequence): seq := sequence.(instance.List).Slice() idx := int(z.(instance.Integer)) if idx > 0 && len(seq) <= idx { - return ProgramError("INDEX-OUT-OF-RANGE") + return nil, instance.NewIndexOutOfRange() } return seq[idx], nil } @@ -94,7 +94,7 @@ func SetElt(_, _ *environment.Environment, obj, sequence, z ilos.Instance) (ilos seq := sequence.(instance.String) idx := int(z.(instance.Integer)) if idx > 0 && len(seq) <= idx { - return ProgramError("INDEX-OUT-OF-RANGE") + return nil, instance.NewIndexOutOfRange() } if err := ensure(class.Character, obj); err != nil { return nil, err @@ -105,7 +105,7 @@ func SetElt(_, _ *environment.Environment, obj, sequence, z ilos.Instance) (ilos seq := sequence.(instance.GeneralVector) idx := int(z.(instance.Integer)) if idx > 0 && len(seq) <= idx { - return ProgramError("INDEX-OUT-OF-RANGE") + return nil, instance.NewIndexOutOfRange() } seq[idx] = obj return obj, nil @@ -113,7 +113,7 @@ func SetElt(_, _ *environment.Environment, obj, sequence, z ilos.Instance) (ilos seq := sequence.(instance.List).Slice() idx := int(z.(instance.Integer)) if idx > 0 && len(seq) <= idx { - return ProgramError("INDEX-OUT-OF-RANGE") + return nil, instance.NewIndexOutOfRange() } for idx != 0 && instance.Of(class.Cons, sequence) { idx-- @@ -148,19 +148,19 @@ func Subseq(_, _ *environment.Environment, sequence, z1, z2 ilos.Instance) (ilos case instance.Of(class.String, sequence): seq := sequence.(instance.String) if !(0 <= start && start < len(seq) && 0 <= end && end < len(seq) && start <= end) { - return ProgramError("INDEX-OUT-OF-RANGE") + return nil, instance.NewIndexOutOfRange() } return seq[start:end], nil case instance.Of(class.GeneralVector, sequence): seq := sequence.(instance.GeneralVector) if !(0 <= start && start < len(seq) && 0 <= end && end < len(seq) && start <= end) { - return ProgramError("INDEX-OUT-OF-RANGE") + return nil, instance.NewIndexOutOfRange() } return seq[start:end], nil case instance.Of(class.List, sequence): seq := sequence.(instance.List).Slice() if !(0 < start && start < len(seq) && 0 < end && end < len(seq) && start <= end) { - return ProgramError("INDEX-OUT-OF-RANGE") + return nil, instance.NewIndexOutOfRange() } return List(nil, nil, seq[start:end]...) } @@ -210,7 +210,7 @@ func mapInto(local, global *environment.Environment, destination, function ilos. arguments := make([]ilos.Instance, int(max)) for _, seq := range sequences { var err ilos.Instance - arguments[i], err = Elt(nil, nil, seq, instance.Integer(i)) + arguments[i], err = Elt(nil, nil, seq, instance.NewInteger(i)) if err != nil { return nil, err } @@ -219,7 +219,7 @@ func mapInto(local, global *environment.Environment, destination, function ilos. if err != nil { return nil, err } - _, err = SetElt(nil, nil, ret, destination, instance.Integer(i)) + _, err = SetElt(nil, nil, ret, destination, instance.NewInteger(i)) if err != nil { return nil, err } diff --git a/runtime/string_class.go b/runtime/string_class.go index 85b1dbd..7f1b257 100644 --- a/runtime/string_class.go +++ b/runtime/string_class.go @@ -34,7 +34,7 @@ func CreateString(_, _ *environment.Environment, i ilos.Instance, initialElement }) } if len(initialElement) > 1 { - return ProgramError("ARITY-ERROR") + return nil, instance.NewArityError() } n := int(i.(instance.Integer)) v := make([]ilos.Instance, n) @@ -130,7 +130,7 @@ func CharIndex(_, _ *environment.Environment, char, str ilos.Instance, startPosi return nil, err } if len(startPosition) > 1 { - return ProgramError("ARITY-ERROR") + return nil, instance.NewArityError() } n := 0 if len(startPosition) == 1 { @@ -145,7 +145,7 @@ func CharIndex(_, _ *environment.Environment, char, str ilos.Instance, startPosi if i < 0 { return Nil, nil } - return instance.Integer(i), nil + return instance.NewInteger(i), nil } // StringIndex returns the position of the given substring within string. The search starts @@ -163,7 +163,7 @@ func StringIndex(_, _ *environment.Environment, sub, str ilos.Instance, startPos return nil, err } if len(startPosition) > 1 { - return ProgramError("ARITY-ERROR") + return nil, instance.NewArityError() } n := 0 if len(startPosition) == 1 { @@ -178,7 +178,7 @@ func StringIndex(_, _ *environment.Environment, sub, str ilos.Instance, startPos if i < 0 { return Nil, nil } - return instance.Integer(i), nil + return instance.NewInteger(i), nil } // StringAppend returns a single string containing a sequence of characters that results @@ -197,5 +197,5 @@ func StringAppend(_, _ *environment.Environment, str ...ilos.Instance) (ilos.Ins } ret += string(s.(instance.String)) } - return instance.String(ret), nil + return instance.NewString(ret), nil } diff --git a/runtime/symbol_class.go b/runtime/symbol_class.go index f6809b5..52d5218 100644 --- a/runtime/symbol_class.go +++ b/runtime/symbol_class.go @@ -35,7 +35,7 @@ func Property(local, global *environment.Environment, symbol, propertyName ilos. return nil, err } if len(obj) > 1 { - return ProgramError("ARITY-ERROR") + return nil, instance.NewArityError() } ret, ok := global.Property.Get(symbol, propertyName) if ok { @@ -79,5 +79,5 @@ func RemoveProperty(local, global *environment.Environment, symbol, propertyName // It is impossible for an identifier to name an unnamed symbol. func Gensym(local, global *environment.Environment) (ilos.Instance, ilos.Instance) { global.GensymID++ - return instance.Symbol(fmt.Sprintf("IRIS:G#%v", global.GensymID)), nil + return instance.NewSymbol(fmt.Sprintf("IRIS:G#%v", global.GensymID)), nil } diff --git a/runtime/util.go b/runtime/util.go index fcde475..3527e66 100644 --- a/runtime/util.go +++ b/runtime/util.go @@ -57,31 +57,31 @@ func defspecial(function interface{}) { name = regexp.MustCompile(`.*\.`).ReplaceAllString(name, "") name = regexp.MustCompile(`(.)([A-Z])`).ReplaceAllString(name, "$1-$2") name = strings.ToUpper(name) - symbol := instance.Symbol(name) - environment.TopLevel.Special.Define(symbol, instance.New(class.Function, symbol, function)) + symbol := instance.NewSymbol(name) + environment.TopLevel.Special.Define(symbol, instance.NewFunction(symbol, function)) } func defmacro(function interface{}) { name := runtime.FuncForPC(reflect.ValueOf(function).Pointer()).Name() name = regexp.MustCompile(`.*\.`).ReplaceAllString(name, "") name = regexp.MustCompile(`(.)([A-Z])`).ReplaceAllString(name, "$1-$2") name = strings.ToUpper(name) - symbol := instance.Symbol(name) - environment.TopLevel.Macro.Define(symbol, instance.New(class.Function, symbol, function)) + symbol := instance.NewSymbol(name) + environment.TopLevel.Macro.Define(symbol, instance.NewFunction(symbol, function)) } func defun(function interface{}) { name := runtime.FuncForPC(reflect.ValueOf(function).Pointer()).Name() name = regexp.MustCompile(`.*\.`).ReplaceAllString(name, "") name = regexp.MustCompile(`(.)([A-Z])`).ReplaceAllString(name, "$1-$2") name = strings.ToUpper(name) - symbol := instance.Symbol(name) - environment.TopLevel.Function.Define(symbol, instance.New(class.Function, symbol, function)) + symbol := instance.NewSymbol(name) + environment.TopLevel.Function.Define(symbol, instance.NewFunction(symbol, function)) } func defun2(name string, function interface{}) { - symbol := instance.Symbol(name) - environment.TopLevel.Function.Define(symbol, instance.New(class.Function, symbol, function)) + symbol := instance.NewSymbol(name) + environment.TopLevel.Function.Define(symbol, instance.NewFunction(symbol, function)) } func defglobal(name string, value ilos.Instance) { - symbol := instance.Symbol(name) + symbol := instance.NewSymbol(name) environment.TopLevel.Variable.Define(symbol, value) } func ensure(c ilos.Class, i ...ilos.Instance) ilos.Instance { @@ -104,6 +104,6 @@ func ProgramError(cause string) (ilos.Instance, ilos.Instance) { name = regexp.MustCompile(`(.)([A-Z])`).ReplaceAllString(name, "$1-$2") name = strings.ToUpper(name) return nil, instance.New(class.ProgramError, map[string]ilos.Instance{ - "CAUSE": instance.String(cause + fmt.Sprintf(" in %v", name)), + "CAUSE": instance.NewString(cause + fmt.Sprintf(" in %v", name)), }) } diff --git a/runtime/variables.go b/runtime/variables.go index 8cc8125..c42cccb 100644 --- a/runtime/variables.go +++ b/runtime/variables.go @@ -32,7 +32,7 @@ func Setq(local, global *environment.Environment, var1, form ilos.Instance) (ilo } return nil, instance.New(class.UndefinedVariable, map[string]ilos.Instance{ "NAME": var1, - "NAMESPACE": instance.Symbol("VARIABLE"), + "NAMESPACE": instance.NewSymbol("VARIABLE"), }) } @@ -61,7 +61,7 @@ func Let(local, global *environment.Environment, varForm ilos.Instance, bodyForm } s := cadr.(instance.List).Slice() if len(s) != 2 { - return ProgramError("ARITY-ERROR") + return nil, instance.NewArityError() } f, err := Eval(local, global, s[1]) if err != nil { @@ -71,7 +71,7 @@ func Let(local, global *environment.Environment, varForm ilos.Instance, bodyForm } for v, f := range vfs { if !local.Variable.Define(v, f) { - return ProgramError("IMMUTABLE-BINDING") + return nil, instance.NewImmutableBinding() } } return Progn(local, global, bodyForm...) @@ -101,14 +101,14 @@ func LetStar(local, global *environment.Environment, varForm ilos.Instance, body } s := cadr.(instance.List).Slice() if len(s) != 2 { - return ProgramError("ARITY-ERROR") + return nil, instance.NewArityError() } f, err := Eval(local, global, s[1]) if err != nil { return nil, err } if !local.Variable.Define(s[0], f) { - return ProgramError("IMMUTABLE-BINDING") + return nil, instance.NewImmutableBinding() } } return Progn(local, global, bodyForm...) diff --git a/runtime/vectors.go b/runtime/vectors.go index 99934d4..717ae3d 100644 --- a/runtime/vectors.go +++ b/runtime/vectors.go @@ -43,7 +43,7 @@ func CreateVector(_, _ *environment.Environment, i ilos.Instance, initialElement }) } if len(initialElement) > 1 { - return ProgramError("ARITY-ERROR") + return nil, instance.NewArityError() } n := int(i.(instance.Integer)) v := make([]ilos.Instance, n) From de5d0fdc7b1344f4e2d2a9801a20d818023b2a0a Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Tue, 15 Aug 2017 21:23:50 +0900 Subject: [PATCH 180/228] Adds constructors --- reader/parser/parser.go | 7 ++--- reader/tokenizer/tokenizer.go | 2 +- runtime/dynamic_variables.go | 10 ++---- runtime/eval.go | 19 +++-------- runtime/functions.go | 5 +-- runtime/ilos/instance/error.go | 20 +++++++++++- runtime/ilos/instance/function.go | 4 +-- runtime/ilos/instance/tag.go | 28 +++++++++++++++++ runtime/integer_class.go | 25 ++++++++------- runtime/iteration.go | 2 +- runtime/non-local_exits.go | 52 +++++++++---------------------- runtime/number_class.go | 45 ++++++++++---------------- runtime/sequence_functions.go | 35 +++++++-------------- runtime/string_class.go | 5 +-- runtime/util.go | 23 ++------------ runtime/variables.go | 5 +-- runtime/vectors.go | 5 +-- 17 files changed, 121 insertions(+), 171 deletions(-) create mode 100644 runtime/ilos/instance/tag.go diff --git a/reader/parser/parser.go b/reader/parser/parser.go index 507bfbf..acfdc8b 100644 --- a/reader/parser/parser.go +++ b/reader/parser/parser.go @@ -84,10 +84,7 @@ func ParseAtom(tok string) (ilos.Instance, ilos.Instance) { if m, _ := regexp.MatchString(str, tok); m { return instance.NewSymbol(strings.ToUpper(tok)), nil } - return nil, instance.New(class.ParseError, map[string]ilos.Instance{ - "STRING": instance.NewString(tok), - "EXPECTED-CLASS": class.Object, - }) + return nil, instance.NewParseError(instance.NewString(tok), class.Object) } func parseMacro(tok string, t *tokenizer.Tokenizer) (ilos.Instance, ilos.Instance) { @@ -105,7 +102,7 @@ func parseMacro(tok string, t *tokenizer.Tokenizer) (ilos.Instance, ilos.Instanc } v, err := strconv.ParseInt(tok[1:i], 10, 32) if err != nil { - return nil, instance.New(class.ParseError, instance.NewString(tok), class.Integer) + return nil, instance.NewParseError(instance.NewString(tok), class.Integer) } d := instance.NewInteger(int(v)) return instance.NewCons(s, instance.NewCons(d, instance.NewCons(cdr, instance.NewNull()))), nil diff --git a/reader/tokenizer/tokenizer.go b/reader/tokenizer/tokenizer.go index 7336e2c..a75e939 100644 --- a/reader/tokenizer/tokenizer.go +++ b/reader/tokenizer/tokenizer.go @@ -50,7 +50,7 @@ func (t *Tokenizer) Next() (string, ilos.Instance) { if t.sc.Scan() { return t.sc.Text(), nil } - return "", instance.New(class.ParseError, instance.NewString(t.sc.Text()), class.Object) + return "", instance.NewParseError(instance.NewString(t.sc.Text()), class.Object) } func splitter(data []byte, atEOF bool) (advance int, token []byte, err error) { diff --git a/runtime/dynamic_variables.go b/runtime/dynamic_variables.go index 24052d2..72d423e 100644 --- a/runtime/dynamic_variables.go +++ b/runtime/dynamic_variables.go @@ -31,10 +31,7 @@ func Dynamic(local, global *environment.Environment, var1 ilos.Instance) (ilos.I if v, ok := global.DynamicVariable.Get(var1); ok { return v, nil } - return nil, instance.New(class.UndefinedVariable, map[string]ilos.Instance{ - "NAME": var1, - "NAMESPACE": instance.NewSymbol("Variable"), - }) + return nil, instance.NewUndefinedVariable(var1) } // SetDynamic denotes an assignment to a dynamic variable. This @@ -60,10 +57,7 @@ func SetDynamic(local, global *environment.Environment, form, var1 ilos.Instance if global.DynamicVariable.Set(var1, form) { return form, nil } - return nil, instance.New(class.UndefinedFunction, map[string]ilos.Instance{ - "NAME": var1, - "NAMESPACE": instance.NewSymbol("FUNCTION"), - }) + return nil, instance.NewUndefinedVariable(var1) } // DyamicLet is used to establish dynamic variable bindings. diff --git a/runtime/eval.go b/runtime/eval.go index 6f97ae0..a13d709 100644 --- a/runtime/eval.go +++ b/runtime/eval.go @@ -130,12 +130,8 @@ func evalFunction(local, global *environment.Environment, car, cdr ilos.Instance } func evalCons(local, global *environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { - // obj, function call form, must be a instance of Cons, NOT Null, and ends with nil - if !isProperList(obj) || obj == Nil { - return nil, instance.New(class.ParseError, map[string]ilos.Instance{ - "STRING": obj, - "EXPECTED-CLASS": class.Cons, - }) + if err := ensure(class.Cons, obj); err != nil { + return nil, err } car := obj.(*instance.Cons).Car // Checked at the top of// This function cdr := obj.(*instance.Cons).Cdr // Checked at the top of// This function @@ -156,11 +152,7 @@ func evalCons(local, global *environment.Environment, obj ilos.Instance) (ilos.I if a, b, c := evalFunction(local, global, car, cdr); c { return a, b } - - return nil, instance.New(class.UndefinedFunction, map[string]ilos.Instance{ - "NAME": car, - "NAMESPACE": instance.NewSymbol("FUNCTION"), - }) + return nil, instance.NewUndefinedFunction(car) } func evalVariable(local, global *environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { @@ -173,10 +165,7 @@ func evalVariable(local, global *environment.Environment, obj ilos.Instance) (il if val, ok := global.Constant.Get(obj); ok { return val, nil } - return nil, instance.New(class.UndefinedVariable, map[string]ilos.Instance{ - "NAME": obj, - "NAMESPACE": instance.NewSymbol("VARIABLE"), - }) + return nil, instance.NewUndefinedVariable(obj) } // Eval evaluates any classs diff --git a/runtime/functions.go b/runtime/functions.go index d7d1166..01b5876 100644 --- a/runtime/functions.go +++ b/runtime/functions.go @@ -42,10 +42,7 @@ func Function(local, global *environment.Environment, fun ilos.Instance) (ilos.I if f, ok := global.Function.Get(fun); ok { return f, nil } - return nil, instance.New(class.UndefinedFunction, map[string]ilos.Instance{ - "NAME": fun, - "NAMESPACE": instance.NewSymbol("FUNCTION"), - }) + return nil, instance.NewUndefinedFunction(fun) } // Lambda special form creates a function object. diff --git a/runtime/ilos/instance/error.go b/runtime/ilos/instance/error.go index e147d97..37da2b9 100644 --- a/runtime/ilos/instance/error.go +++ b/runtime/ilos/instance/error.go @@ -16,6 +16,13 @@ func NewArithmeticError(operation, operands ilos.Instance) ilos.Instance { }) } +func NewDivisionByZero(operation, operands ilos.Instance) ilos.Instance { + return New(class.DivisionByZero, map[string]ilos.Instance{ + "OPERATION": operation, + "OPERANDS": operands, + }) +} + func NewParseError(str, expectedClass ilos.Instance) ilos.Instance { return New(class.ParseError, map[string]ilos.Instance{ "STRING": str, @@ -23,7 +30,7 @@ func NewParseError(str, expectedClass ilos.Instance) ilos.Instance { }) } -func NewDomainError(object, expectedClass ilos.Instance) ilos.Instance { +func NewDomainError(object ilos.Instance, expectedClass ilos.Class) ilos.Instance { return New(class.DomainError, map[string]ilos.Instance{"CAUSE": Symbol("DOMAIN-ERROR"), "OBJECT": object, "EXPECTED-CLASSS": expectedClass, @@ -55,3 +62,14 @@ func NewIndexOutOfRange() ilos.Instance { func NewImmutableBinding() ilos.Instance { return New(class.ProgramError, map[string]ilos.Instance{}) } + +func NewSimpleError(formatString, formatArguments ilos.Instance) ilos.Instance { + return New(class.SimpleError, map[string]ilos.Instance{ + "FORMAT-STRING": formatString, + "FORMAT-ARGUMENTS": formatArguments, + }) +} + +func NewControlError() ilos.Instance { + return New(class.ControlError) +} diff --git a/runtime/ilos/instance/function.go b/runtime/ilos/instance/function.go index 3973a18..06e175e 100644 --- a/runtime/ilos/instance/function.go +++ b/runtime/ilos/instance/function.go @@ -50,9 +50,7 @@ func (f Function) Apply(local, global *environment.Environment, arguments ...ilo argv = append(argv, reflect.ValueOf(cadr)) } if ft.NumIn() != len(argv) && (!ft.IsVariadic() || ft.NumIn()-2 >= len(argv)) { - return nil, New(class.ProgramError, map[string]ilos.Instance{ - "CAUSE": New(class.String, fmt.Sprintf("ARITY-ERROR in %v", f.name)), - }) + return nil, NewArityError() } rets := fv.Call(argv) a, _ := rets[0].Interface().(ilos.Instance) diff --git a/runtime/ilos/instance/tag.go b/runtime/ilos/instance/tag.go new file mode 100644 index 0000000..47262dd --- /dev/null +++ b/runtime/ilos/instance/tag.go @@ -0,0 +1,28 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package instance + +import ( + "github.com/ta2gch/iris/runtime/ilos" + "github.com/ta2gch/iris/runtime/ilos/class" +) + +func NewBlockTag(tag, object ilos.Instance) ilos.Instance { + return New(class.BlockTag, map[string]ilos.Instance{ + "TAG": tag, + "OBJECT": object, + }) +} +func NewCatchTag(tag, object ilos.Instance) ilos.Instance { + return New(class.CatchTag, map[string]ilos.Instance{ + "TAG": tag, + "OBJECT": object, + }) +} +func NewTagbodyTag(tag ilos.Instance) ilos.Instance { + return New(class.TagbodyTag, map[string]ilos.Instance{ + "TAG": tag, + }) +} diff --git a/runtime/integer_class.go b/runtime/integer_class.go index ce19d71..62ee235 100644 --- a/runtime/integer_class.go +++ b/runtime/integer_class.go @@ -41,10 +41,12 @@ func Div(_, _ *environment.Environment, z1, z2 ilos.Instance) (ilos.Instance, il return nil, err } if b == 0 { - return nil, instance.New(class.DivisionByZero, map[string]ilos.Instance{ - "OPERATION": instance.NewSymbol("DIV"), - "OPERANDS": instance.NewCons(z1, instance.NewCons(z2, Nil)), - }) + operation := instance.NewSymbol("DIV") + operands, err := List(nil, nil, z1, z2) + if err != nil { + return nil, err + } + return nil, instance.NewDivisionByZero(operation, operands) } return instance.NewInteger(a / b), nil } @@ -65,10 +67,12 @@ func Mod(_, _ *environment.Environment, z1, z2 ilos.Instance) (ilos.Instance, il return nil, err } if b == 0 { - return nil, instance.New(class.DivisionByZero, map[string]ilos.Instance{ - "OPERATION": instance.NewSymbol("MOD"), - "OPERANDS": instance.NewCons(z1, instance.NewCons(z2, Nil)), - }) + operation := instance.NewSymbol("MOD") + operands, err := List(nil, nil, z1, z2) + if err != nil { + return nil, err + } + return nil, instance.NewDivisionByZero(operation, operands) } return instance.NewInteger(a % b), nil } @@ -129,10 +133,7 @@ func Isqrt(_, _ *environment.Environment, z ilos.Instance) (ilos.Instance, ilos. return nil, err } if a < 0 { - return nil, instance.New(class.DomainError, map[string]ilos.Instance{ - "OBJECT": z, - "EXPECTED-CLASS": class.Number, - }) + return nil, instance.NewDomainError(z, class.Number) } return instance.NewInteger(int(math.Sqrt(float64(a)))), nil } diff --git a/runtime/iteration.go b/runtime/iteration.go index a31ec66..b21996b 100644 --- a/runtime/iteration.go +++ b/runtime/iteration.go @@ -80,7 +80,7 @@ func For(local, global *environment.Environment, iterationSpecs, endTestAndResul } ends := endTestAndResults.(instance.List).Slice() if len(ends) == 0 { - return nil, instance.New(class.ParseError) + return nil, instance.NewArityError() } endTest := ends[0] results := ends[1:] diff --git a/runtime/non-local_exits.go b/runtime/non-local_exits.go index 53f0b4c..fcdfbde 100644 --- a/runtime/non-local_exits.go +++ b/runtime/non-local_exits.go @@ -45,10 +45,7 @@ func Block(local, global *environment.Environment, tag ilos.Instance, body ...il return nil, err } if instance.Of(class.Number, tag) || instance.Of(class.Character, tag) { - return nil, instance.New(class.DomainError, map[string]ilos.Instance{ - "OBJECT": tag, - "EXPECTED-CLASS": class.Object, - }) + return nil, instance.NewDomainError(tag, class.Object) } if !local.BlockTag.Define(tag, nil) { return nil, instance.NewImmutableBinding() @@ -78,25 +75,16 @@ func ReturnFrom(local, global *environment.Environment, tag, object ilos.Instanc return nil, err } if instance.Of(class.Number, tag) || instance.Of(class.Character, tag) { - return nil, instance.New(class.DomainError, map[string]ilos.Instance{ - "OBJECT": tag, - "EXPECTED-CLASS": class.Object, - }) + return nil, instance.NewDomainError(tag, class.Object) } object, err = Eval(local, global, object) if err != nil { return nil, err } if _, ok := local.BlockTag.Get(tag); !ok { - return nil, instance.New(class.SimpleError, map[string]ilos.Instance{ - "FORMAT-STRING": instance.NewString("%v is not defined as the tag"), - "FORMAT-ARGUMENTS": tag, - }) - } - return nil, instance.New(class.BlockTag, map[string]ilos.Instance{ - "TAG": tag, - "OBJECT": object, - }) + return nil, instance.NewSimpleError(instance.NewString("%v is not defined as the tag"), tag) + } + return nil, instance.NewBlockTag(tag, object) } func Catch(local, global *environment.Environment, tag ilos.Instance, body ...ilos.Instance) (ilos.Instance, ilos.Instance) { @@ -106,7 +94,7 @@ func Catch(local, global *environment.Environment, tag ilos.Instance, body ...il return nil, err } if instance.Of(class.Number, tag) || instance.Of(class.Character, tag) { - return nil, instance.New(class.DomainError, tag, class.Object) + return nil, instance.NewDomainError(tag, class.Object) } if !local.CatchTag.Define(tag, nil) { return nil, instance.NewImmutableBinding() @@ -136,25 +124,17 @@ func Throw(local, global *environment.Environment, tag, object ilos.Instance) (i return nil, err } if instance.Of(class.Number, tag) || instance.Of(class.Character, tag) { - return nil, instance.New(class.DomainError, map[string]ilos.Instance{ - "OBJECT": tag, - "EXPECTED-CLASS": class.Object, - }) + return nil, instance.NewDomainError(tag, class.Object) } object, err = Eval(local, global, object) if err != nil { return nil, err } if _, ok := local.CatchTag.Get(tag); !ok { - return nil, instance.New(class.SimpleError, map[string]ilos.Instance{ - "FORMAT-STRING": instance.NewString("%v is not defined as the tag"), - "FORMAT-ARGUMENTS": tag, - }) - } - return nil, instance.New(class.CatchTag, map[string]ilos.Instance{ - "TAG": tag, - "OBJECT": object, - }) + return nil, instance.NewSimpleError(instance.NewString("%v is not defined as the tag"), tag) + + } + return nil, instance.NewCatchTag(tag, object) } func Tagbody(local, global *environment.Environment, body ...ilos.Instance) (ilos.Instance, ilos.Instance) { @@ -203,12 +183,10 @@ func Tagbody(local, global *environment.Environment, body ...ilos.Instance) (ilo func Go(local, global *environment.Environment, tag ilos.Instance) (ilos.Instance, ilos.Instance) { if _, ok := local.TagbodyTag.Get(tag); !ok { - return nil, instance.New(class.SimpleError, map[string]ilos.Instance{ - "FORMAT-STRING": instance.NewString("%v is not defined as the tag"), - "FORMAT-ARGUMENTS": tag, - }) + return nil, instance.NewSimpleError(instance.NewString("%v is not defined as the tag"), tag) + } - return nil, instance.New(class.TagbodyTag, map[string]ilos.Instance{"TAG": tag}) + return nil, instance.NewTagbodyTag(tag) } // UnwindProtect first evaluates form. Evaluation of the cleanup-forms always @@ -243,7 +221,7 @@ func UnwindProtect(local, global *environment.Environment, form ilos.Instance, c ret1, err1 := Eval(local, global, form) ret2, err2 := Progn(local, global, cleanupForms...) if instance.Of(class.Escape, err2) { - return nil, instance.New(class.ControlError) + return nil, instance.NewControlError() } if err2 != nil { return ret2, err2 diff --git a/runtime/number_class.go b/runtime/number_class.go index 383074b..96c06d0 100644 --- a/runtime/number_class.go +++ b/runtime/number_class.go @@ -35,10 +35,7 @@ func ParseNumber(_, _ *environment.Environment, str ilos.Instance) (ilos.Instanc } ret, err := parser.ParseAtom(string(str.(instance.String))) if err != nil || !instance.Of(class.Number, ret) { - return nil, instance.New(class.ParseError, map[string]ilos.Instance{ - "STRING": str, - "EXPECTED-CLASS": class.Number, - }) + return nil, instance.NewParseError(str, class.Number) } return ret, err } @@ -227,10 +224,7 @@ func Quotient(_, _ *environment.Environment, dividend, divisor1 ilos.Instance, d for i := len(divisor) - 1; i >= 0; i-- { arguments = instance.NewCons(divisor[i], arguments) } - return nil, instance.New(class.DivisionByZero, map[string]ilos.Instance{ - "OPERATION": instance.NewSymbol("QUOTIENT"), - "OPERANDS": arguments, - }) + return nil, instance.NewDivisionByZero(instance.NewSymbol("QUOTIENT"), arguments) } if !flt && !b && int(quotient)%int(f) != 0 { flt = true @@ -312,10 +306,7 @@ func Log(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos.In return nil, err } if f <= 0.0 { - return nil, instance.New(class.DomainError, map[string]ilos.Instance{ - "OBJECT": x, - "EXPECTED-CLASS": class.Number, - }) + return nil, instance.NewDomainError(x, class.Number) } return instance.NewFloat(math.Log(f)), nil } @@ -338,10 +329,12 @@ func Expt(_, _ *environment.Environment, x1, x2 ilos.Instance) (ilos.Instance, i return instance.NewInteger(int(math.Pow(a, b))), nil } if (a == 0 && b < 0) || (a == 0 && bf && b == 0) || (a < 0 && bf) { - return nil, instance.New(class.ArithmeticError, map[string]ilos.Instance{ - "OPERATION": instance.NewSymbol("EXPT"), - "OPERANDS": instance.NewCons(x1, instance.NewCons(x2, Nil)), - }) + operation := instance.NewSymbol("EXPT") + operands, err := List(nil, nil, x1, x2) + if err != nil { + return nil, err + } + return nil, instance.NewArithmeticError(operation, operands) } return instance.NewFloat(math.Pow(a, b)), nil } @@ -354,10 +347,7 @@ func Sqrt(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos.I return nil, err } if a < 0.0 { - return nil, instance.New(class.DomainError, map[string]ilos.Instance{ - "OBJECT": x, - "EXPECTED-CLASS": class.Number, - }) + return nil, instance.NewDomainError(x, class.Number) } if math.Ceil(math.Sqrt(a)) == math.Sqrt(a) { return instance.NewInteger(int(math.Sqrt(a))), nil @@ -428,10 +418,12 @@ func Atan2(_, _ *environment.Environment, x1, x2 ilos.Instance) (ilos.Instance, return nil, err } if a == 0 && b == 0 { - return nil, instance.New(class.ArithmeticError, map[string]ilos.Instance{ - "OPERATION": instance.NewSymbol("ATAN2"), - "OPERANDS": instance.NewCons(x1, instance.NewCons(x2, Nil)), - }) + operation := instance.NewSymbol("ATAN2") + operands, err := List(nil, nil, x1, x2) + if err != nil { + return nil, err + } + return nil, instance.NewArithmeticError(operation, operands) } return instance.NewFloat(math.Atan2(a, b)), nil } @@ -474,10 +466,7 @@ func Atanh(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos. return nil, err } if math.Abs(a) >= 1 { - return nil, instance.New(class.DomainError, map[string]ilos.Instance{ - "OBJECT": x, - "EXPECTED-CLASS": class.Number, - }) + instance.NewDomainError(x, class.Number) } return instance.NewFloat(math.Atanh(a)), nil } diff --git a/runtime/sequence_functions.go b/runtime/sequence_functions.go index f00610a..1f745fe 100644 --- a/runtime/sequence_functions.go +++ b/runtime/sequence_functions.go @@ -24,20 +24,17 @@ import ( // // An error shall be signaled if sequence is not a basic-vector or a list // (error-id. domain-error). -func Length(_, _ *environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { +func Length(_, _ *environment.Environment, sequence ilos.Instance) (ilos.Instance, ilos.Instance) { switch { - case instance.Of(class.String, obj): - return instance.NewInteger(len(obj.(instance.String))), nil - case instance.Of(class.GeneralVector, obj): - return instance.NewInteger(len(obj.(instance.GeneralVector))), nil - case instance.Of(class.List, obj): - return instance.NewInteger(len(obj.(instance.List).Slice())), nil + case instance.Of(class.String, sequence): + return instance.NewInteger(len(sequence.(instance.String))), nil + case instance.Of(class.GeneralVector, sequence): + return instance.NewInteger(len(sequence.(instance.GeneralVector))), nil + case instance.Of(class.List, sequence): + return instance.NewInteger(len(sequence.(instance.List).Slice())), nil } // TODO: class.Seq - return nil, instance.New(class.DomainError, map[string]ilos.Instance{ - "OBJECT": obj, - "EXPECTED-CLASS": class.Object, - }) + return nil, instance.NewDomainError(sequence, class.Object) } // Elt returns the element of sequence that has index z. Indexing is 0-based; i.e., z = 0 @@ -74,10 +71,8 @@ func Elt(_, _ *environment.Environment, sequence, z ilos.Instance) (ilos.Instanc } return seq[idx], nil } - return nil, instance.New(class.DomainError, map[string]ilos.Instance{ - "OBJECT": sequence, - "EXPECTED-CLASS": class.Object, - }) + return nil, instance.NewDomainError(sequence, class.Object) + } // SetElt is that these replace the object obtainable by elt with obj. The returned value is obj. @@ -122,10 +117,7 @@ func SetElt(_, _ *environment.Environment, obj, sequence, z ilos.Instance) (ilos sequence.(*instance.Cons).Car = obj return obj, nil } - return nil, instance.New(class.DomainError, map[string]ilos.Instance{ - "OBJECT": sequence, - "EXPECTED-CLASS": class.Object, - }) + return nil, instance.NewDomainError(sequence, class.Object) } // Subseq returns the subsequence of length z2 − z1, containing the elements with indices from @@ -164,10 +156,7 @@ func Subseq(_, _ *environment.Environment, sequence, z1, z2 ilos.Instance) (ilos } return List(nil, nil, seq[start:end]...) } - return nil, instance.New(class.DomainError, map[string]ilos.Instance{ - "OBJECT": sequence, - "EXPECTED-CLASS": class.Object, - }) + return nil, instance.NewDomainError(sequence, class.Object) } // Destructively modifies destination to contain the results of applying function to diff --git a/runtime/string_class.go b/runtime/string_class.go index 7f1b257..79ad154 100644 --- a/runtime/string_class.go +++ b/runtime/string_class.go @@ -28,10 +28,7 @@ func Stringp(_, _ *environment.Environment, obj ilos.Instance) (ilos.Instance, i // An error shall be signaled if i is not a non-negative integer or if initial-character is not a character (error-id. domain-error). func CreateString(_, _ *environment.Environment, i ilos.Instance, initialElement ...ilos.Instance) (ilos.Instance, ilos.Instance) { if !instance.Of(class.Integer, i) || int(i.(instance.Integer)) < 0 { - return nil, instance.New(class.DomainError, map[string]ilos.Instance{ - "OBJECT": i, - "EXPECTED-CLASS": class.Integer, - }) + return nil, instance.NewDomainError(i, class.Integer) } if len(initialElement) > 1 { return nil, instance.NewArityError() diff --git a/runtime/util.go b/runtime/util.go index 3527e66..4a58ede 100644 --- a/runtime/util.go +++ b/runtime/util.go @@ -5,7 +5,6 @@ package runtime import ( - "fmt" "reflect" "regexp" "runtime" @@ -37,10 +36,7 @@ func convFloat64(x ilos.Instance) (float64, bool, ilos.Instance) { case instance.Of(class.Float, x): return float64(x.(instance.Float)), true, nil default: - return 0.0, false, instance.New(class.DomainError, map[string]ilos.Instance{ - "OBJECT": x, - "EXPECTED-CLASS": class.Number, - }) + return 0.0, false, instance.NewDomainError(x, class.Number) } } @@ -87,23 +83,8 @@ func defglobal(name string, value ilos.Instance) { func ensure(c ilos.Class, i ...ilos.Instance) ilos.Instance { for _, o := range i { if !instance.Of(c, o) { - return instance.New(class.DomainError, map[string]ilos.Instance{ - "OBJECT": o, - "EXPECTED-CLASS": c, - }) + return instance.NewDomainError(o, c) } } return nil } - -func ProgramError(cause string) (ilos.Instance, ilos.Instance) { - pc := make([]uintptr, 10) // at least 1 entry needed - runtime.Callers(2, pc) - name := runtime.FuncForPC(pc[0]).Name() - name = regexp.MustCompile(`.*\.`).ReplaceAllString(name, "") - name = regexp.MustCompile(`(.)([A-Z])`).ReplaceAllString(name, "$1-$2") - name = strings.ToUpper(name) - return nil, instance.New(class.ProgramError, map[string]ilos.Instance{ - "CAUSE": instance.NewString(cause + fmt.Sprintf(" in %v", name)), - }) -} diff --git a/runtime/variables.go b/runtime/variables.go index c42cccb..193398f 100644 --- a/runtime/variables.go +++ b/runtime/variables.go @@ -30,10 +30,7 @@ func Setq(local, global *environment.Environment, var1, form ilos.Instance) (ilo if global.Variable.Set(var1, ret) { return ret, nil } - return nil, instance.New(class.UndefinedVariable, map[string]ilos.Instance{ - "NAME": var1, - "NAMESPACE": instance.NewSymbol("VARIABLE"), - }) + return nil, instance.NewUndefinedVariable(var1) } // TODO: Setf diff --git a/runtime/vectors.go b/runtime/vectors.go index 717ae3d..72f035d 100644 --- a/runtime/vectors.go +++ b/runtime/vectors.go @@ -37,10 +37,7 @@ func GeneralVectorP(_, _ *environment.Environment, obj ilos.Instance) (ilos.Inst // initial-element may be any ISLISP object. func CreateVector(_, _ *environment.Environment, i ilos.Instance, initialElement ...ilos.Instance) (ilos.Instance, ilos.Instance) { if !instance.Of(class.Integer, i) || int(i.(instance.Integer)) < 0 { - return nil, instance.New(class.DomainError, map[string]ilos.Instance{ - "OBJECT": i, - "EXPECTED-CLASS": class.Integer, - }) + return nil, instance.NewDomainError(i, class.Integer) } if len(initialElement) > 1 { return nil, instance.NewArityError() From f60898b625abae058cc65ce7865595553234547a Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Tue, 15 Aug 2017 21:27:36 +0900 Subject: [PATCH 181/228] Remove an unused library --- reader/parser/parser_test.go | 1 - 1 file changed, 1 deletion(-) diff --git a/reader/parser/parser_test.go b/reader/parser/parser_test.go index 49b15a9..1713454 100644 --- a/reader/parser/parser_test.go +++ b/reader/parser/parser_test.go @@ -9,7 +9,6 @@ import ( "testing" "github.com/ta2gch/iris/runtime/ilos" - "github.com/ta2gch/iris/runtime/ilos/class" "github.com/ta2gch/iris/runtime/ilos/instance" ) From 7567a142857750ed8fddc7551b2b448ebb7178af Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Tue, 15 Aug 2017 21:42:17 +0900 Subject: [PATCH 182/228] Added func2symbol --- runtime/util.go | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/runtime/util.go b/runtime/util.go index 4a58ede..76243b4 100644 --- a/runtime/util.go +++ b/runtime/util.go @@ -48,30 +48,27 @@ func evalString(local, global *environment.Environment, s string) ilos.Instance e, _ := Eval(local, global, readFromString(s)) return e } -func defspecial(function interface{}) { + +func func2symbol(function interface{}) ilos.Instance { name := runtime.FuncForPC(reflect.ValueOf(function).Pointer()).Name() name = regexp.MustCompile(`.*\.`).ReplaceAllString(name, "") name = regexp.MustCompile(`(.)([A-Z])`).ReplaceAllString(name, "$1-$2") name = strings.ToUpper(name) - symbol := instance.NewSymbol(name) - environment.TopLevel.Special.Define(symbol, instance.NewFunction(symbol, function)) + return instance.NewSymbol(name) +} + +func defspecial(function interface{}) { + environment.TopLevel.Special.Define(func2symbol(function), instance.NewFunction(func2symbol(function), function)) } + func defmacro(function interface{}) { - name := runtime.FuncForPC(reflect.ValueOf(function).Pointer()).Name() - name = regexp.MustCompile(`.*\.`).ReplaceAllString(name, "") - name = regexp.MustCompile(`(.)([A-Z])`).ReplaceAllString(name, "$1-$2") - name = strings.ToUpper(name) - symbol := instance.NewSymbol(name) - environment.TopLevel.Macro.Define(symbol, instance.NewFunction(symbol, function)) + environment.TopLevel.Macro.Define(func2symbol(function), instance.NewFunction(func2symbol(function), function)) } + func defun(function interface{}) { - name := runtime.FuncForPC(reflect.ValueOf(function).Pointer()).Name() - name = regexp.MustCompile(`.*\.`).ReplaceAllString(name, "") - name = regexp.MustCompile(`(.)([A-Z])`).ReplaceAllString(name, "$1-$2") - name = strings.ToUpper(name) - symbol := instance.NewSymbol(name) - environment.TopLevel.Function.Define(symbol, instance.NewFunction(symbol, function)) + environment.TopLevel.Function.Define(func2symbol(function), instance.NewFunction(func2symbol(function), function)) } + func defun2(name string, function interface{}) { symbol := instance.NewSymbol(name) environment.TopLevel.Function.Define(symbol, instance.NewFunction(symbol, function)) From eb02ab530551b75dae32e49a5e27153717006ce7 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Wed, 16 Aug 2017 13:51:00 +0900 Subject: [PATCH 183/228] Added test for defining operators --- reader/parser/parser.go | 14 ++-- reader/tokenizer/tokenizer.go | 9 +- runtime/defining_operators_test.go | 128 +++++++++++++++++++++++++++++ runtime/dynamic_variables.go | 4 +- runtime/environment/stack.go | 1 + runtime/eval.go | 4 +- runtime/functions.go | 4 +- runtime/ilos/instance/error.go | 5 ++ 8 files changed, 149 insertions(+), 20 deletions(-) create mode 100644 runtime/defining_operators_test.go diff --git a/reader/parser/parser.go b/reader/parser/parser.go index acfdc8b..8619da9 100644 --- a/reader/parser/parser.go +++ b/reader/parser/parser.go @@ -42,11 +42,11 @@ func ParseAtom(tok string) (ilos.Instance, ilos.Instance) { // // float // - if m, _ := regexp.MatchString("^[-+]?[[:digit:]]+\\.[[:digit:]]+$", tok); m { + if m, _ := regexp.MatchString(`^[-+]?[[:digit:]]+\.[[:digit:]]+$`, tok); m { n, _ := strconv.ParseFloat(tok, 64) return instance.NewFloat(n), nil } - if r := regexp.MustCompile("^([-+]?[[:digit:]]+(?:\\.[[:digit:]]+)?)[eE]([-+]?[[:digit:]]+)$").FindStringSubmatch(tok); len(r) >= 3 { + if r := regexp.MustCompile(`^([-+]?[[:digit:]]+(?:\.[[:digit:]]+)?)[eE]([-+]?[[:digit:]]+)$`).FindStringSubmatch(tok); len(r) >= 3 { n, _ := strconv.ParseFloat(r[1], 64) e, _ := strconv.ParseInt(r[2], 10, 64) return instance.NewFloat(n * math.Pow10(int(e))), nil @@ -54,19 +54,19 @@ func ParseAtom(tok string) (ilos.Instance, ilos.Instance) { // // character // - if m, _ := regexp.MatchString("^#\\\\newline$", tok); m { + if m, _ := regexp.MatchString(`^#\\newline$`, tok); m { return instance.NewCharacter('\n'), nil } - if m, _ := regexp.MatchString("^#\\\\space$", tok); m { + if m, _ := regexp.MatchString(`^#\\space$`, tok); m { return instance.NewCharacter(' '), nil } - if r := regexp.MustCompile("^#\\\\([[:graph:]])$").FindStringSubmatch(tok); len(r) >= 2 { + if r := regexp.MustCompile(`^#\\([[:graph:]])$`).FindStringSubmatch(tok); len(r) >= 2 { return instance.NewCharacter(rune(r[1][0])), nil } // // string // - if m, _ := regexp.MatchString("^\".*\"$", tok); m { + if m, _ := regexp.MatchString(`^".*"$`, tok); m { return instance.NewString(tok), nil } // @@ -80,7 +80,7 @@ func ParseAtom(tok string) (ilos.Instance, ilos.Instance) { str += `\|.*\||` str += `\+|\-|1\+|1\-|` str += `[a-zA-Z<>/*=?_!$%[\]^{}~][-a-zA-Z0-9+<>/*=?_!$%[\]^{}~]*|` - str += ")$" + str += `)$` if m, _ := regexp.MatchString(str, tok); m { return instance.NewSymbol(strings.ToUpper(tok)), nil } diff --git a/reader/tokenizer/tokenizer.go b/reader/tokenizer/tokenizer.go index a75e939..e657e67 100644 --- a/reader/tokenizer/tokenizer.go +++ b/reader/tokenizer/tokenizer.go @@ -24,12 +24,12 @@ var re *regexp.Regexp func New(r io.Reader) *Tokenizer { str := `` + str += `[-+]?[[:digit:]]+\.[[:digit:]]+|` + str += `[-+]?[[:digit:]]+(?:\.[[:digit:]]+)?[eE][-+]?[[:digit:]]+|` str += `[-+]?[[:digit:]]+|` str += `#[bB][-+]?[01]+|` str += `#[oO][-+]?[0-7]+|` str += `#[xX][-+]?[[:xdigit:]]+|` - str += `[-+]?[[:digit:]]+\.[[:digit:]]+|` - str += `[-+]?[[:digit:]]+(?:\.[[:digit:]]+)?[eE][-+]?[[:digit:]]+|` str += `#\\newline|` str += `#\\space|` str += `#\\[[:graph:]]|` @@ -64,11 +64,6 @@ func splitter(data []byte, atEOF bool) (advance int, token []byte, err error) { advance = loc[1] token = data[loc[0]:loc[1]] err = nil - if ok, _ := regexp.Match(`^[-+]?[[:digit:]]+$`, token); ok && len(data) > loc[1] && data[loc[1]] == '.' { - advance = 0 - token = nil - err = nil - } return } return diff --git a/runtime/defining_operators_test.go b/runtime/defining_operators_test.go new file mode 100644 index 0000000..8aa073c --- /dev/null +++ b/runtime/defining_operators_test.go @@ -0,0 +1,128 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package runtime + +import "testing" + +func TestDefconstant(t *testing.T) { + defspecial(Defconstant) + defspecial(Quote) + defspecial(Defun) + tests := []test{ + { + exp: `(defconstant e 2.7182818284590451)`, + want: `'e`, + wantErr: false, + }, + { + exp: `e`, + want: `2.7182818284590451`, + wantErr: false, + }, + { + exp: `(defun f () e)`, + want: `'f`, + wantErr: false, + }, + { + exp: `(f)`, + want: `2.7182818284590451`, + wantErr: false, + }, + } + execTests(t, Defconstant, tests) +} + +func TestDefglobal(t *testing.T) { + defspecial(Defglobal) + defspecial(Quote) + defspecial(Defun) + defspecial(Let) + tests := []test{ + { + exp: `(defglobal today 'wednesday)`, + want: `'today`, + wantErr: false, + }, + { + exp: `today`, + want: `'wednesday'`, + wantErr: false, + }, + { + exp: `(defun what-is-today () today)`, + want: `'what-is-today`, + wantErr: false, + }, + { + exp: `(what-is-today)`, + want: `'wednesday`, + wantErr: false, + }, + { + exp: ` + (let ((what-is-today 'tuesday)) + (what-is-today)) + `, + want: `'wednesday`, + wantErr: false, + }, + { + exp: `(let ((today 'thursday)) (what-is-today))`, + want: `'wednesday`, + wantErr: false, + }, + } + execTests(t, Defglobal, tests) +} +func TestDefdynamic(t *testing.T) { + defspecial(Defdynamic) + defspecial(Quote) + defspecial(Defun) + defspecial(Dynamic) + defspecial(DynamicLet) + tests := []test{ + { + exp: `(defdynamic *color* 'red)`, + want: `'*color*`, + wantErr: false, + }, + { + exp: `(dynamic *color*)`, + want: `'red`, + wantErr: false, + }, + { + exp: `(defun what-color () (dynamic *color*))`, + want: `'what-color`, + wantErr: false, + }, + { + exp: `(what-color)`, + want: `'red'`, + wantErr: false, + }, + { + exp: `(dynamic-let ((*color* 'green)) (what-color))`, + want: `'green'`, + wantErr: false, + }, + } + execTests(t, Defconstant, tests) +} + +func TestDefun(t *testing.T) { + defspecial(Defconstant) + defspecial(Quote) + defspecial(Defun) + tests := []test{ + { + exp: `(defun caar (x) (car (car x)))`, + want: `'caar`, + wantErr: false, + }, + } + execTests(t, Defconstant, tests) +} diff --git a/runtime/dynamic_variables.go b/runtime/dynamic_variables.go index 72d423e..1eefc03 100644 --- a/runtime/dynamic_variables.go +++ b/runtime/dynamic_variables.go @@ -60,7 +60,7 @@ func SetDynamic(local, global *environment.Environment, form, var1 ilos.Instance return nil, instance.NewUndefinedVariable(var1) } -// DyamicLet is used to establish dynamic variable bindings. +// DynamicLet is used to establish dynamic variable bindings. // The first subform (the dynamic-let variable list) is a list of pairs (var // form). The scope of an identifier var defined by dynamic-let is the current // toplevel scope. The extent of the bindings of each var is the extent of the @@ -77,7 +77,7 @@ func SetDynamic(local, global *environment.Environment, form, var1 ilos.Instance // returned value of dynamic-let is that of the last body-form of the body (or // nil if there is none). The bindings are undone when control leaves the // prepared dynamic-let special form. -func DyamicLet(local, global *environment.Environment, varForm ilos.Instance, bodyForm ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func DynamicLet(local, global *environment.Environment, varForm ilos.Instance, bodyForm ...ilos.Instance) (ilos.Instance, ilos.Instance) { vfs := map[ilos.Instance]ilos.Instance{} if err := ensure(class.List, varForm); err != nil { return nil, err diff --git a/runtime/environment/stack.go b/runtime/environment/stack.go index 1e59ba7..ff3c6b5 100644 --- a/runtime/environment/stack.go +++ b/runtime/environment/stack.go @@ -38,5 +38,6 @@ func (s stack) Define(key, value ilos.Instance) bool { s[len(s)-1][key] = value return true } + s[len(s)-1][key] = value return false } diff --git a/runtime/eval.go b/runtime/eval.go index a13d709..68b5730 100644 --- a/runtime/eval.go +++ b/runtime/eval.go @@ -106,10 +106,10 @@ func evalMacro(local, global *environment.Environment, car, cdr ilos.Instance) ( func evalFunction(local, global *environment.Environment, car, cdr ilos.Instance) (ilos.Instance, ilos.Instance, bool) { // get special instance has value of Function interface var fun ilos.Instance - if f, ok := local.Function.Get(car); ok { + if f, ok := global.Function.Get(car); ok { fun = f } - if f, ok := global.Function.Get(car); ok { + if f, ok := local.Function.Get(car); ok { fun = f } if fun != nil { diff --git a/runtime/functions.go b/runtime/functions.go index 01b5876..a9dd8d8 100644 --- a/runtime/functions.go +++ b/runtime/functions.go @@ -36,10 +36,10 @@ func Function(local, global *environment.Environment, fun ilos.Instance) (ilos.I if err := ensure(class.Symbol, fun); err != nil { return nil, err } - if f, ok := local.Function.Get(fun); ok { + if f, ok := global.Function.Get(fun); ok { return f, nil } - if f, ok := global.Function.Get(fun); ok { + if f, ok := local.Function.Get(fun); ok { return f, nil } return nil, instance.NewUndefinedFunction(fun) diff --git a/runtime/ilos/instance/error.go b/runtime/ilos/instance/error.go index 37da2b9..655035f 100644 --- a/runtime/ilos/instance/error.go +++ b/runtime/ilos/instance/error.go @@ -5,6 +5,8 @@ package instance import ( + "fmt" + "github.com/ta2gch/iris/runtime/ilos" "github.com/ta2gch/iris/runtime/ilos/class" ) @@ -52,14 +54,17 @@ func NewUndefinedVariable(name ilos.Instance) ilos.Instance { } func NewArityError() ilos.Instance { + fmt.Println("Arity-Error") return New(class.ProgramError, map[string]ilos.Instance{}) } func NewIndexOutOfRange() ilos.Instance { + fmt.Println("Index Out Of Range") return New(class.ProgramError, map[string]ilos.Instance{}) } func NewImmutableBinding() ilos.Instance { + fmt.Println("Immutable binding") return New(class.ProgramError, map[string]ilos.Instance{}) } From 309db677a1e58a5f1850baf0123b7d187c9fca8c Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Wed, 16 Aug 2017 17:41:51 +0900 Subject: [PATCH 184/228] Added test for equality --- reader/parser/array.go | 31 +++ reader/parser/parser.go | 33 +-- reader/tokenizer/tokenizer.go | 7 +- runtime/array_operations.go | 37 ++- runtime/conditional_expressions.go | 2 +- runtime/defining_operators_test.go | 4 +- runtime/equality.go | 10 +- runtime/equality_test.go | 362 +++++++++++++++++++++++++++ runtime/ilos/instance/basic-array.go | 4 +- runtime/ilos/instance/error.go | 31 ++- runtime/ilos/instance/function.go | 6 +- runtime/list_operations.go | 12 +- runtime/sequence_functions.go | 2 +- runtime/string_class.go | 2 +- runtime/symbol_class.go | 2 +- runtime/test.go | 2 - 16 files changed, 478 insertions(+), 69 deletions(-) create mode 100644 reader/parser/array.go create mode 100644 runtime/equality_test.go diff --git a/reader/parser/array.go b/reader/parser/array.go new file mode 100644 index 0000000..013f777 --- /dev/null +++ b/reader/parser/array.go @@ -0,0 +1,31 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package parser + +import ( + "github.com/ta2gch/iris/runtime/ilos" + "github.com/ta2gch/iris/runtime/ilos/instance" +) + +func list2array(dim int, list ilos.Instance) (ilos.Instance, ilos.Instance) { + // TODO: check array correctly ( #2((a) ()) ) + if dim == 0 { + return instance.NewGeneralArrayStar(nil, list), nil + } + elements := list.(instance.List).Slice() + arrays := make([]instance.GeneralArrayStar, len(elements)) + for idx, elt := range elements { + array, err := list2array(dim-1, elt) + if err != nil { + return nil, err + } + arrays[idx] = array.(instance.GeneralArrayStar) + } + return instance.NewGeneralArrayStar(arrays, nil), nil +} + +func list2vector(list ilos.Instance) (ilos.Instance, ilos.Instance) { + return instance.NewGeneralVector(list.(instance.List).Slice()), nil +} diff --git a/reader/parser/parser.go b/reader/parser/parser.go index 8619da9..0a7c01e 100644 --- a/reader/parser/parser.go +++ b/reader/parser/parser.go @@ -54,10 +54,10 @@ func ParseAtom(tok string) (ilos.Instance, ilos.Instance) { // // character // - if m, _ := regexp.MatchString(`^#\\newline$`, tok); m { + if m, _ := regexp.MatchString(`^#\\newline$`, strings.ToLower(tok)); m { return instance.NewCharacter('\n'), nil } - if m, _ := regexp.MatchString(`^#\\space$`, tok); m { + if m, _ := regexp.MatchString(`^#\\space$`, strings.ToLower(tok)); m { return instance.NewCharacter(' '), nil } if r := regexp.MustCompile(`^#\\([[:graph:]])$`).FindStringSubmatch(tok); len(r) >= 2 { @@ -66,8 +66,8 @@ func ParseAtom(tok string) (ilos.Instance, ilos.Instance) { // // string // - if m, _ := regexp.MatchString(`^".*"$`, tok); m { - return instance.NewString(tok), nil + if r := regexp.MustCompile(`^"(.*)"$`).FindStringSubmatch(tok); len(r) >= 2 { + return instance.NewString(r[1]), nil } // // symbol @@ -93,19 +93,20 @@ func parseMacro(tok string, t *tokenizer.Tokenizer) (ilos.Instance, ilos.Instanc return nil, err } n := tok - if m, _ := regexp.MatchString("#[[:digit:]]*[aA]", tok); m { - s := instance.NewSymbol("array") + if m, _ := regexp.MatchString("#[[:digit:]]+[aA]", tok); m { i := strings.IndexRune(strings.ToLower(tok), 'a') - if i == 1 { - d := instance.NewInteger(1) - return instance.NewCons(s, instance.NewCons(d, instance.NewCons(cdr, instance.NewNull()))), nil + var v int64 = 1 + if i != 1 { + var err error + v, err = strconv.ParseInt(tok[1:i], 10, 64) + if err != nil { + return nil, instance.NewParseError(instance.NewString(tok), class.Integer) + } } - v, err := strconv.ParseInt(tok[1:i], 10, 32) - if err != nil { - return nil, instance.NewParseError(instance.NewString(tok), class.Integer) - } - d := instance.NewInteger(int(v)) - return instance.NewCons(s, instance.NewCons(d, instance.NewCons(cdr, instance.NewNull()))), nil + return list2array(int(v), cdr) + } + if tok == "#" { + return list2vector(cdr) } switch tok { case "#'": @@ -166,7 +167,7 @@ func Parse(t *tokenizer.Tokenizer) (ilos.Instance, ilos.Instance) { if tok == "." { return nil, bod } - if mat, _ := regexp.MatchString("^(?:#'|,@?|'|`|#[[:digit:]]*[aA])$", tok); mat { + if mat, _ := regexp.MatchString("^(?:#'|,@?|'|`|#[[:digit:]]*[aA]|#)$", tok); mat { m, err := parseMacro(tok, t) if err != nil { return nil, err diff --git a/reader/tokenizer/tokenizer.go b/reader/tokenizer/tokenizer.go index e657e67..813598d 100644 --- a/reader/tokenizer/tokenizer.go +++ b/reader/tokenizer/tokenizer.go @@ -30,16 +30,15 @@ func New(r io.Reader) *Tokenizer { str += `#[bB][-+]?[01]+|` str += `#[oO][-+]?[0-7]+|` str += `#[xX][-+]?[[:xdigit:]]+|` - str += `#\\newline|` - str += `#\\space|` + str += `#\\[[:alpha:]]+|` str += `#\\[[:graph:]]|` - str += `".*"|` // TODO: support \" + str += `"[^"]*"|` // TODO: support \" str += `[:&][a-zA-Z]+|` str += `\|.*\||` // TODO: support \" str += `\+|\-|1\+|1\-|` str += `[a-zA-Z<>/*=?_!$%[\]^{}~][-a-zA-Z0-9+<>/*=?_!$%[\]^{}~]*|` str += `[.()]|` - str += "#'|,@?|'|`|#[[:digit:]]*[aA]" + str += "#'|,@?|'|`|#[[:digit:]]*[aA]|#" // TODO: hangs at #ab or #3 re = regexp.MustCompile(str) sc := bufio.NewScanner(r) sc.Split(splitter) diff --git a/runtime/array_operations.go b/runtime/array_operations.go index 12e43a2..214d91b 100644 --- a/runtime/array_operations.go +++ b/runtime/array_operations.go @@ -67,29 +67,22 @@ func CreateArray(_, _ *environment.Environment, dimensions ilos.Instance, initia if len(initialElement) == 1 { elt = initialElement[0] } - switch len(dim) { - case 0: + if len(dim) == 0 { return instance.NewGeneralArrayStar(nil, elt), nil - case 1: - array := make([]*instance.GeneralArrayStar, int(dim[0].(instance.Integer))) - for i := range array { - array[i] = instance.NewGeneralArrayStar(nil, elt).(*instance.GeneralArrayStar) - } - return instance.NewGeneralArrayStar(array, nil), nil - default: - array := make([]*instance.GeneralArrayStar, int(dim[len(dim)-1].(instance.Integer))) - for i := range array { - array[i] = instance.NewGeneralArrayStar(nil, elt).(*instance.GeneralArrayStar) + } + array := make([]instance.GeneralArrayStar, int(dim[0].(instance.Integer))) + for i := range array { + d, err := List(nil, nil, dim[1:]...) // TODO: replace UnsafeCdr + if err != nil { + return nil, err } - for i := len(dim) - 2; i >= 0; i-- { - elt := array - array := make([]*instance.GeneralArrayStar, int(dim[i].(instance.Integer))) - for i := range array { - array[i] = instance.NewGeneralArrayStar(elt, nil).(*instance.GeneralArrayStar) - } + a, err := CreateArray(nil, nil, d, elt) + if err != nil { + return nil, err } - return instance.NewGeneralArrayStar(array, nil), nil + array[i] = a.(instance.GeneralArrayStar) } + return instance.NewGeneralArrayStar(array, nil), nil } // Aref returns the object stored in the component of the basic-array specified by the sequence @@ -140,7 +133,7 @@ func Garef(_, _ *environment.Environment, generalArray ilos.Instance, dimensions if err := ensure(class.Integer, dimensions...); err != nil { return nil, err } - var array *instance.GeneralArrayStar + var array instance.GeneralArrayStar for _, dim := range dimensions { index := int(dim.(instance.Integer)) if array.Vector == nil || len(array.Vector) <= index { @@ -203,7 +196,7 @@ func SetGaref(_, _ *environment.Environment, obj, generalArray ilos.Instance, di if err := ensure(class.Integer, dimensions...); err != nil { return nil, err } - var array *instance.GeneralArrayStar + var array instance.GeneralArrayStar for _, dim := range dimensions { index := int(dim.(instance.Integer)) if array.Vector == nil || len(array.Vector) <= index { @@ -231,7 +224,7 @@ func ArrayDimensions(_, _ *environment.Environment, basicArray ilos.Instance) (i case instance.Of(class.GeneralVector, basicArray): return List(nil, nil, instance.NewInteger(len(basicArray.(instance.GeneralVector)))) default: // General Array* - var array *instance.GeneralArrayStar + var array instance.GeneralArrayStar dimensions := []ilos.Instance{} for array.Vector != nil { dimensions = append(dimensions, instance.NewInteger(len(array.Vector))) diff --git a/runtime/conditional_expressions.go b/runtime/conditional_expressions.go index 6d8422b..eba80b2 100644 --- a/runtime/conditional_expressions.go +++ b/runtime/conditional_expressions.go @@ -142,7 +142,7 @@ func CaseUsing(local, global *environment.Environment, key, pred ilos.Instance, } keys := form[0].(instance.List).Slice() for _, k := range keys { - ret, err := pred.(instance.Function).Apply(local, global, k, key) + ret, err := pred.(*instance.Function).Apply(local, global, k, key) if err != nil { return nil, err } diff --git a/runtime/defining_operators_test.go b/runtime/defining_operators_test.go index 8aa073c..09366c3 100644 --- a/runtime/defining_operators_test.go +++ b/runtime/defining_operators_test.go @@ -110,7 +110,7 @@ func TestDefdynamic(t *testing.T) { wantErr: false, }, } - execTests(t, Defconstant, tests) + execTests(t, Defdynamic, tests) } func TestDefun(t *testing.T) { @@ -124,5 +124,5 @@ func TestDefun(t *testing.T) { wantErr: false, }, } - execTests(t, Defconstant, tests) + execTests(t, Defun, tests) } diff --git a/runtime/equality.go b/runtime/equality.go index 9210ee8..e511d7b 100644 --- a/runtime/equality.go +++ b/runtime/equality.go @@ -9,6 +9,8 @@ import ( "github.com/ta2gch/iris/runtime/environment" "github.com/ta2gch/iris/runtime/ilos" + "github.com/ta2gch/iris/runtime/ilos/class" + "github.com/ta2gch/iris/runtime/ilos/instance" ) // Eq tests whether obj1 and obj2 are same identical object. @@ -16,6 +18,9 @@ import ( // Two objects are the same if there is no operation that could distinguish // them (without modifying them), and if modifying one would modify the other the same way. func Eq(_, _ *environment.Environment, obj1, obj2 ilos.Instance) (ilos.Instance, ilos.Instance) { + if instance.Of(class.String, obj1) && instance.Of(class.String, obj1) { + return StringEqual(nil, nil, obj1, obj2) + } if obj1 == obj2 { return T, nil } @@ -27,10 +32,7 @@ func Eq(_, _ *environment.Environment, obj1, obj2 ilos.Instance) (ilos.Instance, // Two objects are the same if there is no operation that could distinguish // them (without modifying them), and if modifying one would modify the other the same way. func Eql(_, _ *environment.Environment, obj1, obj2 ilos.Instance) (ilos.Instance, ilos.Instance) { - if obj1 == obj2 { - return T, nil - } - return Nil, nil + return Eq(nil, nil, obj1, obj2) } // Equal tests whether obj1 and obj2 are isomorphic—i.e., whether obj1 and obj2 denote the same diff --git a/runtime/equality_test.go b/runtime/equality_test.go new file mode 100644 index 0000000..0857508 --- /dev/null +++ b/runtime/equality_test.go @@ -0,0 +1,362 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package runtime + +import "testing" + +func TestEq(t *testing.T) { + defun(Eq) + defspecial(Quote) + defglobal("T", T) + defglobal("NIL", Nil) + defun(Cons) + defun(Cdr) + defspecial(Let) + defspecial(Lambda) + tests := []test{ + { + exp: `(eq () ())`, + want: `T`, + wantErr: false, + }, + { + exp: `(eq '() '())`, + want: `T`, + wantErr: false, + }, + { + exp: `(eq 'a 'a)`, + want: `T`, + wantErr: false, + }, + { + exp: `(eq 'a 'A)`, + want: `T`, + wantErr: false, + }, + { + exp: `(eq 'a 'b)`, + want: `nil`, + wantErr: false, + }, + { + exp: `(eq 'f 'nil)`, + want: `nil`, + wantErr: false, + }, + { + exp: `(eq 2 2)`, + want: `T`, + wantErr: false, + }, + { + exp: `(eq 2 2.0)`, + want: `nil`, + wantErr: false, + }, + { + exp: `(eq 100000000 100000000)`, + want: `T`, + wantErr: false, + }, + { + exp: `(eq 10.00000 10.0)`, + want: `T`, + wantErr: false, + }, + { + exp: `(eq (cons 1 2) (cons 1 2))`, + want: `nil`, + wantErr: false, + }, + { + exp: `(let ((x '(a))) (eq x x))`, + want: `T`, + wantErr: false, + }, + { + exp: `(eq '(a) '(a))`, + want: `nil`, + wantErr: false, + }, + { + exp: ` + (let ((x '(b)) + (y '(a b))) + (eq x (cdr y))) + `, + want: `nil`, + wantErr: false, + }, + { + exp: `(eq '(b) (cdr '(a b)))`, + want: `nil`, + wantErr: false, + }, + { + exp: ` + (let ((p (lambda (x) x))) + (eq p p)) + `, + want: `t`, + wantErr: false, + }, + { + exp: `(let ((x "a")) (eq x x))`, + want: `t`, + wantErr: false, + }, + { + exp: `(eq "a" "a")`, + want: `t`, + wantErr: false, + }, + { + exp: `(let ((x "")) (eq x x))`, + want: `t`, + wantErr: false, + }, + { + exp: `(eq "" "")`, + want: `t`, + wantErr: false, + }, + { + exp: `(eq #\a #\A)`, + want: `nil`, + wantErr: false, + }, + { + exp: `(eq #\a #\a)`, + want: `t`, + wantErr: false, + }, + { + exp: `(eq #\space #\Space)`, + want: `t`, + wantErr: false, + }, + { + exp: `(eq #\space #\space)`, + want: `t`, + wantErr: false, + }, + } + execTests(t, Eq, tests) +} + +func TestEql(t *testing.T) { + defun(Eql) + defspecial(Quote) + defglobal("T", T) + defglobal("NIL", Nil) + defun(Cons) + defun(Cdr) + defspecial(Let) + defspecial(Lambda) + tests := []test{ + { + exp: `(eql () ())`, + want: `T`, + wantErr: false, + }, + { + exp: `(eql '() '())`, + want: `T`, + wantErr: false, + }, + { + exp: `(eql 'a 'a)`, + want: `T`, + wantErr: false, + }, + { + exp: `(eql 'a 'A)`, + want: `T`, + wantErr: false, + }, + { + exp: `(eql 'a 'b)`, + want: `nil`, + wantErr: false, + }, + { + exp: `(eql 'f 'nil)`, + want: `nil`, + wantErr: false, + }, + { + exp: `(eql 2 2)`, + want: `T`, + wantErr: false, + }, + { + exp: `(eql 2 2.0)`, + want: `nil`, + wantErr: false, + }, + { + exp: `(eql 100000000 100000000)`, + want: `T`, + wantErr: false, + }, + { + exp: `(eql 10.00000 10.0)`, + want: `T`, + wantErr: false, + }, + { + exp: `(eql (cons 1 2) (cons 1 2))`, + want: `nil`, + wantErr: false, + }, + { + exp: `(let ((x '(a))) (eql x x))`, + want: `T`, + wantErr: false, + }, + { + exp: `(eql '(a) '(a))`, + want: `nil`, + wantErr: false, + }, + { + exp: ` + (let ((x '(b)) + (y '(a b))) + (eql x (cdr y))) + `, + want: `nil`, + wantErr: false, + }, + { + exp: `(eql '(b) (cdr '(a b)))`, + want: `nil`, + wantErr: false, + }, + { + exp: ` + (let ((p (lambda (x) x))) + (eql p p)) + `, + want: `t`, + wantErr: false, + }, + { + exp: `(let ((x "a")) (eql x x))`, + want: `t`, + wantErr: false, + }, + { + exp: `(eql "a" "a")`, + want: `t`, + wantErr: false, + }, + { + exp: `(let ((x "")) (eql x x))`, + want: `t`, + wantErr: false, + }, + { + exp: `(eql "" "")`, + want: `t`, + wantErr: false, + }, + { + exp: `(eql #\a #\A)`, + want: `nil`, + wantErr: false, + }, + { + exp: `(eql #\a #\a)`, + want: `t`, + wantErr: false, + }, + { + exp: `(eql #\space #\Space)`, + want: `t`, + wantErr: false, + }, + { + exp: `(eql #\space #\space)`, + want: `t`, + wantErr: false, + }, + } + execTests(t, Eql, tests) +} + +func TestEqual(t *testing.T) { + defun(Equal) + defspecial(Quote) + defglobal("T", T) + defglobal("NIL", Nil) + defun(Cons) + defun(List) + defun(Vector) + tests := []test{ + { + exp: `(equal 'a 'a)`, + want: `t`, + wantErr: false, + }, + { + exp: `(equal 2 2)`, + want: `t`, + wantErr: false, + }, + { + exp: `(equal 2 2.0)`, + want: `nil`, + wantErr: false, + }, + { + exp: `(equal '(a) '(a))`, + want: `t`, + wantErr: false, + }, + { + exp: `(equal '(a (b) c) '(a (b) c))`, + want: `t`, + wantErr: false, + }, + { + exp: `(equal (cons 1 2) (cons 1 2))`, + want: `t`, + wantErr: false, + }, + { + exp: `(equal '(a) (list 'a))`, + want: `t`, + wantErr: false, + }, + { + exp: `(equal "abc" "abc")`, + want: `t`, + wantErr: false, + }, + { + exp: `(equal (vector 'a) (vector 'a))`, + want: `t`, + wantErr: false, + }, + { + exp: `(equal #(a b) #(a b))`, + want: `t`, + wantErr: false, + }, + { + exp: `(equal #(a b) #(a c))`, + want: `nil`, + wantErr: false, + }, + { + exp: `(equal "a" "A")`, + want: `nil`, + wantErr: false, + }, + } + execTests(t, Equal, tests) +} diff --git a/runtime/ilos/instance/basic-array.go b/runtime/ilos/instance/basic-array.go index 426fe3f..3f46919 100644 --- a/runtime/ilos/instance/basic-array.go +++ b/runtime/ilos/instance/basic-array.go @@ -15,11 +15,11 @@ import ( // type GeneralArrayStar struct { - Vector []*GeneralArrayStar + Vector []GeneralArrayStar Scalar ilos.Instance } -func NewGeneralArrayStar(vector []*GeneralArrayStar, scalar ilos.Instance) ilos.Instance { +func NewGeneralArrayStar(vector []GeneralArrayStar, scalar ilos.Instance) ilos.Instance { return GeneralArrayStar{vector, scalar} } diff --git a/runtime/ilos/instance/error.go b/runtime/ilos/instance/error.go index 655035f..2b43ff7 100644 --- a/runtime/ilos/instance/error.go +++ b/runtime/ilos/instance/error.go @@ -5,12 +5,35 @@ package instance import ( - "fmt" + "log" + "runtime" + "strings" "github.com/ta2gch/iris/runtime/ilos" "github.com/ta2gch/iris/runtime/ilos/class" ) +func stackTrace() { + println("----") + programCounter, sourceFileName, sourceFileLineNum, ok := runtime.Caller(2) + log.Printf("programCounter: %v\n", programCounter) + log.Printf("souruntime: %s\n", sourceFileName) + log.Printf("sourceFileLineNum: %d\n", sourceFileLineNum) + log.Printf("ok: %t\n", ok) + + fn := runtime.FuncForPC(programCounter) + log.Printf("Function Name: %s\n", fn.Name()) + fileName, fileLine := fn.FileLine(programCounter) + log.Printf("FileName:%s, FileLine: %d\n", fileName, fileLine) + + splitedFnName := strings.Split(fn.Name(), ".") + packageName := splitedFnName[0] + callerFuncName := splitedFnName[1] + log.Printf("packageName: %s\n", packageName) + log.Printf("functionName: %s\n", callerFuncName) + println("-----") +} + func NewArithmeticError(operation, operands ilos.Instance) ilos.Instance { return New(class.ArithmeticError, map[string]ilos.Instance{ "OPERATION": operation, @@ -54,17 +77,17 @@ func NewUndefinedVariable(name ilos.Instance) ilos.Instance { } func NewArityError() ilos.Instance { - fmt.Println("Arity-Error") + //stackTrace() return New(class.ProgramError, map[string]ilos.Instance{}) } func NewIndexOutOfRange() ilos.Instance { - fmt.Println("Index Out Of Range") + //stackTrace() return New(class.ProgramError, map[string]ilos.Instance{}) } func NewImmutableBinding() ilos.Instance { - fmt.Println("Immutable binding") + //stackTrace() return New(class.ProgramError, map[string]ilos.Instance{}) } diff --git a/runtime/ilos/instance/function.go b/runtime/ilos/instance/function.go index 06e175e..2c9d4a6 100644 --- a/runtime/ilos/instance/function.go +++ b/runtime/ilos/instance/function.go @@ -23,7 +23,7 @@ type Function struct { } func NewFunction(name ilos.Instance, function interface{}) ilos.Instance { - return Function{name, function} + return &Function{name, function} } func (Function) Class() ilos.Class { @@ -38,11 +38,11 @@ func (Function) SetSlotValue(key ilos.Instance, value ilos.Instance, _ ilos.Clas return false } -func (f Function) String() string { +func (f *Function) String() string { return fmt.Sprintf("#%v", f.Class()) } -func (f Function) Apply(local, global *environment.Environment, arguments ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func (f *Function) Apply(local, global *environment.Environment, arguments ...ilos.Instance) (ilos.Instance, ilos.Instance) { fv := reflect.ValueOf(f.function) ft := reflect.TypeOf(f.function) argv := []reflect.Value{reflect.ValueOf(local), reflect.ValueOf(global)} diff --git a/runtime/list_operations.go b/runtime/list_operations.go index a12e7b7..32cdaa9 100644 --- a/runtime/list_operations.go +++ b/runtime/list_operations.go @@ -158,7 +158,7 @@ func Mapcar(local, global *environment.Environment, function, list1 ilos.Instanc for j, list := range lists { arguments[j] = list.(instance.List).Slice()[i] } - ret, err := function.(instance.Function).Apply(local, global, arguments...) + ret, err := function.(*instance.Function).Apply(local, global, arguments...) if err != nil { return nil, err } @@ -186,7 +186,7 @@ func Mapc(local, global *environment.Environment, function, list1 ilos.Instance, for j, list := range lists { arguments[j] = list.(instance.List).Slice()[i] } - if _, err := function.(instance.Function).Apply(local, global, arguments...); err != nil { + if _, err := function.(*instance.Function).Apply(local, global, arguments...); err != nil { return nil, err } } @@ -214,7 +214,7 @@ func Mapcan(local, global *environment.Environment, function, list1 ilos.Instanc for j, list := range lists { arguments[j] = list.(instance.List).Slice()[i] } - ret, err := function.(instance.Function).Apply(local, global, arguments...) + ret, err := function.(*instance.Function).Apply(local, global, arguments...) if err != nil { return nil, err } @@ -248,7 +248,7 @@ func Maplist(local, global *environment.Environment, function, list1 ilos.Instan return nil, err } } - ret, err := function.(instance.Function).Apply(local, global, arguments...) + ret, err := function.(*instance.Function).Apply(local, global, arguments...) if err != nil { return nil, err } @@ -280,7 +280,7 @@ func Mapl(local, global *environment.Environment, function, list1 ilos.Instance, return nil, err } } - if _, err := function.(instance.Function).Apply(local, global, arguments...); err != nil { + if _, err := function.(*instance.Function).Apply(local, global, arguments...); err != nil { return nil, err } } @@ -312,7 +312,7 @@ func Mapcon(local, global *environment.Environment, function, list1 ilos.Instanc return nil, err } } - ret, err := function.(instance.Function).Apply(local, global, arguments...) + ret, err := function.(*instance.Function).Apply(local, global, arguments...) if err != nil { return nil, err } diff --git a/runtime/sequence_functions.go b/runtime/sequence_functions.go index 1f745fe..02c0d85 100644 --- a/runtime/sequence_functions.go +++ b/runtime/sequence_functions.go @@ -204,7 +204,7 @@ func mapInto(local, global *environment.Environment, destination, function ilos. return nil, err } } - ret, err := function.(instance.Function).Apply(local, global, arguments...) + ret, err := function.(*instance.Function).Apply(local, global, arguments...) if err != nil { return nil, err } diff --git a/runtime/string_class.go b/runtime/string_class.go index 79ad154..bacd597 100644 --- a/runtime/string_class.go +++ b/runtime/string_class.go @@ -53,7 +53,7 @@ func StringEqual(_, _ *environment.Environment, string1, string2 ilos.Instance) if err := ensure(class.String, string1, string2); err != nil { return nil, err } - if string1 == string2 { + if string(string1.(instance.String)) == string(string2.(instance.String)) { return T, nil } return Nil, nil diff --git a/runtime/symbol_class.go b/runtime/symbol_class.go index 52d5218..ac0e95c 100644 --- a/runtime/symbol_class.go +++ b/runtime/symbol_class.go @@ -79,5 +79,5 @@ func RemoveProperty(local, global *environment.Environment, symbol, propertyName // It is impossible for an identifier to name an unnamed symbol. func Gensym(local, global *environment.Environment) (ilos.Instance, ilos.Instance) { global.GensymID++ - return instance.NewSymbol(fmt.Sprintf("IRIS:G#%v", global.GensymID)), nil + return instance.NewSymbol(fmt.Sprintf("IRIS/G#%v", global.GensymID)), nil } diff --git a/runtime/test.go b/runtime/test.go index 33bc7e8..3a6e565 100644 --- a/runtime/test.go +++ b/runtime/test.go @@ -10,7 +10,6 @@ import ( "runtime" "testing" - "github.com/k0kubun/pp" "github.com/ta2gch/iris/runtime/environment" ) @@ -30,7 +29,6 @@ func execTests(t *testing.T, function interface{}, tests []test) { got, err := Eval(local, global, readFromString(tt.exp)) want, _ := Eval(local, global, readFromString(tt.want)) if !reflect.DeepEqual(got, want) { - pp.Println(got, want) t.Errorf("%v() got = %v, want %v", name, got, want) } if (err != nil) != tt.wantErr { From 5bb16cd8e9ef8e2578e6fe176e28cc83eca49d14 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Wed, 16 Aug 2017 22:26:24 +0900 Subject: [PATCH 185/228] removed StringEqual in Eq --- runtime/equality.go | 13 ++++++++----- runtime/equality_test.go | 8 ++++---- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/runtime/equality.go b/runtime/equality.go index e511d7b..15dbb65 100644 --- a/runtime/equality.go +++ b/runtime/equality.go @@ -9,8 +9,6 @@ import ( "github.com/ta2gch/iris/runtime/environment" "github.com/ta2gch/iris/runtime/ilos" - "github.com/ta2gch/iris/runtime/ilos/class" - "github.com/ta2gch/iris/runtime/ilos/instance" ) // Eq tests whether obj1 and obj2 are same identical object. @@ -18,10 +16,15 @@ import ( // Two objects are the same if there is no operation that could distinguish // them (without modifying them), and if modifying one would modify the other the same way. func Eq(_, _ *environment.Environment, obj1, obj2 ilos.Instance) (ilos.Instance, ilos.Instance) { - if instance.Of(class.String, obj1) && instance.Of(class.String, obj1) { - return StringEqual(nil, nil, obj1, obj2) + t1, t2 := reflect.TypeOf(obj1), reflect.TypeOf(obj2) + if t1.Comparable() || t2.Comparable() { + if obj1 == obj2 { + return T, nil + } + return Nil, nil } - if obj1 == obj2 { + v1, v2 := reflect.ValueOf(obj1), reflect.ValueOf(obj2) + if v1 == v2 { return T, nil } return Nil, nil diff --git a/runtime/equality_test.go b/runtime/equality_test.go index 0857508..e599f74 100644 --- a/runtime/equality_test.go +++ b/runtime/equality_test.go @@ -110,7 +110,7 @@ func TestEq(t *testing.T) { }, { exp: `(eq "a" "a")`, - want: `t`, + want: `nil`, wantErr: false, }, { @@ -120,7 +120,7 @@ func TestEq(t *testing.T) { }, { exp: `(eq "" "")`, - want: `t`, + want: `nil`, wantErr: false, }, { @@ -251,7 +251,7 @@ func TestEql(t *testing.T) { }, { exp: `(eql "a" "a")`, - want: `t`, + want: `nil`, wantErr: false, }, { @@ -261,7 +261,7 @@ func TestEql(t *testing.T) { }, { exp: `(eql "" "")`, - want: `t`, + want: `nil`, wantErr: false, }, { From 291ab3099114081603d8fdc5d689a98c265115f5 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Wed, 16 Aug 2017 22:46:28 +0900 Subject: [PATCH 186/228] Changed equality --- runtime/equality.go | 23 +++++++++++++++-------- runtime/equality_test.go | 12 ++++++------ 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/runtime/equality.go b/runtime/equality.go index 15dbb65..7e7b7fe 100644 --- a/runtime/equality.go +++ b/runtime/equality.go @@ -7,6 +7,9 @@ package runtime import ( "reflect" + "github.com/ta2gch/iris/runtime/ilos/class" + "github.com/ta2gch/iris/runtime/ilos/instance" + "github.com/ta2gch/iris/runtime/environment" "github.com/ta2gch/iris/runtime/ilos" ) @@ -16,6 +19,18 @@ import ( // Two objects are the same if there is no operation that could distinguish // them (without modifying them), and if modifying one would modify the other the same way. func Eq(_, _ *environment.Environment, obj1, obj2 ilos.Instance) (ilos.Instance, ilos.Instance) { + v1, v2 := reflect.ValueOf(obj1), reflect.ValueOf(obj2) + if v1 == v2 || instance.Of(class.Symbol, obj1) && instance.Of(class.Symbol, obj2) && obj1 == obj2 { + return T, nil + } + return Nil, nil +} + +// Eql tests whether obj1 and obj2 are same identical object. +// They return t if the objects are the same; otherwise, they return nil. +// Two objects are the same if there is no operation that could distinguish +// them (without modifying them), and if modifying one would modify the other the same way. +func Eql(_, _ *environment.Environment, obj1, obj2 ilos.Instance) (ilos.Instance, ilos.Instance) { t1, t2 := reflect.TypeOf(obj1), reflect.TypeOf(obj2) if t1.Comparable() || t2.Comparable() { if obj1 == obj2 { @@ -30,14 +45,6 @@ func Eq(_, _ *environment.Environment, obj1, obj2 ilos.Instance) (ilos.Instance, return Nil, nil } -// Eql tests whether obj1 and obj2 are same identical object. -// They return t if the objects are the same; otherwise, they return nil. -// Two objects are the same if there is no operation that could distinguish -// them (without modifying them), and if modifying one would modify the other the same way. -func Eql(_, _ *environment.Environment, obj1, obj2 ilos.Instance) (ilos.Instance, ilos.Instance) { - return Eq(nil, nil, obj1, obj2) -} - // Equal tests whether obj1 and obj2 are isomorphic—i.e., whether obj1 and obj2 denote the same // structure with equivalent values. equal returns t if the test was satisfied, and nil if not. // Specifically: diff --git a/runtime/equality_test.go b/runtime/equality_test.go index e599f74..7fdab0c 100644 --- a/runtime/equality_test.go +++ b/runtime/equality_test.go @@ -48,7 +48,7 @@ func TestEq(t *testing.T) { }, { exp: `(eq 2 2)`, - want: `T`, + want: `nil`, wantErr: false, }, { @@ -58,12 +58,12 @@ func TestEq(t *testing.T) { }, { exp: `(eq 100000000 100000000)`, - want: `T`, + want: `nil`, wantErr: false, }, { exp: `(eq 10.00000 10.0)`, - want: `T`, + want: `nil`, wantErr: false, }, { @@ -130,17 +130,17 @@ func TestEq(t *testing.T) { }, { exp: `(eq #\a #\a)`, - want: `t`, + want: `nil`, wantErr: false, }, { exp: `(eq #\space #\Space)`, - want: `t`, + want: `nil`, wantErr: false, }, { exp: `(eq #\space #\space)`, - want: `t`, + want: `nil`, wantErr: false, }, } From 03ca70c36654663e93de123d59a363fb875b4a3d Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Wed, 16 Aug 2017 23:31:33 +0900 Subject: [PATCH 187/228] Changed *instance.Function to instance.Function --- reader/parser/parser.go | 6 +++--- runtime/boolean_values.go | 2 +- runtime/conditional_expressions.go | 2 +- runtime/equality.go | 24 ++++++++++++++++++++---- runtime/ilos/instance/function.go | 6 +++--- runtime/ilos/instance/list.go | 16 +++++++++------- runtime/list_operations.go | 12 ++++++------ runtime/sequence_functions.go | 2 +- 8 files changed, 44 insertions(+), 26 deletions(-) diff --git a/reader/parser/parser.go b/reader/parser/parser.go index 0a7c01e..06d6c8f 100644 --- a/reader/parser/parser.go +++ b/reader/parser/parser.go @@ -73,7 +73,7 @@ func ParseAtom(tok string) (ilos.Instance, ilos.Instance) { // symbol // if "nil" == tok { - return instance.NewNull(), nil + return instance.Nil, nil } str := `^(` str += `[:&][a-zA-Z]+|` @@ -121,12 +121,12 @@ func parseMacro(tok string, t *tokenizer.Tokenizer) (ilos.Instance, ilos.Instanc n = "BACKQUOTE" } m := instance.NewSymbol(n) - return instance.NewCons(m, instance.NewCons(cdr, instance.NewNull())), nil + return instance.NewCons(m, instance.NewCons(cdr, instance.Nil)), nil } func parseCons(t *tokenizer.Tokenizer) (ilos.Instance, ilos.Instance) { car, err := Parse(t) if err == eop { - return instance.NewNull(), nil + return instance.Nil, nil } if err == bod { cdr, err := Parse(t) diff --git a/runtime/boolean_values.go b/runtime/boolean_values.go index 3cc4aac..8b36520 100644 --- a/runtime/boolean_values.go +++ b/runtime/boolean_values.go @@ -29,6 +29,6 @@ import ( // t is a named constant whose value is the symbol t itself. // nil is a named constant whose value is the symbol nil itself. var ( - Nil = instance.NewNull() + Nil = instance.Nil T = instance.NewSymbol("T") ) diff --git a/runtime/conditional_expressions.go b/runtime/conditional_expressions.go index eba80b2..6d8422b 100644 --- a/runtime/conditional_expressions.go +++ b/runtime/conditional_expressions.go @@ -142,7 +142,7 @@ func CaseUsing(local, global *environment.Environment, key, pred ilos.Instance, } keys := form[0].(instance.List).Slice() for _, k := range keys { - ret, err := pred.(*instance.Function).Apply(local, global, k, key) + ret, err := pred.(instance.Function).Apply(local, global, k, key) if err != nil { return nil, err } diff --git a/runtime/equality.go b/runtime/equality.go index 7e7b7fe..848e7e4 100644 --- a/runtime/equality.go +++ b/runtime/equality.go @@ -7,13 +7,29 @@ package runtime import ( "reflect" - "github.com/ta2gch/iris/runtime/ilos/class" - "github.com/ta2gch/iris/runtime/ilos/instance" - "github.com/ta2gch/iris/runtime/environment" "github.com/ta2gch/iris/runtime/ilos" + "github.com/ta2gch/iris/runtime/ilos/class" + "github.com/ta2gch/iris/runtime/ilos/instance" ) +func isComparable(t reflect.Type) bool { + if t.Comparable() { + if t.Kind() == reflect.Interface { + return false + } + if t.Kind() == reflect.Struct { + for i := 0; i < t.NumField(); i++ { + if !isComparable(t.Field(i).Type) { + return false + } + } + } + return true + } + return false +} + // Eq tests whether obj1 and obj2 are same identical object. // They return t if the objects are the same; otherwise, they return nil. // Two objects are the same if there is no operation that could distinguish @@ -32,7 +48,7 @@ func Eq(_, _ *environment.Environment, obj1, obj2 ilos.Instance) (ilos.Instance, // them (without modifying them), and if modifying one would modify the other the same way. func Eql(_, _ *environment.Environment, obj1, obj2 ilos.Instance) (ilos.Instance, ilos.Instance) { t1, t2 := reflect.TypeOf(obj1), reflect.TypeOf(obj2) - if t1.Comparable() || t2.Comparable() { + if isComparable(t1) || isComparable(t2) { if obj1 == obj2 { return T, nil } diff --git a/runtime/ilos/instance/function.go b/runtime/ilos/instance/function.go index 2c9d4a6..06e175e 100644 --- a/runtime/ilos/instance/function.go +++ b/runtime/ilos/instance/function.go @@ -23,7 +23,7 @@ type Function struct { } func NewFunction(name ilos.Instance, function interface{}) ilos.Instance { - return &Function{name, function} + return Function{name, function} } func (Function) Class() ilos.Class { @@ -38,11 +38,11 @@ func (Function) SetSlotValue(key ilos.Instance, value ilos.Instance, _ ilos.Clas return false } -func (f *Function) String() string { +func (f Function) String() string { return fmt.Sprintf("#%v", f.Class()) } -func (f *Function) Apply(local, global *environment.Environment, arguments ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func (f Function) Apply(local, global *environment.Environment, arguments ...ilos.Instance) (ilos.Instance, ilos.Instance) { fv := reflect.ValueOf(f.function) ft := reflect.TypeOf(f.function) argv := []reflect.Value{reflect.ValueOf(local), reflect.ValueOf(global)} diff --git a/runtime/ilos/instance/list.go b/runtime/ilos/instance/list.go index 3934606..e2f8958 100644 --- a/runtime/ilos/instance/list.go +++ b/runtime/ilos/instance/list.go @@ -89,26 +89,28 @@ func (i *Cons) Slice() []ilos.Instance { type Null struct{} +var Nil = NewNull() + func NewNull() ilos.Instance { - return Null{} + return &Null{} } -func (Null) Class() ilos.Class { +func (*Null) Class() ilos.Class { return class.Null } -func (i Null) GetSlotValue(key ilos.Instance, _ ilos.Class) (ilos.Instance, bool) { +func (i *Null) GetSlotValue(key ilos.Instance, _ ilos.Class) (ilos.Instance, bool) { return nil, false } -func (i Null) SetSlotValue(key ilos.Instance, value ilos.Instance, _ ilos.Class) bool { +func (i *Null) SetSlotValue(key ilos.Instance, value ilos.Instance, _ ilos.Class) bool { return false } -func (Null) String() string { - return "nil" +func (*Null) String() string { + return "NIL" } -func (Null) Slice() []ilos.Instance { +func (*Null) Slice() []ilos.Instance { return []ilos.Instance{} } diff --git a/runtime/list_operations.go b/runtime/list_operations.go index 32cdaa9..a12e7b7 100644 --- a/runtime/list_operations.go +++ b/runtime/list_operations.go @@ -158,7 +158,7 @@ func Mapcar(local, global *environment.Environment, function, list1 ilos.Instanc for j, list := range lists { arguments[j] = list.(instance.List).Slice()[i] } - ret, err := function.(*instance.Function).Apply(local, global, arguments...) + ret, err := function.(instance.Function).Apply(local, global, arguments...) if err != nil { return nil, err } @@ -186,7 +186,7 @@ func Mapc(local, global *environment.Environment, function, list1 ilos.Instance, for j, list := range lists { arguments[j] = list.(instance.List).Slice()[i] } - if _, err := function.(*instance.Function).Apply(local, global, arguments...); err != nil { + if _, err := function.(instance.Function).Apply(local, global, arguments...); err != nil { return nil, err } } @@ -214,7 +214,7 @@ func Mapcan(local, global *environment.Environment, function, list1 ilos.Instanc for j, list := range lists { arguments[j] = list.(instance.List).Slice()[i] } - ret, err := function.(*instance.Function).Apply(local, global, arguments...) + ret, err := function.(instance.Function).Apply(local, global, arguments...) if err != nil { return nil, err } @@ -248,7 +248,7 @@ func Maplist(local, global *environment.Environment, function, list1 ilos.Instan return nil, err } } - ret, err := function.(*instance.Function).Apply(local, global, arguments...) + ret, err := function.(instance.Function).Apply(local, global, arguments...) if err != nil { return nil, err } @@ -280,7 +280,7 @@ func Mapl(local, global *environment.Environment, function, list1 ilos.Instance, return nil, err } } - if _, err := function.(*instance.Function).Apply(local, global, arguments...); err != nil { + if _, err := function.(instance.Function).Apply(local, global, arguments...); err != nil { return nil, err } } @@ -312,7 +312,7 @@ func Mapcon(local, global *environment.Environment, function, list1 ilos.Instanc return nil, err } } - ret, err := function.(*instance.Function).Apply(local, global, arguments...) + ret, err := function.(instance.Function).Apply(local, global, arguments...) if err != nil { return nil, err } diff --git a/runtime/sequence_functions.go b/runtime/sequence_functions.go index 02c0d85..1f745fe 100644 --- a/runtime/sequence_functions.go +++ b/runtime/sequence_functions.go @@ -204,7 +204,7 @@ func mapInto(local, global *environment.Environment, destination, function ilos. return nil, err } } - ret, err := function.(*instance.Function).Apply(local, global, arguments...) + ret, err := function.(instance.Function).Apply(local, global, arguments...) if err != nil { return nil, err } From 986d0df252cfc3752c6501bc2783ef57b8f24fb9 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Thu, 17 Aug 2017 08:50:27 +0900 Subject: [PATCH 188/228] Change env type --- runtime/array_operations.go | 32 +++++------ runtime/character_class.go | 30 +++++----- runtime/conditional_expressions.go | 8 +-- runtime/cons.go | 12 ++-- runtime/constants.go | 2 +- runtime/defining_operators.go | 8 +-- runtime/dynamic_variables.go | 6 +- runtime/environment/environment.go | 9 ++- runtime/equality.go | 6 +- runtime/eval.go | 21 ++++--- runtime/float_class.go | 12 ++-- runtime/functions.go | 17 +++--- runtime/ilos/instance/function.go | 4 +- runtime/integer_class.go | 16 +++--- runtime/iteration.go | 4 +- runtime/list_operations.go | 48 ++++++++-------- runtime/logical_connectives.go | 6 +- runtime/namedfunc.go | 6 +- runtime/non-local_exits.go | 14 ++--- runtime/null_class.go | 2 +- runtime/number_class.go | 90 +++++++++++++++--------------- runtime/sequence_functions.go | 16 +++--- runtime/sequencing_forms.go | 2 +- runtime/string_class.go | 38 ++++++------- runtime/symbol_class.go | 10 ++-- runtime/util.go | 2 +- runtime/variables.go | 6 +- runtime/vectors.go | 8 +-- 28 files changed, 219 insertions(+), 216 deletions(-) diff --git a/runtime/array_operations.go b/runtime/array_operations.go index 214d91b..1cc41b4 100644 --- a/runtime/array_operations.go +++ b/runtime/array_operations.go @@ -13,7 +13,7 @@ import ( // BasicArrayP returns t if obj is a basic-array (instance of class basic-array); // otherwise, returns nil. obj may be any ISLISP object. -func BasicArrayP(_, _ *environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { +func BasicArrayP(local, global environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { if instance.Of(class.BasicArray, obj) { return T, nil } @@ -22,7 +22,7 @@ func BasicArrayP(_, _ *environment.Environment, obj ilos.Instance) (ilos.Instanc // BasicArrayStarP returns t if obj is a basic-array* (instance of class ); // otherwise, returns nil. obj may be any ISLISP object. -func BasicArrayStarP(_, _ *environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { +func BasicArrayStarP(local, global environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { if instance.Of(class.BasicArrayStar, obj) { return T, nil } @@ -31,7 +31,7 @@ func BasicArrayStarP(_, _ *environment.Environment, obj ilos.Instance) (ilos.Ins // GeneralArrayStarP returns t if obj is a general-array* (instance of class ); // otherwise, returns nil. obj may be any ISLISP object. -func GeneralArrayStarP(_, _ *environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { +func GeneralArrayStarP(local, global environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { if instance.Of(class.GeneralArrayStar, obj) { return T, nil } @@ -52,7 +52,7 @@ func GeneralArrayStarP(_, _ *environment.Environment, obj ilos.Instance) (ilos.I // // An error shall be signaled if dimensions is not a proper list of non-negative integers // (error-id. domain-error). initial-element may be any ISLISP object -func CreateArray(_, _ *environment.Environment, dimensions ilos.Instance, initialElement ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func CreateArray(local, global environment.Environment, dimensions ilos.Instance, initialElement ...ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.List, dimensions); err != nil { return nil, err } @@ -72,11 +72,11 @@ func CreateArray(_, _ *environment.Environment, dimensions ilos.Instance, initia } array := make([]instance.GeneralArrayStar, int(dim[0].(instance.Integer))) for i := range array { - d, err := List(nil, nil, dim[1:]...) // TODO: replace UnsafeCdr + d, err := List(local, global, dim[1:]...) // TODO: replace UnsafeCdr if err != nil { return nil, err } - a, err := CreateArray(nil, nil, d, elt) + a, err := CreateArray(local, global, d, elt) if err != nil { return nil, err } @@ -93,7 +93,7 @@ func CreateArray(_, _ *environment.Environment, dimensions ilos.Instance, initia // // An error shall be signaled if basic-array is not a basic-array (error-id. domain-error). // An error shall be signaled if any z is not a non-negative integer (error-id. domain-error). -func Aref(_, _ *environment.Environment, basicArray ilos.Instance, dimensions ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Aref(local, global environment.Environment, basicArray ilos.Instance, dimensions ...ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.BasicArray, basicArray); err != nil { return nil, err } @@ -120,13 +120,13 @@ func Aref(_, _ *environment.Environment, basicArray ilos.Instance, dimensions .. } return basicArray.(instance.GeneralVector)[index], nil default: // General Array* - return Garef(nil, nil, basicArray, dimensions...) + return Garef(local, global, basicArray, dimensions...) } } // Garef is like aref but an error shall be signaled if its first argument, general-array, is // not an object of class general-vector or of class (error-id. domain-error). -func Garef(_, _ *environment.Environment, generalArray ilos.Instance, dimensions ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Garef(local, global environment.Environment, generalArray ilos.Instance, dimensions ...ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.GeneralArrayStar, generalArray); err != nil { return nil, err } @@ -150,7 +150,7 @@ func Garef(_, _ *environment.Environment, generalArray ilos.Instance, dimensions // SetAref replaces the object obtainable by aref or garef with obj . The returned value is obj. // The constraints on the basic-array, the general-array, and the sequence of indices z is the // same as for aref and garef. -func SetAref(_, _ *environment.Environment, obj, basicArray ilos.Instance, dimensions ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func SetAref(local, global environment.Environment, obj, basicArray ilos.Instance, dimensions ...ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.BasicArray, basicArray); err != nil { return nil, err } @@ -182,14 +182,14 @@ func SetAref(_, _ *environment.Environment, obj, basicArray ilos.Instance, dimen basicArray.(instance.GeneralVector)[index] = obj return obj, nil default: // General Array* - return SetGaref(nil, nil, obj, basicArray, dimensions...) + return SetGaref(local, global, obj, basicArray, dimensions...) } } // SetGaref replaces the object obtainable by aref or garef with obj . The returned value is obj. // The constraints on the basic-array, the general-array, and the sequence of indices z is the // same as for aref and garef. -func SetGaref(_, _ *environment.Environment, obj, generalArray ilos.Instance, dimensions ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func SetGaref(local, global environment.Environment, obj, generalArray ilos.Instance, dimensions ...ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.GeneralArrayStar, generalArray); err != nil { return nil, err } @@ -214,15 +214,15 @@ func SetGaref(_, _ *environment.Environment, obj, generalArray ilos.Instance, di // ArrayDimensions returns a list of the dimensions of a given basic-array. // An error shall be signaled if basic-array is not a basic-array (error-id. domain-error). // The consequences are undefined if the returned list is modified. -func ArrayDimensions(_, _ *environment.Environment, basicArray ilos.Instance) (ilos.Instance, ilos.Instance) { +func ArrayDimensions(local, global environment.Environment, basicArray ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.BasicArray, basicArray); err != nil { return nil, err } switch { case instance.Of(class.String, basicArray): - return List(nil, nil, instance.NewInteger(len(basicArray.(instance.String)))) + return List(local, global, instance.NewInteger(len(basicArray.(instance.String)))) case instance.Of(class.GeneralVector, basicArray): - return List(nil, nil, instance.NewInteger(len(basicArray.(instance.GeneralVector)))) + return List(local, global, instance.NewInteger(len(basicArray.(instance.GeneralVector)))) default: // General Array* var array instance.GeneralArrayStar dimensions := []ilos.Instance{} @@ -230,6 +230,6 @@ func ArrayDimensions(_, _ *environment.Environment, basicArray ilos.Instance) (i dimensions = append(dimensions, instance.NewInteger(len(array.Vector))) array = array.Vector[0] } - return List(nil, nil, dimensions...) + return List(local, global, dimensions...) } } diff --git a/runtime/character_class.go b/runtime/character_class.go index cef8b89..92195fd 100644 --- a/runtime/character_class.go +++ b/runtime/character_class.go @@ -13,7 +13,7 @@ import ( // Characterp returns t if obj is a character (instance of class character); // otherwise, returns nil. obj may be any ISLISP object. -func Characterp(_, _ *environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { +func Characterp(local, global environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { if instance.Of(class.Character, obj) { return T, nil } @@ -21,7 +21,7 @@ func Characterp(_, _ *environment.Environment, obj ilos.Instance) (ilos.Instance } // CharEqual tests whether char1 is the same character as char2. -func CharEqual(_, _ *environment.Environment, char1, char2 ilos.Instance) (ilos.Instance, ilos.Instance) { +func CharEqual(local, global environment.Environment, char1, char2 ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Character, char1, char2); err != nil { return nil, err } @@ -32,17 +32,17 @@ func CharEqual(_, _ *environment.Environment, char1, char2 ilos.Instance) (ilos. } // CharNotEqual if and only if they are not char=. -func CharNotEqual(_, _ *environment.Environment, char1, char2 ilos.Instance) (ilos.Instance, ilos.Instance) { - ret, err := CharEqual(nil, nil, char1, char2) +func CharNotEqual(local, global environment.Environment, char1, char2 ilos.Instance) (ilos.Instance, ilos.Instance) { + ret, err := CharEqual(local, global, char1, char2) if err != nil { return nil, err } - return Not(nil, nil, ret) + return Not(local, global, ret) } // CharGreaterThan tests whether char1 is greater than char2. // An error shall be signaled if either char1 or char2 is not a character (error-id. domain-error). -func CharGreaterThan(_, _ *environment.Environment, char1, char2 ilos.Instance) (ilos.Instance, ilos.Instance) { +func CharGreaterThan(local, global environment.Environment, char1, char2 ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Character, char1, char2); err != nil { return nil, err } @@ -54,12 +54,12 @@ func CharGreaterThan(_, _ *environment.Environment, char1, char2 ilos.Instance) // CharGreaterThanOrEqual tests whether char1 is greater than or equal to char2. // An error shall be signaled if either char1 or char2 is not a character (error-id. domain-error). -func CharGreaterThanOrEqual(_, _ *environment.Environment, char1, char2 ilos.Instance) (ilos.Instance, ilos.Instance) { - gt, err := CharGreaterThan(nil, nil, char1, char2) +func CharGreaterThanOrEqual(local, global environment.Environment, char1, char2 ilos.Instance) (ilos.Instance, ilos.Instance) { + gt, err := CharGreaterThan(local, global, char1, char2) if err != nil { return nil, err } - eq, err := CharEqual(nil, nil, char1, char2) + eq, err := CharEqual(local, global, char1, char2) if err != nil { return nil, err } @@ -71,20 +71,20 @@ func CharGreaterThanOrEqual(_, _ *environment.Environment, char1, char2 ilos.Ins // CharLessThan tests whether char1 is less than char2. // An error shall be signaled if either char1 or char2 is not a character (error-id. domain-error). -func CharLessThan(_, _ *environment.Environment, char1, char2 ilos.Instance) (ilos.Instance, ilos.Instance) { - gt, err := CharGreaterThanOrEqual(nil, nil, char1, char2) +func CharLessThan(local, global environment.Environment, char1, char2 ilos.Instance) (ilos.Instance, ilos.Instance) { + gt, err := CharGreaterThanOrEqual(local, global, char1, char2) if err != nil { return nil, err } - return Not(nil, nil, gt) + return Not(local, global, gt) } // CharLessThanOrEqual tests whether char1 is less than or equal to char2. // An error shall be signaled if either char1 or char2 is not a character (error-id. domain-error). -func CharLessThanOrEqual(_, _ *environment.Environment, char1, char2 ilos.Instance) (ilos.Instance, ilos.Instance) { - gt, err := CharGreaterThan(nil, nil, char1, char2) +func CharLessThanOrEqual(local, global environment.Environment, char1, char2 ilos.Instance) (ilos.Instance, ilos.Instance) { + gt, err := CharGreaterThan(local, global, char1, char2) if err != nil { return nil, err } - return Not(nil, nil, gt) + return Not(local, global, gt) } diff --git a/runtime/conditional_expressions.go b/runtime/conditional_expressions.go index 6d8422b..9aae43b 100644 --- a/runtime/conditional_expressions.go +++ b/runtime/conditional_expressions.go @@ -18,7 +18,7 @@ import ( // is evaluated and its value is returned. // // If no else-form is provided, it defaults to nil. -func If(local, global *environment.Environment, testForm, thenForm ilos.Instance, elseForm ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func If(local, global environment.Environment, testForm, thenForm ilos.Instance, elseForm ...ilos.Instance) (ilos.Instance, ilos.Instance) { tf, err := Eval(local, global, testForm) if err != nil { return nil, err @@ -41,7 +41,7 @@ func If(local, global *environment.Environment, testForm, thenForm ilos.Instance //are sequentially evaluated and the value of the last one is returned. // If no test is true, then nil is returned. // If no form exists for the successful test then the value of this test is returned. -func Cond(local, global *environment.Environment, testFrom ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Cond(local, global environment.Environment, testFrom ...ilos.Instance) (ilos.Instance, ilos.Instance) { for _, tf := range testFrom { if err := ensure(class.List, tf); err != nil { return nil, err @@ -74,7 +74,7 @@ func Cond(local, global *environment.Environment, testFrom ...ilos.Instance) (il // the value returned by keyform and key. If no form exists for a matching key, the case form evaluates to nil. // If the value of keyform is different from every key, and there is a default clause, its forms, if any, // are evaluated sequentially, and the value of the last one is the result of the case form. -func Case(local, global *environment.Environment, key ilos.Instance, pattern ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Case(local, global environment.Environment, key ilos.Instance, pattern ...ilos.Instance) (ilos.Instance, ilos.Instance) { key, err := Eval(local, global, key) if err != nil { return nil, err @@ -118,7 +118,7 @@ func Case(local, global *environment.Environment, key ilos.Instance, pattern ... // the value returned by keyform and key. If no form exists for a matching key, the case form evaluates to nil. // If the value of keyform is different from every key, and there is a default clause, its forms, if any, // are evaluated sequentially, and the value of the last one is the result of the case form. -func CaseUsing(local, global *environment.Environment, key, pred ilos.Instance, pattern ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func CaseUsing(local, global environment.Environment, key, pred ilos.Instance, pattern ...ilos.Instance) (ilos.Instance, ilos.Instance) { key, err := Eval(local, global, key) if err != nil { return nil, err diff --git a/runtime/cons.go b/runtime/cons.go index 1ef4325..b07e967 100644 --- a/runtime/cons.go +++ b/runtime/cons.go @@ -13,7 +13,7 @@ import ( // Consp returns t if obj is a cons (instance of class cons); // otherwise, returns nil. obj may be any ISLISP object. -func Consp(_, _ *environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { +func Consp(local, global environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { if instance.Of(class.Cons, obj) { return T, nil } @@ -25,13 +25,13 @@ func Consp(_, _ *environment.Environment, obj ilos.Instance) (ilos.Instance, ilo // An error shall be signaled if the requested cons cannot // be allocated (error-id. cannot-create-cons). Both obj1 // and obj2 may be any ISLISP object. -func Cons(_, _ *environment.Environment, obj1, obj2 ilos.Instance) (ilos.Instance, ilos.Instance) { +func Cons(local, global environment.Environment, obj1, obj2 ilos.Instance) (ilos.Instance, ilos.Instance) { return instance.NewCons(obj1, obj2), nil } // Car returns the left component of the cons. // An error shall be signaled if cons is not a cons (error-id. domain-error). -func Car(_, _ *environment.Environment, cons ilos.Instance) (ilos.Instance, ilos.Instance) { +func Car(local, global environment.Environment, cons ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Cons, cons); err != nil { return nil, err } @@ -40,7 +40,7 @@ func Car(_, _ *environment.Environment, cons ilos.Instance) (ilos.Instance, ilos // Cdr returns the right component of the cons. // An error shall be signaled if cons is not a cons (error-id. domain-error). -func Cdr(_, _ *environment.Environment, cons ilos.Instance) (ilos.Instance, ilos.Instance) { +func Cdr(local, global environment.Environment, cons ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Cons, cons); err != nil { return nil, err } @@ -52,7 +52,7 @@ func Cdr(_, _ *environment.Environment, cons ilos.Instance) (ilos.Instance, ilos // SetCar updates the left component of cons with obj. The returned value is obj . // An error shall be signaled if cons is not a cons (error-id. domain-error). // obj may be any ISLISP object. -func SetCar(_, _ *environment.Environment, obj, cons ilos.Instance) (ilos.Instance, ilos.Instance) { +func SetCar(local, global environment.Environment, obj, cons ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Cons, cons); err != nil { return nil, err } @@ -65,7 +65,7 @@ func SetCar(_, _ *environment.Environment, obj, cons ilos.Instance) (ilos.Instan // SetCdr updates the right component of cons with obj. The returned value is obj . // An error shall be signaled if cons is not a cons (error-id. domain-error). // obj may be any ISLISP object. -func SetCdr(_, _ *environment.Environment, obj, cons ilos.Instance) (ilos.Instance, ilos.Instance) { +func SetCdr(local, global environment.Environment, obj, cons ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Cons, cons); err != nil { return nil, err } diff --git a/runtime/constants.go b/runtime/constants.go index 7a9271b..de564bf 100644 --- a/runtime/constants.go +++ b/runtime/constants.go @@ -11,6 +11,6 @@ import ( // Quote is used to include any object in an ISLisp text. // A quoted expression denotes a reference to an object. -func Quote(local, global *environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { +func Quote(local, global environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { return obj, nil } diff --git a/runtime/defining_operators.go b/runtime/defining_operators.go index 66239ee..8a71fdf 100644 --- a/runtime/defining_operators.go +++ b/runtime/defining_operators.go @@ -20,7 +20,7 @@ import ( // The result of the evaluation of form is bound to the variable named by name. The binding and // the object created as the result of evaluating the second argument are immutable. The symbol named // name is returned. -func Defconstant(local, global *environment.Environment, name, form ilos.Instance) (ilos.Instance, ilos.Instance) { +func Defconstant(local, global environment.Environment, name, form ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Symbol, name); err != nil { return nil, err } @@ -41,7 +41,7 @@ func Defconstant(local, global *environment.Environment, name, form ilos.Instanc // // A lexical variable binding for name can still be locally established by a binding form; in that // case, the local binding lexically shadows the outer binding of name defined by defglobal. -func Defglobal(local, global *environment.Environment, name, form ilos.Instance) (ilos.Instance, ilos.Instance) { +func Defglobal(local, global environment.Environment, name, form ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Symbol, name); err != nil { return nil, err } @@ -60,7 +60,7 @@ func Defglobal(local, global *environment.Environment, name, form ilos.Instance) // The scope of name is the entire current toplevel scope except the body form. // //The symbol named name is returned. -func Defdynamic(local, global *environment.Environment, name, form ilos.Instance) (ilos.Instance, ilos.Instance) { +func Defdynamic(local, global environment.Environment, name, form ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Symbol, name); err != nil { return nil, err } @@ -85,7 +85,7 @@ func Defdynamic(local, global *environment.Environment, name, form ilos.Instance // defun returns the function name which is the symbol named function-name. The free identifiers in // the body form* (i.e., those which are not contained in the lambda list) follow the rules of lexical // scoping. -func Defun(local, global *environment.Environment, functionName, lambdaList ilos.Instance, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Defun(local, global environment.Environment, functionName, lambdaList ilos.Instance, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Symbol, functionName); err != nil { return nil, err } diff --git a/runtime/dynamic_variables.go b/runtime/dynamic_variables.go index 1eefc03..b286fdb 100644 --- a/runtime/dynamic_variables.go +++ b/runtime/dynamic_variables.go @@ -21,7 +21,7 @@ import ( // returned that was established most recently and is still in effect. An // error shall be signaled if such a binding does not exist // (error-id. unbound-variable). -func Dynamic(local, global *environment.Environment, var1 ilos.Instance) (ilos.Instance, ilos.Instance) { +func Dynamic(local, global environment.Environment, var1 ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Symbol, var1); err != nil { return nil, err } @@ -43,7 +43,7 @@ func Dynamic(local, global *environment.Environment, var1 ilos.Instance) (ilos.I // An error shall be signaled if var has no dynamic value // (error-id. unbound-variable). setf of dynamic can be used only for // modifying bindings, and not for establishing them. -func SetDynamic(local, global *environment.Environment, form, var1 ilos.Instance) (ilos.Instance, ilos.Instance) { +func SetDynamic(local, global environment.Environment, form, var1 ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Symbol, var1); err != nil { return nil, err } @@ -77,7 +77,7 @@ func SetDynamic(local, global *environment.Environment, form, var1 ilos.Instance // returned value of dynamic-let is that of the last body-form of the body (or // nil if there is none). The bindings are undone when control leaves the // prepared dynamic-let special form. -func DynamicLet(local, global *environment.Environment, varForm ilos.Instance, bodyForm ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func DynamicLet(local, global environment.Environment, varForm ilos.Instance, bodyForm ...ilos.Instance) (ilos.Instance, ilos.Instance) { vfs := map[ilos.Instance]ilos.Instance{} if err := ensure(class.List, varForm); err != nil { return nil, err diff --git a/runtime/environment/environment.go b/runtime/environment/environment.go index 56f4b07..39eb626 100644 --- a/runtime/environment/environment.go +++ b/runtime/environment/environment.go @@ -20,7 +20,7 @@ type Environment struct { } // New creates new environment -func New() *Environment { +func New() Environment { env := new(Environment) env.BlockTag = newStack() env.TagbodyTag = newStack() @@ -31,12 +31,12 @@ func New() *Environment { env.Variable = newStack() env.DynamicVariable = newStack() env.Constant = newStack() - env.GensymID = 0 + env.GensymID = 0 // Will Not Worked env.Property = mmap{} - return env + return *env } -func (env *Environment) Merge(before *Environment) *Environment { +func (env *Environment) Merge(before Environment) { env.BlockTag = append(before.BlockTag, env.BlockTag...) env.TagbodyTag = append(before.TagbodyTag, env.TagbodyTag...) env.CatchTag = append(before.CatchTag, env.CatchTag...) @@ -48,7 +48,6 @@ func (env *Environment) Merge(before *Environment) *Environment { env.Constant = append(before.Constant, env.Constant...) env.GensymID = before.GensymID env.Property = before.Property - return env } // TopLevel is a global environment diff --git a/runtime/equality.go b/runtime/equality.go index 848e7e4..077f352 100644 --- a/runtime/equality.go +++ b/runtime/equality.go @@ -34,7 +34,7 @@ func isComparable(t reflect.Type) bool { // They return t if the objects are the same; otherwise, they return nil. // Two objects are the same if there is no operation that could distinguish // them (without modifying them), and if modifying one would modify the other the same way. -func Eq(_, _ *environment.Environment, obj1, obj2 ilos.Instance) (ilos.Instance, ilos.Instance) { +func Eq(local, global environment.Environment, obj1, obj2 ilos.Instance) (ilos.Instance, ilos.Instance) { v1, v2 := reflect.ValueOf(obj1), reflect.ValueOf(obj2) if v1 == v2 || instance.Of(class.Symbol, obj1) && instance.Of(class.Symbol, obj2) && obj1 == obj2 { return T, nil @@ -46,7 +46,7 @@ func Eq(_, _ *environment.Environment, obj1, obj2 ilos.Instance) (ilos.Instance, // They return t if the objects are the same; otherwise, they return nil. // Two objects are the same if there is no operation that could distinguish // them (without modifying them), and if modifying one would modify the other the same way. -func Eql(_, _ *environment.Environment, obj1, obj2 ilos.Instance) (ilos.Instance, ilos.Instance) { +func Eql(local, global environment.Environment, obj1, obj2 ilos.Instance) (ilos.Instance, ilos.Instance) { t1, t2 := reflect.TypeOf(obj1), reflect.TypeOf(obj2) if isComparable(t1) || isComparable(t2) { if obj1 == obj2 { @@ -66,7 +66,7 @@ func Eql(_, _ *environment.Environment, obj1, obj2 ilos.Instance) (ilos.Instance // Specifically: // // If obj1 and obj2 are direct instances of the same class, equal returns t if they are eql. -func Equal(_, _ *environment.Environment, obj1, obj2 ilos.Instance) (ilos.Instance, ilos.Instance) { +func Equal(local, global environment.Environment, obj1, obj2 ilos.Instance) (ilos.Instance, ilos.Instance) { if reflect.DeepEqual(obj1, obj2) { return T, nil } diff --git a/runtime/eval.go b/runtime/eval.go index 68b5730..3522c35 100644 --- a/runtime/eval.go +++ b/runtime/eval.go @@ -5,13 +5,14 @@ package runtime import ( + "github.com/k0kubun/pp" "github.com/ta2gch/iris/runtime/environment" "github.com/ta2gch/iris/runtime/ilos" "github.com/ta2gch/iris/runtime/ilos/class" "github.com/ta2gch/iris/runtime/ilos/instance" ) -func evalArguments(local, global *environment.Environment, arguments ilos.Instance) (ilos.Instance, ilos.Instance) { +func evalArguments(local, global environment.Environment, arguments ilos.Instance) (ilos.Instance, ilos.Instance) { // if arguments ends here if arguments == Nil { return Nil, nil @@ -33,7 +34,7 @@ func evalArguments(local, global *environment.Environment, arguments ilos.Instan } -func evalLambda(local, global *environment.Environment, car, cdr ilos.Instance) (ilos.Instance, ilos.Instance, bool) { +func evalLambda(local, global environment.Environment, car, cdr ilos.Instance) (ilos.Instance, ilos.Instance, bool) { // eval if lambda form if instance.Of(class.Cons, car) { caar := car.(*instance.Cons).Car // Checked at the top of// This sentence @@ -60,14 +61,15 @@ func evalLambda(local, global *environment.Environment, car, cdr ilos.Instance) return nil, nil, false } -func evalSpecial(local, global *environment.Environment, car, cdr ilos.Instance) (ilos.Instance, ilos.Instance, bool) { +func evalSpecial(local, global environment.Environment, car, cdr ilos.Instance) (ilos.Instance, ilos.Instance, bool) { // get special instance has value of Function interface var spl ilos.Instance if s, ok := global.Special.Get(car); ok { spl = s } if spl != nil { - env := environment.New().Merge(local) + env := environment.New() + env.Merge(local) ret, err := spl.(instance.Applicable).Apply(env, global, cdr.(instance.List).Slice()...) if err != nil { return nil, err, true @@ -77,7 +79,7 @@ func evalSpecial(local, global *environment.Environment, car, cdr ilos.Instance) return nil, nil, false } -func evalMacro(local, global *environment.Environment, car, cdr ilos.Instance) (ilos.Instance, ilos.Instance, bool) { +func evalMacro(local, global environment.Environment, car, cdr ilos.Instance) (ilos.Instance, ilos.Instance, bool) { // get special instance has value of Function interface var mac ilos.Instance if m, ok := local.Macro.Get(car); ok { @@ -103,7 +105,7 @@ func evalMacro(local, global *environment.Environment, car, cdr ilos.Instance) ( return nil, nil, false } -func evalFunction(local, global *environment.Environment, car, cdr ilos.Instance) (ilos.Instance, ilos.Instance, bool) { +func evalFunction(local, global environment.Environment, car, cdr ilos.Instance) (ilos.Instance, ilos.Instance, bool) { // get special instance has value of Function interface var fun ilos.Instance if f, ok := global.Function.Get(car); ok { @@ -129,7 +131,7 @@ func evalFunction(local, global *environment.Environment, car, cdr ilos.Instance return nil, nil, false } -func evalCons(local, global *environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { +func evalCons(local, global environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Cons, obj); err != nil { return nil, err } @@ -152,10 +154,11 @@ func evalCons(local, global *environment.Environment, obj ilos.Instance) (ilos.I if a, b, c := evalFunction(local, global, car, cdr); c { return a, b } + pp.Println(global, local) return nil, instance.NewUndefinedFunction(car) } -func evalVariable(local, global *environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { +func evalVariable(local, global environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { if val, ok := local.Variable.Get(obj); ok { return val, nil } @@ -169,7 +172,7 @@ func evalVariable(local, global *environment.Environment, obj ilos.Instance) (il } // Eval evaluates any classs -func Eval(local, global *environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { +func Eval(local, global environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { if obj == Nil { return Nil, nil } diff --git a/runtime/float_class.go b/runtime/float_class.go index 5004e75..f70ccfd 100644 --- a/runtime/float_class.go +++ b/runtime/float_class.go @@ -25,7 +25,7 @@ var ( // Floatp returns t if obj is a float (instance of class float); // otherwise, returns nil. The obj may be any ISLISP object. -func Floatp(_, _ *environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { +func Floatp(local, global environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { if instance.Of(class.Float, obj) { return T, nil } @@ -35,7 +35,7 @@ func Floatp(_, _ *environment.Environment, obj ilos.Instance) (ilos.Instance, il // Float returns x itself if it is an instance of the class float // and returns a floating-point approximation of x otherwise. // An error shall be signaled if x is not a number (error-id. domain-error). -func Float(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { +func Float(local, global environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { f, _, err := convFloat64(x) if err != nil { return nil, err @@ -46,7 +46,7 @@ func Float(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos. // Floor returns the greatest integer less than or equal to x . // That is, x is truncated towards negative infinity. An error // shall be signaled if x is not a number (error-id. domain-error). -func Floor(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { +func Floor(local, global environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { f, _, err := convFloat64(x) if err != nil { return nil, err @@ -57,7 +57,7 @@ func Floor(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos. // Ceiling Returns the smallest integer that is not smaller than x. // That is, x is truncated towards positive infinity. An error // shall be signaled if x is not a number (error-id. domain-error). -func Ceiling(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { +func Ceiling(local, global environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { f, _, err := convFloat64(x) if err != nil { return nil, err @@ -68,7 +68,7 @@ func Ceiling(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilo // Truncate returns the integer between 0 and x (inclusive) that is nearest to x. // That is, x is truncated towards zero. An error shall be signaled // if x is not a number (error-id. domain-error). -func Truncate(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { +func Truncate(local, global environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { f, _, err := convFloat64(x) if err != nil { return nil, err @@ -79,7 +79,7 @@ func Truncate(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, il // Round returns the integer nearest to x. // If x is exactly halfway between two integers, the even one is chosen. // An error shall be signaled if x is not a number (error-id. domain-error). -func Round(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { +func Round(local, global environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { f, _, err := convFloat64(x) if err != nil { return nil, err diff --git a/runtime/functions.go b/runtime/functions.go index a9dd8d8..6f9629b 100644 --- a/runtime/functions.go +++ b/runtime/functions.go @@ -19,7 +19,7 @@ import ( // A function binding is an association between an identifier, function-name, // and a function object that is denoted by function-name—if in operator // position—or by (function function-name) elsewhere. -func Functionp(local, global *environment.Environment, fun ilos.Instance) (ilos.Instance, ilos.Instance) { +func Functionp(local, global environment.Environment, fun ilos.Instance) (ilos.Instance, ilos.Instance) { if instance.Of(class.Function, fun) { return T, nil } @@ -31,7 +31,7 @@ func Functionp(local, global *environment.Environment, fun ilos.Instance) (ilos. // An error shall be signaled if no binding has been established for the identifier // in the function namespace of current lexical environment (error-id. undefined-function). // The consequences are undefined if the function-name names a macro or special form -func Function(local, global *environment.Environment, fun ilos.Instance) (ilos.Instance, ilos.Instance) { +func Function(local, global environment.Environment, fun ilos.Instance) (ilos.Instance, ilos.Instance) { // car must be a symbol if err := ensure(class.Symbol, fun); err != nil { return nil, err @@ -69,7 +69,7 @@ func Function(local, global *environment.Environment, fun ilos.Instance) (ilos.I // was called with apply and R corresponds to the final argument, L2 , to that call // to apply (or some subtail of L2), in which case it is implementation defined whether // L1 shares structure with L2 . -func Lambda(local, global *environment.Environment, lambdaList ilos.Instance, form ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Lambda(local, global environment.Environment, lambdaList ilos.Instance, form ...ilos.Instance) (ilos.Instance, ilos.Instance) { if err := checkLambdaList(lambdaList); err != nil { return nil, err } @@ -99,7 +99,7 @@ func Lambda(local, global *environment.Environment, lambdaList ilos.Instance, fo // (or nil if there is none) is the value returned by the special form activation. // // No function-name may appear more than once in the function bindings. -func Labels(local, global *environment.Environment, functions ilos.Instance, bodyForm ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Labels(local, global environment.Environment, functions ilos.Instance, bodyForm ...ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.List, functions); err != nil { return nil, err } @@ -127,11 +127,12 @@ func Labels(local, global *environment.Environment, functions ilos.Instance, bod // Flet special form allow the definition of new identifiers in the function // namespace for function objects (see Labels). -func Flet(local, global *environment.Environment, functions ilos.Instance, bodyForm ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Flet(local, global environment.Environment, functions ilos.Instance, bodyForm ...ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.List, functions); err != nil { return nil, err } - env := environment.New().Merge(local) + env := environment.New() + env.Merge(local) for _, function := range functions.(instance.List).Slice() { if err := ensure(class.List, function); err != nil { return nil, err @@ -160,7 +161,7 @@ func Flet(local, global *environment.Environment, functions ilos.Instance, bodyF // An error shall be signaled if function is not a function (error-id. domain-error). // Each obj may be any ISLISP object. An error shall be signaled // if list is not a proper list (error-id. improper-argument-list). -func Apply(local, global *environment.Environment, function ilos.Instance, obj ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Apply(local, global environment.Environment, function ilos.Instance, obj ...ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Function, function); err != nil { return nil, err } @@ -176,7 +177,7 @@ func Apply(local, global *environment.Environment, function ilos.Instance, obj . // // An error shall be signaled if function is not a function (error-id. domain-error). // Each obj may be any ISLISP object. -func Funcall(local, global *environment.Environment, function ilos.Instance, obj ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Funcall(local, global environment.Environment, function ilos.Instance, obj ...ilos.Instance) (ilos.Instance, ilos.Instance) { obj = append(obj, Nil) return Apply(local, global, function, obj...) } diff --git a/runtime/ilos/instance/function.go b/runtime/ilos/instance/function.go index 06e175e..b4fbd21 100644 --- a/runtime/ilos/instance/function.go +++ b/runtime/ilos/instance/function.go @@ -14,7 +14,7 @@ import ( ) type Applicable interface { - Apply(*environment.Environment, *environment.Environment, ...ilos.Instance) (ilos.Instance, ilos.Instance) + Apply(environment.Environment, environment.Environment, ...ilos.Instance) (ilos.Instance, ilos.Instance) } type Function struct { @@ -42,7 +42,7 @@ func (f Function) String() string { return fmt.Sprintf("#%v", f.Class()) } -func (f Function) Apply(local, global *environment.Environment, arguments ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func (f Function) Apply(local, global environment.Environment, arguments ...ilos.Instance) (ilos.Instance, ilos.Instance) { fv := reflect.ValueOf(f.function) ft := reflect.TypeOf(f.function) argv := []reflect.Value{reflect.ValueOf(local), reflect.ValueOf(global)} diff --git a/runtime/integer_class.go b/runtime/integer_class.go index 62ee235..0b09a99 100644 --- a/runtime/integer_class.go +++ b/runtime/integer_class.go @@ -22,7 +22,7 @@ func convInt(z ilos.Instance) (int, ilos.Instance) { // Integerp returns t if obj is an integer (instance of class integer); // otherwise, returns nil. obj may be any ISLISP object. -func Integerp(_, _ *environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { +func Integerp(local, global environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { if instance.Of(class.Integer, obj) { return T, nil } @@ -31,7 +31,7 @@ func Integerp(_, _ *environment.Environment, obj ilos.Instance) (ilos.Instance, // Div returns the greatest integer less than or equal to the quotient of z1 and z2. // An error shall be signaled if z2 is zero (error-id. division-by-zero). -func Div(_, _ *environment.Environment, z1, z2 ilos.Instance) (ilos.Instance, ilos.Instance) { +func Div(local, global environment.Environment, z1, z2 ilos.Instance) (ilos.Instance, ilos.Instance) { a, err := convInt(z1) if err != nil { return nil, err @@ -42,7 +42,7 @@ func Div(_, _ *environment.Environment, z1, z2 ilos.Instance) (ilos.Instance, il } if b == 0 { operation := instance.NewSymbol("DIV") - operands, err := List(nil, nil, z1, z2) + operands, err := List(local, global, z1, z2) if err != nil { return nil, err } @@ -57,7 +57,7 @@ func Div(_, _ *environment.Environment, z1, z2 ilos.Instance) (ilos.Instance, il // and this result is divisible by z2 without remainder. // // An error shall be signaled if either z1 or z2 is not an integer (error-id. domain-error). -func Mod(_, _ *environment.Environment, z1, z2 ilos.Instance) (ilos.Instance, ilos.Instance) { +func Mod(local, global environment.Environment, z1, z2 ilos.Instance) (ilos.Instance, ilos.Instance) { a, err := convInt(z1) if err != nil { return nil, err @@ -68,7 +68,7 @@ func Mod(_, _ *environment.Environment, z1, z2 ilos.Instance) (ilos.Instance, il } if b == 0 { operation := instance.NewSymbol("MOD") - operands, err := List(nil, nil, z1, z2) + operands, err := List(local, global, z1, z2) if err != nil { return nil, err } @@ -84,7 +84,7 @@ func Mod(_, _ *environment.Environment, z1, z2 ilos.Instance) (ilos.Instance, il // // An error shall be signaled if either z1 or z2 is not an integer // (error-id. domain-error). -func Gcd(_, _ *environment.Environment, z1, z2 ilos.Instance) (ilos.Instance, ilos.Instance) { +func Gcd(local, global environment.Environment, z1, z2 ilos.Instance) (ilos.Instance, ilos.Instance) { gcd := func(x, y int) int { for y != 0 { x, y = y, x%y @@ -106,7 +106,7 @@ func Gcd(_, _ *environment.Environment, z1, z2 ilos.Instance) (ilos.Instance, il // // An error shall be signaled if either z1 or z2 is not an integer // (error-id. domain-error). -func Lcm(_, _ *environment.Environment, z1, z2 ilos.Instance) (ilos.Instance, ilos.Instance) { +func Lcm(local, global environment.Environment, z1, z2 ilos.Instance) (ilos.Instance, ilos.Instance) { gcd := func(x, y int) int { for y != 0 { x, y = y, x%y @@ -127,7 +127,7 @@ func Lcm(_, _ *environment.Environment, z1, z2 ilos.Instance) (ilos.Instance, il // Isqrt Returns the greatest integer less than or equal to // the exact positive square root of z . An error shall be signaled // if z is not a non-negative integer (error-id. domain-error). -func Isqrt(_, _ *environment.Environment, z ilos.Instance) (ilos.Instance, ilos.Instance) { +func Isqrt(local, global environment.Environment, z ilos.Instance) (ilos.Instance, ilos.Instance) { a, err := convInt(z) if err != nil { return nil, err diff --git a/runtime/iteration.go b/runtime/iteration.go index b21996b..6254c83 100644 --- a/runtime/iteration.go +++ b/runtime/iteration.go @@ -20,7 +20,7 @@ import ( // 3. Otherwise, if Vt is non-nil, the forms body-form* are evaluated sequentially (from left to right). // // 4. Upon successful completion of the body-forms*, the while form begins again with step 1. -func While(local, global *environment.Environment, testForm ilos.Instance, bodyForm ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func While(local, global environment.Environment, testForm ilos.Instance, bodyForm ...ilos.Instance) (ilos.Instance, ilos.Instance) { test, err := Eval(local, global, testForm) if err != nil { return nil, err @@ -55,7 +55,7 @@ func While(local, global *environment.Environment, testForm ilos.Instance, bodyF // order from left to right. Then their values are assigned to the corresponding variables and the next iteration begins. // If end-test returns a non-nil value, then the result * are evaluated sequentially and the value of the // last one is returned as value of the whole for macro. If no result is present, then the value of the for macro is nil. -func For(local, global *environment.Environment, iterationSpecs, endTestAndResults ilos.Instance, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func For(local, global environment.Environment, iterationSpecs, endTestAndResults ilos.Instance, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.List, iterationSpecs); err != nil { return nil, err } diff --git a/runtime/list_operations.go b/runtime/list_operations.go index a12e7b7..b20a75a 100644 --- a/runtime/list_operations.go +++ b/runtime/list_operations.go @@ -15,7 +15,7 @@ import ( // Listp returns t if obj is a list (instance of class list); otherwise, returns nil. // obj may be any ISLISP object. -func Listp(_, _ *environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { +func Listp(local, global environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { if instance.Of(class.Cons, obj) { return T, nil } @@ -27,7 +27,7 @@ func Listp(_, _ *environment.Environment, obj ilos.Instance) (ilos.Instance, ilo // error shall be signaled if the requested list cannot be allocated (error-id. cannot-create-list). // An error shall be signaled if i is not a non-negative integer (error-id. domain-error). //initial-element may be any ISLISP object. -func CreateList(_, _ *environment.Environment, i ilos.Instance, initialElement ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func CreateList(local, global environment.Environment, i ilos.Instance, initialElement ...ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Integer, i); err != nil { return nil, err } @@ -48,7 +48,7 @@ func CreateList(_, _ *environment.Environment, i ilos.Instance, initialElement . // List returns a new list whose length is the number of arguments and whose elements are the // arguments in the same order as in the list-form. An error shall be signaled if the requested list // cannot be allocated (error-id. cannot-create-list). Each obj may be any ISLISP object. -func List(_, _ *environment.Environment, objs ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func List(local, global environment.Environment, objs ...ilos.Instance) (ilos.Instance, ilos.Instance) { cons := Nil for i := len(objs) - 1; i >= 0; i-- { cons = instance.NewCons(objs[i], cons) @@ -61,7 +61,7 @@ func List(_, _ *environment.Environment, objs ...ilos.Instance) (ilos.Instance, // // For reverse, no side-effect to the given list occurs. The resulting list is permitted but not // required to share structure with the input list. -func Reverse(_, _ *environment.Environment, list ilos.Instance) (ilos.Instance, ilos.Instance) { +func Reverse(local, global environment.Environment, list ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.List, list); err != nil { return nil, err } @@ -78,7 +78,7 @@ func Reverse(_, _ *environment.Environment, list ilos.Instance) (ilos.Instance, // For nreverse, the conses which make up the top level of the given list are permitted, but not // required, to be side-effected in order to produce this new list. nreverse should never be called // on a literal object. -func Nreverse(_, _ *environment.Environment, list ilos.Instance) (ilos.Instance, ilos.Instance) { +func Nreverse(local, global environment.Environment, list ilos.Instance) (ilos.Instance, ilos.Instance) { // TODO: tests literal object if err := ensure(class.List, list); err != nil { return nil, err @@ -97,10 +97,10 @@ func Nreverse(_, _ *environment.Environment, list ilos.Instance) (ilos.Instance, // result shares structure with its list arguments. // // An error shall be signaled if the list cannot be allocated (error-id. cannot-create-list). -func Append(_, _ *environment.Environment, lists ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Append(local, global environment.Environment, lists ...ilos.Instance) (ilos.Instance, ilos.Instance) { // Ref: https://github.com/sbcl/sbcl/blob/fe4faef65315c6ad52b3b89b62b6c6497cb78d09/src/code/list.lisp#L364 - result, err := List(nil, nil, Nil) + result, err := List(local, global, Nil) if err != nil { return nil, err } @@ -110,7 +110,7 @@ func Append(_, _ *environment.Environment, lists ...ilos.Instance) (ilos.Instanc } for _, list := range lists { for _, elt := range list.(instance.List).Slice() { - it, err := List(nil, nil, elt) + it, err := List(local, global, elt) if err != nil { return nil, err } @@ -124,13 +124,13 @@ func Append(_, _ *environment.Environment, lists ...ilos.Instance) (ilos.Instanc // Member returnes the first sublist of list whose car is obj if list contains at least one // occurrence of obj (as determined by eql). Otherwise, nil is returned. An error shall be signaled // if list is not a list (error-id. domain-error). -func Member(_, _ *environment.Environment, obj, list ilos.Instance) (ilos.Instance, ilos.Instance) { +func Member(local, global environment.Environment, obj, list ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.List, list); err != nil { return nil, err } for idx, elt := range list.(instance.List).Slice() { if obj == elt { // eql - return List(nil, nil, list.(instance.List).Slice()[idx:]...) + return List(local, global, list.(instance.List).Slice()[idx:]...) } } return Nil, nil @@ -140,7 +140,7 @@ func Member(_, _ *environment.Environment, obj, list ilos.Instance) (ilos.Instan // each list, then to the second element of each list, and so on. The iteration terminates when the // shortest list runs out, and excess elements in other lists are ignored. The value returned by // mapcar is a list of the results of successive calls to function. -func Mapcar(local, global *environment.Environment, function, list1 ilos.Instance, lists ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Mapcar(local, global environment.Environment, function, list1 ilos.Instance, lists ...ilos.Instance) (ilos.Instance, ilos.Instance) { lists = append([]ilos.Instance{list1}, lists...) if err := ensure(class.Function, function); err != nil { return nil, err @@ -164,12 +164,12 @@ func Mapcar(local, global *environment.Environment, function, list1 ilos.Instanc } result = append(result, ret) } - return List(nil, nil, result...) + return List(local, global, result...) } // Mapc is like mapcar except that the results of applying function are not accumulated; // list1 is returned. -func Mapc(local, global *environment.Environment, function, list1 ilos.Instance, lists ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Mapc(local, global environment.Environment, function, list1 ilos.Instance, lists ...ilos.Instance) (ilos.Instance, ilos.Instance) { lists = append([]ilos.Instance{list1}, lists...) if err := ensure(class.Function, function); err != nil { return nil, err @@ -196,7 +196,7 @@ func Mapc(local, global *environment.Environment, function, list1 ilos.Instance, // Mapcan is like mapcar respectively, except that the results of applying // function are combined into a list by the use of an operation that performs a destructive form of // append rather than list. -func Mapcan(local, global *environment.Environment, function, list1 ilos.Instance, lists ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Mapcan(local, global environment.Environment, function, list1 ilos.Instance, lists ...ilos.Instance) (ilos.Instance, ilos.Instance) { lists = append([]ilos.Instance{list1}, lists...) if err := ensure(class.Function, function); err != nil { return nil, err @@ -220,13 +220,13 @@ func Mapcan(local, global *environment.Environment, function, list1 ilos.Instanc } result = append(result, ret) } - return Append(nil, nil, result...) + return Append(local, global, result...) } // Maplist is like mapcar except that function is applied to successive sublists of the lists. // function is first applied to the lists themselves, and then to the cdr of each list, and then to // the cdr of the cdr of each list, and so on. -func Maplist(local, global *environment.Environment, function, list1 ilos.Instance, lists ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Maplist(local, global environment.Environment, function, list1 ilos.Instance, lists ...ilos.Instance) (ilos.Instance, ilos.Instance) { lists = append([]ilos.Instance{list1}, lists...) if err := ensure(class.Function, function); err != nil { return nil, err @@ -243,7 +243,7 @@ func Maplist(local, global *environment.Environment, function, list1 ilos.Instan arguments := make([]ilos.Instance, len(lists)) for j, list := range lists { var err ilos.Instance - arguments[j], err = List(nil, nil, list.(instance.List).Slice()[i:]...) + arguments[j], err = List(local, global, list.(instance.List).Slice()[i:]...) if err != nil { return nil, err } @@ -254,12 +254,12 @@ func Maplist(local, global *environment.Environment, function, list1 ilos.Instan } result = append(result, ret) } - return List(nil, nil, result...) + return List(local, global, result...) } // Mapl is like maplist except that the results of applying function are not accumulated; // list1 is returned. -func Mapl(local, global *environment.Environment, function, list1 ilos.Instance, lists ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Mapl(local, global environment.Environment, function, list1 ilos.Instance, lists ...ilos.Instance) (ilos.Instance, ilos.Instance) { lists = append([]ilos.Instance{list1}, lists...) if err := ensure(class.Function, function); err != nil { return nil, err @@ -275,7 +275,7 @@ func Mapl(local, global *environment.Environment, function, list1 ilos.Instance, arguments := make([]ilos.Instance, len(lists)) for j, list := range lists { var err ilos.Instance - arguments[j], err = List(nil, nil, list.(instance.List).Slice()[i:]...) + arguments[j], err = List(local, global, list.(instance.List).Slice()[i:]...) if err != nil { return nil, err } @@ -290,7 +290,7 @@ func Mapl(local, global *environment.Environment, function, list1 ilos.Instance, // Mapcon is like maplist respectively, except that the results of applying // function are combined into a list by the use of an operation that performs a destructive form of // append rather than list. -func Mapcon(local, global *environment.Environment, function, list1 ilos.Instance, lists ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Mapcon(local, global environment.Environment, function, list1 ilos.Instance, lists ...ilos.Instance) (ilos.Instance, ilos.Instance) { lists = append([]ilos.Instance{list1}, lists...) if err := ensure(class.Function, function); err != nil { return nil, err @@ -307,7 +307,7 @@ func Mapcon(local, global *environment.Environment, function, list1 ilos.Instanc arguments := make([]ilos.Instance, len(lists)) for j, list := range lists { var err ilos.Instance - arguments[j], err = List(nil, nil, list.(instance.List).Slice()[i:]...) + arguments[j], err = List(local, global, list.(instance.List).Slice()[i:]...) if err != nil { return nil, err } @@ -318,13 +318,13 @@ func Mapcon(local, global *environment.Environment, function, list1 ilos.Instanc } result = append(result, ret) } - return Append(nil, nil, result...) + return Append(local, global, result...) } // Assoc returns the first cons if assocation-list contains at least one cons whose car is // obj (as determined by eql). Otherwise, nil is returned. An error shall be signaled // if association-list is not a list of conses (error-id. domain-error). -func Assoc(_, _ *environment.Environment, obj, associationList ilos.Instance) (ilos.Instance, ilos.Instance) { +func Assoc(local, global environment.Environment, obj, associationList ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.List, associationList); err != nil { return nil, err } diff --git a/runtime/logical_connectives.go b/runtime/logical_connectives.go index a1dbece..6512096 100644 --- a/runtime/logical_connectives.go +++ b/runtime/logical_connectives.go @@ -11,7 +11,7 @@ import ( // Not is the logical “not” (or “¬”). It returns t if obj is nil // and nil otherwise. obj may be any ISLISP object. -func Not(_, _ *environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { +func Not(local, global environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { if obj == Nil { return T, nil } @@ -22,7 +22,7 @@ func Not(_, _ *environment.Environment, obj ilos.Instance) (ilos.Instance, ilos. // from left to right until either one of them evaluates to nil or else // none are left. If one of them evaluates to nil, then nil is returned // from the and; otherwise, the value of the last evaluated form is returned. -func And(_, _ *environment.Environment, form ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func And(local, global environment.Environment, form ...ilos.Instance) (ilos.Instance, ilos.Instance) { for _, f := range form { if f == Nil { return Nil, nil @@ -38,7 +38,7 @@ func And(_, _ *environment.Environment, form ...ilos.Instance) (ilos.Instance, i // from left to right until either one of them evaluates to a non-nil value // or else none are left. If one of them evaluates to a non-nil value, // then this non-nil value is returned, otherwise nil is returned. -func Or(_, _ *environment.Environment, form ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Or(local, global environment.Environment, form ...ilos.Instance) (ilos.Instance, ilos.Instance) { for _, f := range form { if f != Nil { return f, nil diff --git a/runtime/namedfunc.go b/runtime/namedfunc.go index a985bd7..55f2d93 100644 --- a/runtime/namedfunc.go +++ b/runtime/namedfunc.go @@ -29,7 +29,7 @@ func checkLambdaList(lambdaList ilos.Instance) ilos.Instance { return nil } -func newNamedFunction(local, global *environment.Environment, functionName, lambdaList ilos.Instance, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func newNamedFunction(local, global environment.Environment, functionName, lambdaList ilos.Instance, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { lexical := local if err := ensure(class.Symbol, functionName); err != nil { return nil, err @@ -45,7 +45,7 @@ func newNamedFunction(local, global *environment.Environment, functionName, lamb } parameters = append(parameters, cadr) } - return instance.NewFunction(functionName.(instance.Symbol), func(local, global *environment.Environment, arguments ...ilos.Instance) (ilos.Instance, ilos.Instance) { + return instance.NewFunction(functionName.(instance.Symbol), func(local, global environment.Environment, arguments ...ilos.Instance) (ilos.Instance, ilos.Instance) { local.Merge(lexical) if (variadic && len(parameters)-2 > len(arguments)) || (!variadic && len(parameters) != len(arguments)) { return nil, instance.NewArityError() @@ -54,7 +54,7 @@ func newNamedFunction(local, global *environment.Environment, functionName, lamb key := parameters[idx] if key == instance.NewSymbol(":REST") || key == instance.NewSymbol("&REST") { key := parameters[idx+1] - value, err := List(nil, nil, arguments[idx:]...) + value, err := List(local, global, arguments[idx:]...) if err != nil { return nil, err } diff --git a/runtime/non-local_exits.go b/runtime/non-local_exits.go index fcdfbde..546e262 100644 --- a/runtime/non-local_exits.go +++ b/runtime/non-local_exits.go @@ -38,7 +38,7 @@ more recently than the destination to which control is being transferred is immediately considered invalid. */ -func Block(local, global *environment.Environment, tag ilos.Instance, body ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Block(local, global environment.Environment, tag ilos.Instance, body ...ilos.Instance) (ilos.Instance, ilos.Instance) { var err ilos.Instance tag, err = Eval(local, global, tag) // Checked at the top of// This function if err != nil { @@ -68,7 +68,7 @@ func Block(local, global *environment.Environment, tag ilos.Instance, body ...il return sucess, nil } -func ReturnFrom(local, global *environment.Environment, tag, object ilos.Instance) (ilos.Instance, ilos.Instance) { +func ReturnFrom(local, global environment.Environment, tag, object ilos.Instance) (ilos.Instance, ilos.Instance) { var err ilos.Instance tag, err = Eval(local, global, tag) if err != nil { @@ -87,7 +87,7 @@ func ReturnFrom(local, global *environment.Environment, tag, object ilos.Instanc return nil, instance.NewBlockTag(tag, object) } -func Catch(local, global *environment.Environment, tag ilos.Instance, body ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Catch(local, global environment.Environment, tag ilos.Instance, body ...ilos.Instance) (ilos.Instance, ilos.Instance) { var err ilos.Instance tag, err = Eval(local, global, tag) if err != nil { @@ -117,7 +117,7 @@ func Catch(local, global *environment.Environment, tag ilos.Instance, body ...il return sucess, nil } -func Throw(local, global *environment.Environment, tag, object ilos.Instance) (ilos.Instance, ilos.Instance) { +func Throw(local, global environment.Environment, tag, object ilos.Instance) (ilos.Instance, ilos.Instance) { var err ilos.Instance tag, err = Eval(local, global, tag) if err != nil { @@ -137,7 +137,7 @@ func Throw(local, global *environment.Environment, tag, object ilos.Instance) (i return nil, instance.NewCatchTag(tag, object) } -func Tagbody(local, global *environment.Environment, body ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Tagbody(local, global environment.Environment, body ...ilos.Instance) (ilos.Instance, ilos.Instance) { for idx, cadr := range body { cddr := instance.GeneralVector(body[idx+1:]) if !instance.Of(class.Cons, cadr) { @@ -181,7 +181,7 @@ func Tagbody(local, global *environment.Environment, body ...ilos.Instance) (ilo return Nil, nil } -func Go(local, global *environment.Environment, tag ilos.Instance) (ilos.Instance, ilos.Instance) { +func Go(local, global environment.Environment, tag ilos.Instance) (ilos.Instance, ilos.Instance) { if _, ok := local.TagbodyTag.Get(tag); !ok { return nil, instance.NewSimpleError(instance.NewString("%v is not defined as the tag"), tag) @@ -217,7 +217,7 @@ func Go(local, global *environment.Environment, tag ilos.Instance) (ilos.Instanc // not terminate abnormally, normal mechanisms for non-local exit (return-from, // throw, or go) would be used as necessary and would respect these // cleanup-forms. -func UnwindProtect(local, global *environment.Environment, form ilos.Instance, cleanupForms ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func UnwindProtect(local, global environment.Environment, form ilos.Instance, cleanupForms ...ilos.Instance) (ilos.Instance, ilos.Instance) { ret1, err1 := Eval(local, global, form) ret2, err2 := Progn(local, global, cleanupForms...) if instance.Of(class.Escape, err2) { diff --git a/runtime/null_class.go b/runtime/null_class.go index 31ee297..5c33fb0 100644 --- a/runtime/null_class.go +++ b/runtime/null_class.go @@ -10,7 +10,7 @@ import ( ) // Null returns t if obj is nil; otherwise, returns nil obj may be any ISLISP object. -func Null(_, _ *environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { +func Null(local, global environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { if obj == Nil { return T, nil } diff --git a/runtime/number_class.go b/runtime/number_class.go index 96c06d0..13e983c 100644 --- a/runtime/number_class.go +++ b/runtime/number_class.go @@ -16,7 +16,7 @@ import ( // Numberp returns t if obj is a number (instance of class number); otherwise, // returns nil. The obj may be any ISLISP object. -func Numberp(_, _ *environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { +func Numberp(local, global environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { if instance.Of(class.Number, obj) { return T, nil } @@ -29,7 +29,7 @@ func Numberp(_, _ *environment.Environment, obj ilos.Instance) (ilos.Instance, i // An error shall be signaled if string is not a string (error-id. domain-error). // An error shall be signaled if string is not the textual representation // of a number (error-id. cannot-parse-number). -func ParseNumber(_, _ *environment.Environment, str ilos.Instance) (ilos.Instance, ilos.Instance) { +func ParseNumber(local, global environment.Environment, str ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.String, str); err != nil { return nil, err } @@ -46,7 +46,7 @@ func ParseNumber(_, _ *environment.Environment, str ilos.Instance) (ilos.Instanc // // Note: = differs from eql because = compares only the mathematical values of its arguments, // whereas eql also compares the representations -func NumberEqual(_, _ *environment.Environment, x1, x2 ilos.Instance) (ilos.Instance, ilos.Instance) { +func NumberEqual(local, global environment.Environment, x1, x2 ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Number, x1, x2); err != nil { return nil, err } @@ -70,16 +70,16 @@ func NumberEqual(_, _ *environment.Environment, x1, x2 ilos.Instance) (ilos.Inst // NumberNotEqual returns t if x1 and x2 have mathematically distinct values; // otherwise, returns nil. An error shall be signaled if either x1 or x2 is not // a number (error-id. domain-error). -func NumberNotEqual(_, _ *environment.Environment, x1, x2 ilos.Instance) (ilos.Instance, ilos.Instance) { - ret, err := NumberEqual(nil, nil, x1, x2) +func NumberNotEqual(local, global environment.Environment, x1, x2 ilos.Instance) (ilos.Instance, ilos.Instance) { + ret, err := NumberEqual(local, global, x1, x2) if err != nil { return ret, err } - return Not(nil, nil, ret) + return Not(local, global, ret) } // NumberGreaterThan returns t if x1 is greater than x2 -func NumberGreaterThan(_, _ *environment.Environment, x1, x2 ilos.Instance) (ilos.Instance, ilos.Instance) { +func NumberGreaterThan(local, global environment.Environment, x1, x2 ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Number, x1, x2); err != nil { return nil, err } @@ -101,12 +101,12 @@ func NumberGreaterThan(_, _ *environment.Environment, x1, x2 ilos.Instance) (ilo } // NumberGreaterThanOrEqual returns t if x1 is greater than or = x2 -func NumberGreaterThanOrEqual(_, _ *environment.Environment, x1, x2 ilos.Instance) (ilos.Instance, ilos.Instance) { - gt, err := NumberGreaterThan(nil, nil, x1, x2) +func NumberGreaterThanOrEqual(local, global environment.Environment, x1, x2 ilos.Instance) (ilos.Instance, ilos.Instance) { + gt, err := NumberGreaterThan(local, global, x1, x2) if err != nil { return nil, err } - eq, err := NumberEqual(nil, nil, x1, x2) + eq, err := NumberEqual(local, global, x1, x2) if err != nil { return nil, err } @@ -117,27 +117,27 @@ func NumberGreaterThanOrEqual(_, _ *environment.Environment, x1, x2 ilos.Instanc } // NumberLessThan returns t if x1 is less than x2 -func NumberLessThan(_, _ *environment.Environment, x1, x2 ilos.Instance) (ilos.Instance, ilos.Instance) { - ge, err := NumberGreaterThanOrEqual(nil, nil, x1, x2) +func NumberLessThan(local, global environment.Environment, x1, x2 ilos.Instance) (ilos.Instance, ilos.Instance) { + ge, err := NumberGreaterThanOrEqual(local, global, x1, x2) if err != nil { return nil, err } - return Not(nil, nil, ge) + return Not(local, global, ge) } // NumberLessThanOrEqulal returns t if x1 is less than or = x2 -func NumberLessThanOrEqulal(_, _ *environment.Environment, x1, x2 ilos.Instance) (ilos.Instance, ilos.Instance) { - gt, err := NumberGreaterThan(nil, nil, x1, x2) +func NumberLessThanOrEqulal(local, global environment.Environment, x1, x2 ilos.Instance) (ilos.Instance, ilos.Instance) { + gt, err := NumberGreaterThan(local, global, x1, x2) if err != nil { return nil, err } - return Not(nil, nil, gt) + return Not(local, global, gt) } // Add returns the sum, respectively, of their arguments. If all arguments are integers, // the result is an integer. If any argument is a float, the result is a float. When given no arguments, // + returns 0. An error shall be signaled if any x is not a number (error-id. domain-error). -func Add(_, _ *environment.Environment, x ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Add(local, global environment.Environment, x ...ilos.Instance) (ilos.Instance, ilos.Instance) { flt := false sum := 0.0 for _, a := range x { @@ -157,7 +157,7 @@ func Add(_, _ *environment.Environment, x ...ilos.Instance) (ilos.Instance, ilos // Multiply returns the product, respectively, of their arguments. If all arguments are integers, // the result is an integer. If any argument is a float, the result is a float. When given no arguments, // Multiply returns 1. An error shall be signaled if any x is not a number (error-id. domain-error). -func Multiply(_, _ *environment.Environment, x ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Multiply(local, global environment.Environment, x ...ilos.Instance) (ilos.Instance, ilos.Instance) { flt := false pdt := 1.0 for _, a := range x { @@ -181,9 +181,9 @@ func Multiply(_, _ *environment.Environment, x ...ilos.Instance) (ilos.Instance, // returns -0.0; in implementations where -0.0 and 0.0 are not distinct, (- 0.0) returns 0.0. // Given more than one argument, x1 … xn , - returns their successive differences, // x1 −x2 − … −xn. An error shall be signaled if any x is not a number (error-id. domain-error). -func Substruct(_, _ *environment.Environment, x ilos.Instance, xs ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Substruct(local, global environment.Environment, x ilos.Instance, xs ...ilos.Instance) (ilos.Instance, ilos.Instance) { if len(xs) == 0 { - ret, err := Substruct(nil, nil, instance.NewInteger(0), x) + ret, err := Substruct(local, global, instance.NewInteger(0), x) return ret, err } sub, flt, err := convFloat64(x) @@ -208,7 +208,7 @@ func Substruct(_, _ *environment.Environment, x ilos.Instance, xs ...ilos.Instan // // Given more than two arguments, quotient operates iteratively on each of the divisor1 … divisorn as in dividend /divisor1 / … /divisorn. The type of the result follows from the two-argument case because the three-or-more-argument quotient can be defined as follows: // An error shall be signaled if dividend is not a number (error-id. domain-error). An error shall be signaled if any divisor is not a number (error-id. domain-error). An error shall be signaled if any divisor is zero (error-id. division-by-zero). -func Quotient(_, _ *environment.Environment, dividend, divisor1 ilos.Instance, divisor ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Quotient(local, global environment.Environment, dividend, divisor1 ilos.Instance, divisor ...ilos.Instance) (ilos.Instance, ilos.Instance) { divisor = append([]ilos.Instance{divisor1}, divisor...) quotient, flt, err := convFloat64(dividend) if err != nil { @@ -239,16 +239,16 @@ func Quotient(_, _ *environment.Environment, dividend, divisor1 ilos.Instance, d // Reciprocal returns the reciprocal of its argument x ; that is, 1/x . // An error shall be signaled if x is zero (error-id. division-by-zero). -func Reciprocal(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { - return Quotient(nil, nil, instance.NewInteger(1), x) +func Reciprocal(local, global environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { + return Quotient(local, global, instance.NewInteger(1), x) } // Max returns the greatest (closest to positive infinity) of its arguments. The comparison is done by >. // An error shall be signaled if any x is not a number (error-id. domain-error). -func Max(_, _ *environment.Environment, x ilos.Instance, xs ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Max(local, global environment.Environment, x ilos.Instance, xs ...ilos.Instance) (ilos.Instance, ilos.Instance) { max := x for _, y := range xs { - ret, err := NumberGreaterThan(nil, nil, y, max) + ret, err := NumberGreaterThan(local, global, y, max) if err != nil { return nil, err } @@ -261,10 +261,10 @@ func Max(_, _ *environment.Environment, x ilos.Instance, xs ...ilos.Instance) (i // Min returns the least (closest to negative infinity) of its arguments. The comparison is done by <. // An error shall be signaled if any x is not a number (error-id. domain-error). -func Min(_, _ *environment.Environment, x ilos.Instance, xs ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Min(local, global environment.Environment, x ilos.Instance, xs ...ilos.Instance) (ilos.Instance, ilos.Instance) { min := x for _, y := range xs { - ret, err := NumberLessThan(nil, nil, y, min) + ret, err := NumberLessThan(local, global, y, min) if err != nil { return nil, err } @@ -277,20 +277,20 @@ func Min(_, _ *environment.Environment, x ilos.Instance, xs ...ilos.Instance) (i // Abs returns the absolute value of its argument. // An error shall be signaled if x is not a number (error-id. domain-error). -func Abs(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { - ret, err := NumberLessThan(nil, nil, x, instance.NewInteger(0)) +func Abs(local, global environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { + ret, err := NumberLessThan(local, global, x, instance.NewInteger(0)) if err != nil { return nil, err } if ret == T { - return Substruct(nil, nil, x) + return Substruct(local, global, x) } return x, nil } // Exp returns e raised to the power x , where e is the base of the natural logarithm. // An error shall be signaled if x is not a number (error-id. domain-error). -func Exp(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { +func Exp(local, global environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { f, _, err := convFloat64(x) if err != nil { return nil, err @@ -300,7 +300,7 @@ func Exp(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos.In // Log returns the natural logarithm of x. // An error shall be signaled if x is not a positive number (error-id. domain-error). -func Log(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { +func Log(local, global environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { f, _, err := convFloat64(x) if err != nil { return nil, err @@ -316,7 +316,7 @@ func Log(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos.In // An error shall be signaled if x1 is zero and x2 is negative, // or if x1 is zero and x2 is a zero float, or if x1 is negative // and x2 is not an integer. -func Expt(_, _ *environment.Environment, x1, x2 ilos.Instance) (ilos.Instance, ilos.Instance) { +func Expt(local, global environment.Environment, x1, x2 ilos.Instance) (ilos.Instance, ilos.Instance) { a, af, err := convFloat64(x1) if err != nil { return nil, err @@ -330,7 +330,7 @@ func Expt(_, _ *environment.Environment, x1, x2 ilos.Instance) (ilos.Instance, i } if (a == 0 && b < 0) || (a == 0 && bf && b == 0) || (a < 0 && bf) { operation := instance.NewSymbol("EXPT") - operands, err := List(nil, nil, x1, x2) + operands, err := List(local, global, x1, x2) if err != nil { return nil, err } @@ -341,7 +341,7 @@ func Expt(_, _ *environment.Environment, x1, x2 ilos.Instance) (ilos.Instance, i // Sqrt returns the non-negative square root of x. An error shall be signaled // if x is not a non-negative number (error-id. domain-error). -func Sqrt(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { +func Sqrt(local, global environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { a, _, err := convFloat64(x) if err != nil { return nil, err @@ -360,7 +360,7 @@ var Pi = instance.NewFloat(3.141592653589793) // Sin returns the sine of x . x must be given in radians. // An error shall be signaled if x is not a number (error-id. domain-error). -func Sin(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { +func Sin(local, global environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { a, _, err := convFloat64(x) if err != nil { return nil, err @@ -370,7 +370,7 @@ func Sin(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos.In // Cos returns the cosine of x . x must be given in radians. // An error shall be signaled if x is not a number (error-id. domain-error). -func Cos(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { +func Cos(local, global environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { a, _, err := convFloat64(x) if err != nil { return nil, err @@ -380,7 +380,7 @@ func Cos(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos.In // Tan returns the tangent of x . x must be given in radians. // An error shall be signaled if x is not a number (error-id. domain-error). -func Tan(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { +func Tan(local, global environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { a, _, err := convFloat64(x) if err != nil { return nil, err @@ -391,7 +391,7 @@ func Tan(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos.In // Atan returns the arc tangent of x. // The result is a (real) number that lies between −π/2 and π/2 (both exclusive). // An error shall be signaled if x is not a number (error-id. domain-error). -func Atan(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { +func Atan(local, global environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { a, _, err := convFloat64(x) if err != nil { return nil, err @@ -408,7 +408,7 @@ func Atan(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos.I // is not supported; when minus zero is supported, the range includes −π. // // The signs of x1 (indicated as y) and x2 (indicated as x) are used to derive quadrant information. -func Atan2(_, _ *environment.Environment, x1, x2 ilos.Instance) (ilos.Instance, ilos.Instance) { +func Atan2(local, global environment.Environment, x1, x2 ilos.Instance) (ilos.Instance, ilos.Instance) { a, _, err := convFloat64(x1) if err != nil { return nil, err @@ -419,7 +419,7 @@ func Atan2(_, _ *environment.Environment, x1, x2 ilos.Instance) (ilos.Instance, } if a == 0 && b == 0 { operation := instance.NewSymbol("ATAN2") - operands, err := List(nil, nil, x1, x2) + operands, err := List(local, global, x1, x2) if err != nil { return nil, err } @@ -430,7 +430,7 @@ func Atan2(_, _ *environment.Environment, x1, x2 ilos.Instance) (ilos.Instance, // Sinh returns the hyperbolic sine of x . x must be given in radians. // An error shall be signaled if x is not a number (error-id. domain-error). -func Sinh(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { +func Sinh(local, global environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { a, _, err := convFloat64(x) if err != nil { return nil, err @@ -440,7 +440,7 @@ func Sinh(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos.I // Cosh returns the hyperbolic cosine of x . x must be given in radians. // An error shall be signaled if x is not a number (error-id. domain-error). -func Cosh(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { +func Cosh(local, global environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { a, _, err := convFloat64(x) if err != nil { return nil, err @@ -450,7 +450,7 @@ func Cosh(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos.I // Tanh returns the hyperbolic tangent of x . x must be given in radians. // An error shall be signaled if x is not a number (error-id. domain-error). -func Tanh(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { +func Tanh(local, global environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { a, _, err := convFloat64(x) if err != nil { return nil, err @@ -460,7 +460,7 @@ func Tanh(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos.I // Atanh returns the hyperbolic arc tangent of x. // An error shall be signaled if x is not a number with absolute value less than 1 (error-id. domain-error). -func Atanh(_, _ *environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { +func Atanh(local, global environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { a, _, err := convFloat64(x) if err != nil { return nil, err diff --git a/runtime/sequence_functions.go b/runtime/sequence_functions.go index 1f745fe..c4f6830 100644 --- a/runtime/sequence_functions.go +++ b/runtime/sequence_functions.go @@ -24,7 +24,7 @@ import ( // // An error shall be signaled if sequence is not a basic-vector or a list // (error-id. domain-error). -func Length(_, _ *environment.Environment, sequence ilos.Instance) (ilos.Instance, ilos.Instance) { +func Length(local, global environment.Environment, sequence ilos.Instance) (ilos.Instance, ilos.Instance) { switch { case instance.Of(class.String, sequence): return instance.NewInteger(len(sequence.(instance.String))), nil @@ -44,7 +44,7 @@ func Length(_, _ *environment.Environment, sequence ilos.Instance) (ilos.Instanc // // An error shall be signaled if sequence is not a basic-vector or a list or if z is not an // integer (error-id. domain-error). -func Elt(_, _ *environment.Environment, sequence, z ilos.Instance) (ilos.Instance, ilos.Instance) { +func Elt(local, global environment.Environment, sequence, z ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Integer, z); err != nil { return nil, err } @@ -80,7 +80,7 @@ func Elt(_, _ *environment.Environment, sequence, z ilos.Instance) (ilos.Instanc // An error shall be signaled if z is an integer outside of the valid range of indices // (error-id. index-out-of-range). An error shall be signaled if sequence is not a basic-vector // or a list or if z is not an integer (error-id. domain-error). obj may be any ISLISP object. -func SetElt(_, _ *environment.Environment, obj, sequence, z ilos.Instance) (ilos.Instance, ilos.Instance) { +func SetElt(local, global environment.Environment, obj, sequence, z ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Integer, z); err != nil { return nil, err } @@ -130,7 +130,7 @@ func SetElt(_, _ *environment.Environment, obj, sequence, z ilos.Instance) (ilos // mentioned (error-id. index-out-of-range). An error shall be signaled if sequence is not a // basic-vector or a list, or if z1 is not an integer, or if z2 is not an integer // (error-id. domain-error). -func Subseq(_, _ *environment.Environment, sequence, z1, z2 ilos.Instance) (ilos.Instance, ilos.Instance) { +func Subseq(local, global environment.Environment, sequence, z1, z2 ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Integer, z1, z2); err != nil { return nil, err } @@ -154,7 +154,7 @@ func Subseq(_, _ *environment.Environment, sequence, z1, z2 ilos.Instance) (ilos if !(0 < start && start < len(seq) && 0 < end && end < len(seq) && start <= end) { return nil, instance.NewIndexOutOfRange() } - return List(nil, nil, seq[start:end]...) + return List(local, global, seq[start:end]...) } return nil, instance.NewDomainError(sequence, class.Object) } @@ -175,7 +175,7 @@ func Subseq(_, _ *environment.Environment, sequence, z1, z2 ilos.Instance) (ilos // // An error shall be signaled if any sequence is not a basic-vector or a list // (error-id. domain-error). -func mapInto(local, global *environment.Environment, destination, function ilos.Instance, sequences ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func mapInto(local, global environment.Environment, destination, function ilos.Instance, sequences ...ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.List, append(sequences, destination)...); err != nil { if err := ensure(class.BasicVector, append(sequences, destination)...); err != nil { return nil, err @@ -199,7 +199,7 @@ func mapInto(local, global *environment.Environment, destination, function ilos. arguments := make([]ilos.Instance, int(max)) for _, seq := range sequences { var err ilos.Instance - arguments[i], err = Elt(nil, nil, seq, instance.NewInteger(i)) + arguments[i], err = Elt(local, global, seq, instance.NewInteger(i)) if err != nil { return nil, err } @@ -208,7 +208,7 @@ func mapInto(local, global *environment.Environment, destination, function ilos. if err != nil { return nil, err } - _, err = SetElt(nil, nil, ret, destination, instance.NewInteger(i)) + _, err = SetElt(local, global, ret, destination, instance.NewInteger(i)) if err != nil { return nil, err } diff --git a/runtime/sequencing_forms.go b/runtime/sequencing_forms.go index d1e5269..9d639cb 100644 --- a/runtime/sequencing_forms.go +++ b/runtime/sequencing_forms.go @@ -14,7 +14,7 @@ import ( // The result of evaluation of the last form of form* is returned. All the forms are // evaluated from left to right. The values of all the forms but the last are discarded, // so they are executed only for their side-effects. progn without forms returns nil. -func Progn(local, global *environment.Environment, form ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Progn(local, global environment.Environment, form ...ilos.Instance) (ilos.Instance, ilos.Instance) { var err ilos.Instance ret := Nil for _, e := range form { diff --git a/runtime/string_class.go b/runtime/string_class.go index bacd597..50e83d2 100644 --- a/runtime/string_class.go +++ b/runtime/string_class.go @@ -15,7 +15,7 @@ import ( // Stringp returns t if obj is a string (instance of class string); // otherwise, returns nil. obj may be any ISLISP object. -func Stringp(_, _ *environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { +func Stringp(local, global environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { if instance.Of(class.String, obj) { return T, nil } @@ -26,7 +26,7 @@ func Stringp(_, _ *environment.Environment, obj ilos.Instance) (ilos.Instance, i // the new string are initialized with this character, otherwise the initialization is implementation defined. // An error shall be signaled if the requested string cannot be allocated (error-id. cannot-create-string). // An error shall be signaled if i is not a non-negative integer or if initial-character is not a character (error-id. domain-error). -func CreateString(_, _ *environment.Environment, i ilos.Instance, initialElement ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func CreateString(local, global environment.Environment, i ilos.Instance, initialElement ...ilos.Instance) (ilos.Instance, ilos.Instance) { if !instance.Of(class.Integer, i) || int(i.(instance.Integer)) < 0 { return nil, instance.NewDomainError(i, class.Integer) } @@ -49,7 +49,7 @@ func CreateString(_, _ *environment.Environment, i ilos.Instance, initialElement } // StringEqual tests whether string1 is the same string as string2. -func StringEqual(_, _ *environment.Environment, string1, string2 ilos.Instance) (ilos.Instance, ilos.Instance) { +func StringEqual(local, global environment.Environment, string1, string2 ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.String, string1, string2); err != nil { return nil, err } @@ -60,16 +60,16 @@ func StringEqual(_, _ *environment.Environment, string1, string2 ilos.Instance) } // StringNotEqual tests whether string1 not is the same string as string2. -func StringNotEqual(_, _ *environment.Environment, string1, string2 ilos.Instance) (ilos.Instance, ilos.Instance) { - ret, err := StringEqual(nil, nil, string1, string2) +func StringNotEqual(local, global environment.Environment, string1, string2 ilos.Instance) (ilos.Instance, ilos.Instance) { + ret, err := StringEqual(local, global, string1, string2) if err != nil { return nil, err } - return Not(nil, nil, ret) + return Not(local, global, ret) } // StringGreaterThan tests whether string1 is greater than string2. -func StringGreaterThan(_, _ *environment.Environment, string1, string2 ilos.Instance) (ilos.Instance, ilos.Instance) { +func StringGreaterThan(local, global environment.Environment, string1, string2 ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.String, string1, string2); err != nil { return nil, err } @@ -80,12 +80,12 @@ func StringGreaterThan(_, _ *environment.Environment, string1, string2 ilos.Inst } // StringGreaterThanOrEqual tests whether string1 is greater than or equal to string2. -func StringGreaterThanOrEqual(_, _ *environment.Environment, string1, string2 ilos.Instance) (ilos.Instance, ilos.Instance) { - gt, err := StringGreaterThan(nil, nil, string1, string2) +func StringGreaterThanOrEqual(local, global environment.Environment, string1, string2 ilos.Instance) (ilos.Instance, ilos.Instance) { + gt, err := StringGreaterThan(local, global, string1, string2) if err != nil { return nil, err } - eq, err := StringEqual(nil, nil, string1, string2) + eq, err := StringEqual(local, global, string1, string2) if err != nil { return nil, err } @@ -96,21 +96,21 @@ func StringGreaterThanOrEqual(_, _ *environment.Environment, string1, string2 il } // StringLessThan tests whether string1 is less than string2. -func StringLessThan(_, _ *environment.Environment, string1, string2 ilos.Instance) (ilos.Instance, ilos.Instance) { - gt, err := StringGreaterThanOrEqual(nil, nil, string1, string2) +func StringLessThan(local, global environment.Environment, string1, string2 ilos.Instance) (ilos.Instance, ilos.Instance) { + gt, err := StringGreaterThanOrEqual(local, global, string1, string2) if err != nil { return nil, err } - return Not(nil, nil, gt) + return Not(local, global, gt) } // StringLessThanOrEqual tests whether string1 is less than or equal to string2. -func StringLessThanOrEqual(_, _ *environment.Environment, string1, string2 ilos.Instance) (ilos.Instance, ilos.Instance) { - gt, err := StringGreaterThan(nil, nil, string1, string2) +func StringLessThanOrEqual(local, global environment.Environment, string1, string2 ilos.Instance) (ilos.Instance, ilos.Instance) { + gt, err := StringGreaterThan(local, global, string1, string2) if err != nil { return nil, err } - return Not(nil, nil, gt) + return Not(local, global, gt) } // CharIndex returns the position of char in string, The search starts from the position indicated @@ -119,7 +119,7 @@ func StringLessThanOrEqual(_, _ *environment.Environment, string1, string2 ilos. // If the char does not occur in the string, nil is returned. The function char= is used for the comparisons. // // An error shall be signaled if char is not a character or if string is not a string (error-id. domain-error). -func CharIndex(_, _ *environment.Environment, char, str ilos.Instance, startPosition ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func CharIndex(local, global environment.Environment, char, str ilos.Instance, startPosition ...ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Character, char); err != nil { return nil, err } @@ -152,7 +152,7 @@ func CharIndex(_, _ *environment.Environment, char, str ilos.Instance, startPosi // Presence of the substring is done by sequential use of char= on corresponding elements of the two strings. // // An error shall be signaled if either substring or string is not a string (error-id. domain-error). -func StringIndex(_, _ *environment.Environment, sub, str ilos.Instance, startPosition ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func StringIndex(local, global environment.Environment, sub, str ilos.Instance, startPosition ...ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.String, sub); err != nil { return nil, err } @@ -186,7 +186,7 @@ func StringIndex(_, _ *environment.Environment, sub, str ilos.Instance, startPos // when the result shares structure with its string arguments. // // An error shall be signaled if the string cannot be allocated (error-id. cannot-create-string). -func StringAppend(_, _ *environment.Environment, str ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func StringAppend(local, global environment.Environment, str ...ilos.Instance) (ilos.Instance, ilos.Instance) { ret := "" for _, s := range str { if err := ensure(class.String, s); err != nil { diff --git a/runtime/symbol_class.go b/runtime/symbol_class.go index ac0e95c..4d39870 100644 --- a/runtime/symbol_class.go +++ b/runtime/symbol_class.go @@ -17,7 +17,7 @@ import ( // Symbolp returns t if obj is a symbol (instance of class symbol); // otherwise, returns nil. The obj may be any ISLISP object. -func Symbolp(_, _ *environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { +func Symbolp(local, global environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { if instance.Of(class.Symbol, obj) { return T, nil } @@ -30,7 +30,7 @@ func Symbolp(_, _ *environment.Environment, obj ilos.Instance) (ilos.Instance, i // // An error shall be signaled if either symbol or property-name is not a // symbol (error-id. domain-error). obj may be any ISLISP object -func Property(local, global *environment.Environment, symbol, propertyName ilos.Instance, obj ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Property(local, global environment.Environment, symbol, propertyName ilos.Instance, obj ...ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Symbol, symbol); err != nil { return nil, err } @@ -51,7 +51,7 @@ func Property(local, global *environment.Environment, symbol, propertyName ilos. // // An error shall be signaled if either symbol or property-name is not a // symbol (error-id. domain-error). obj may be any ISLISP object -func SetProperty(local, global *environment.Environment, obj, symbol, propertyName ilos.Instance) (ilos.Instance, ilos.Instance) { +func SetProperty(local, global environment.Environment, obj, symbol, propertyName ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Symbol, symbol); err != nil { return nil, err } @@ -65,7 +65,7 @@ func SetProperty(local, global *environment.Environment, obj, symbol, propertyNa // // An error shall be signaled if either symbol or property-name is not a // symbol (error-id. domain-error). -func RemoveProperty(local, global *environment.Environment, symbol, propertyName ilos.Instance) (ilos.Instance, ilos.Instance) { +func RemoveProperty(local, global environment.Environment, symbol, propertyName ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Symbol, symbol); err != nil { return nil, err } @@ -77,7 +77,7 @@ func RemoveProperty(local, global *environment.Environment, symbol, propertyName // Gensym returns an unnamed symbol. gensym is useful for writing macros. // It is impossible for an identifier to name an unnamed symbol. -func Gensym(local, global *environment.Environment) (ilos.Instance, ilos.Instance) { +func Gensym(local, global environment.Environment) (ilos.Instance, ilos.Instance) { global.GensymID++ return instance.NewSymbol(fmt.Sprintf("IRIS/G#%v", global.GensymID)), nil } diff --git a/runtime/util.go b/runtime/util.go index 76243b4..12b09c4 100644 --- a/runtime/util.go +++ b/runtime/util.go @@ -44,7 +44,7 @@ func readFromString(s string) ilos.Instance { e, _ := parser.Parse(tokenizer.New(strings.NewReader(s))) return e } -func evalString(local, global *environment.Environment, s string) ilos.Instance { +func evalString(local, global environment.Environment, s string) ilos.Instance { e, _ := Eval(local, global, readFromString(s)) return e } diff --git a/runtime/variables.go b/runtime/variables.go index 193398f..9b330d5 100644 --- a/runtime/variables.go +++ b/runtime/variables.go @@ -19,7 +19,7 @@ import ( // setq can be used only for modifying bindings, and not for establishing a variable. // The setq special form must be contained in the scope of var , established by defglobal, // let, let*, for, or a lambda expression. -func Setq(local, global *environment.Environment, var1, form ilos.Instance) (ilos.Instance, ilos.Instance) { +func Setq(local, global environment.Environment, var1, form ilos.Instance) (ilos.Instance, ilos.Instance) { ret, err := Eval(local, global, form) if err != nil { return nil, err @@ -47,7 +47,7 @@ func Setq(local, global *environment.Environment, var1, form ilos.Instance) (ilo // of the evaluation of the last body-form of its body (or nil if there is none). // // No var may appear more than once in let variable list. -func Let(local, global *environment.Environment, varForm ilos.Instance, bodyForm ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Let(local, global environment.Environment, varForm ilos.Instance, bodyForm ...ilos.Instance) (ilos.Instance, ilos.Instance) { vfs := map[ilos.Instance]ilos.Instance{} if err := ensure(class.List, varForm); err != nil { return nil, err @@ -88,7 +88,7 @@ func Let(local, global *environment.Environment, varForm ilos.Instance, bodyForm // and in this enlarged or modified environment the body-forms are executed. // The returned value of let* is the result of the evaluation of the last form // of its body (or nil if there is none). -func LetStar(local, global *environment.Environment, varForm ilos.Instance, bodyForm ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func LetStar(local, global environment.Environment, varForm ilos.Instance, bodyForm ...ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.List, varForm); err != nil { return nil, err } diff --git a/runtime/vectors.go b/runtime/vectors.go index 72f035d..4db62ab 100644 --- a/runtime/vectors.go +++ b/runtime/vectors.go @@ -13,7 +13,7 @@ import ( // BasicVectorP returns t if obj is a basic-vector (instance of class basic-vector); // otherwise, returns nil. obj may be any ISLISP object. -func BasicVectorP(_, _ *environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { +func BasicVectorP(local, global environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { if instance.Of(class.BasicVector, obj) { return T, nil } @@ -22,7 +22,7 @@ func BasicVectorP(_, _ *environment.Environment, obj ilos.Instance) (ilos.Instan // GeneralVectorP returns t if obj is a general-vector (instance of class general-vector); // otherwise, returns nil. obj may be any ISLISP object. -func GeneralVectorP(_, _ *environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { +func GeneralVectorP(local, global environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { if instance.Of(class.GeneralVector, obj) { return T, nil } @@ -35,7 +35,7 @@ func GeneralVectorP(_, _ *environment.Environment, obj ilos.Instance) (ilos.Inst // if the requested vector cannot be allocated (error-id. cannot-create-vector). // An error shall be signaled if i is not a non-negative integer (error-id. domain-error). // initial-element may be any ISLISP object. -func CreateVector(_, _ *environment.Environment, i ilos.Instance, initialElement ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func CreateVector(local, global environment.Environment, i ilos.Instance, initialElement ...ilos.Instance) (ilos.Instance, ilos.Instance) { if !instance.Of(class.Integer, i) || int(i.(instance.Integer)) < 0 { return nil, instance.NewDomainError(i, class.Integer) } @@ -59,6 +59,6 @@ func CreateVector(_, _ *environment.Environment, i ilos.Instance, initialElement // The vector is indexed by integers ranging from 0 to dimension−1. An error shall be signaled // if the requested vector cannot be allocated (error-id. cannot-create-vector). // Each obj may be any ISLISP object. -func Vector(_, _ *environment.Environment, obj ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Vector(local, global environment.Environment, obj ...ilos.Instance) (ilos.Instance, ilos.Instance) { return instance.GeneralVector(obj), nil } From db3cbea57952cfd23f76bb14c00d9c7ae3b48995 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Thu, 17 Aug 2017 10:25:03 +0900 Subject: [PATCH 189/228] Added test for Logical connectives --- runtime/logical_connectives_test.go | 160 ++++++++++++++++++++++++++++ 1 file changed, 160 insertions(+) create mode 100644 runtime/logical_connectives_test.go diff --git a/runtime/logical_connectives_test.go b/runtime/logical_connectives_test.go new file mode 100644 index 0000000..e55b860 --- /dev/null +++ b/runtime/logical_connectives_test.go @@ -0,0 +1,160 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package runtime + +import "testing" + +func TestNot(t *testing.T) { + defun(Not) + defglobal("T", T) + defglobal("NIL", Nil) + defun(List) + defspecial(Quote) + tests := []test{ + { + exp: `(not t)`, + want: `nil`, + wantErr: false, + }, + { + exp: `(not '())`, + want: `t`, + wantErr: false, + }, + { + exp: `(not 3)`, + want: `nil`, + wantErr: false, + }, + { + exp: `(not t)`, + want: `nil`, + wantErr: false, + }, + { + exp: `(not (list))`, + want: `t`, + wantErr: false, + }, + { + exp: `(not (list 3))`, + want: `nil`, + wantErr: false, + }, + } + execTests(t, Not, tests) +} + +func TestAnd(t *testing.T) { + defun(And) + defun2("=", NumberEqual) + defun2(">", NumberGreaterThan) + defun2("<", NumberLessThan) + defun(Eq) + defspecial(Quote) + defun(Not) + defspecial(Let) + defspecial(Setq) + defglobal("T", T) + defglobal("NIL", Nil) + defun2("-", Substruct) + defspecial(If) + defun(Eql) + tests := []test{ + { + exp: `(and (= 2 2) (> 2 1))`, + want: `t`, + wantErr: false, + }, + { + exp: `(and (= 2 2) (< 2 1))`, + want: `nil`, + wantErr: false, + }, + { + exp: `(and (eql 'a 'a) (not (> 1 2)))`, + want: `t`, + wantErr: false, + }, + { + exp: ` + (let ((x 'a)) + (and x (setq x 'b))) + `, + want: `'b`, + wantErr: false, + }, + { + exp: ` + (let ((x nil)) + (and x (setq x 'b))) + `, + want: `nil`, + wantErr: false, + }, + { + exp: ` + (let ((time 10)) + (if (and (< time 24) (> time 12)) + (- time 12) + time)) + `, + want: `10`, + wantErr: false, + }, + { + exp: ` + (let ((time 18)) + (if (and (< time 24) (> time 12)) + (- time 12) + time)) + `, + want: `6`, + wantErr: false, + }, + } + execTests(t, And, tests) +} + +func TestOr(t *testing.T) { + defun(Or) + defun2("=", NumberEqual) + defun2(">", NumberGreaterThan) + defun2("<", NumberLessThan) + defspecial(Quote) + defspecial(Setq) + defspecial(Let) + defglobal("T", T) + defglobal("NIL", Nil) + tests := []test{ + { + exp: `(or (= 2 2) (> 2 1))`, + want: `t`, + wantErr: false, + }, + { + exp: `(or (= 2 2) (< 2 1))`, + want: `t`, + wantErr: false, + }, + { + exp: ` + (let ((x 'a)) + (or x (setq x 'b))) + `, + want: `'a`, + wantErr: false, + }, + { + exp: ` + (let ((x nil)) + (or x (setq x 'b))) + `, + want: `'b`, + wantErr: false, + }, + } + execTests(t, And, tests) +} From 33150391e98094c1abb78b7490a7f15d0b113e28 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Thu, 17 Aug 2017 21:10:24 +0900 Subject: [PATCH 190/228] Added macro expander --- reader/parser/parser.go | 6 +- runtime/ilos/instance/error.go | 8 +- runtime/macros.go | 194 +++++++++++++++++++++++++++++++++ runtime/macros_test.go | 53 +++++++++ 4 files changed, 254 insertions(+), 7 deletions(-) create mode 100644 runtime/macros.go create mode 100644 runtime/macros_test.go diff --git a/reader/parser/parser.go b/reader/parser/parser.go index 06d6c8f..3a52cc7 100644 --- a/reader/parser/parser.go +++ b/reader/parser/parser.go @@ -112,13 +112,13 @@ func parseMacro(tok string, t *tokenizer.Tokenizer) (ilos.Instance, ilos.Instanc case "#'": n = "FUNCTION" case ",@": - n = "commaat" + n = "UNQUOTE-SPLICING" case ",": - n = "comma" + n = "UNQUOTE" case "'": n = "QUOTE" case "`": - n = "BACKQUOTE" + n = "QUASIQUOTE" } m := instance.NewSymbol(n) return instance.NewCons(m, instance.NewCons(cdr, instance.Nil)), nil diff --git a/runtime/ilos/instance/error.go b/runtime/ilos/instance/error.go index 2b43ff7..30f83c1 100644 --- a/runtime/ilos/instance/error.go +++ b/runtime/ilos/instance/error.go @@ -50,15 +50,15 @@ func NewDivisionByZero(operation, operands ilos.Instance) ilos.Instance { func NewParseError(str, expectedClass ilos.Instance) ilos.Instance { return New(class.ParseError, map[string]ilos.Instance{ - "STRING": str, - "EXPECTED-CLASSS": expectedClass, + "STRING": str, + "EXPECTED-CLASS": expectedClass, }) } func NewDomainError(object ilos.Instance, expectedClass ilos.Class) ilos.Instance { return New(class.DomainError, map[string]ilos.Instance{"CAUSE": Symbol("DOMAIN-ERROR"), - "OBJECT": object, - "EXPECTED-CLASSS": expectedClass, + "OBJECT": object, + "EXPECTED-CLASS": expectedClass, }) } diff --git a/runtime/macros.go b/runtime/macros.go new file mode 100644 index 0000000..af119bc --- /dev/null +++ b/runtime/macros.go @@ -0,0 +1,194 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package runtime + +import ( + "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/ilos" + "github.com/ta2gch/iris/runtime/ilos/class" + "github.com/ta2gch/iris/runtime/ilos/instance" +) + +// Defmacro defines a named (toplevel) macro. No implicit block with the macro +// name is established when the macro-expansion function is invoked. macro-name +// must be an identifier whose scope is the current toplevel scope in which the +// defmacro form appears. lambda-list is as defined in page 23. The definition +// point of macro-name is the closing parenthesis of the lambda-list. +func Defmacro(local, global environment.Environment, macroName, lambdaList ilos.Instance, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { + if err := ensure(class.Symbol, macroName); err != nil { + return nil, err + } + ret, err := newNamedFunction(local, global, macroName, lambdaList, forms...) + if err != nil { + return nil, err + } + global.Macro.Define(macroName, ret) + return macroName, nil +} + +// Quasiquote ` or quasiquote constructs a list structure. quasiquote, like quote, returns +// its argument unevaluated if no commas or the syntax , (unquote) or ,@ +// (unquote-splicing) appear within the form. +// +// , (unquote) syntax is valid only within ` (quasiquote) expressions. When +// appearing within a quasiquote the form is evaluated and its result is +// inserted into the quasiquote structure instead of the unquote form. +// +// ,@ (unquote-splicing) is also syntax valid only within ` expressions. When +// appearing within a quasiquote the expression form must evaluate to a list. +// The elements of the list are spliced into the enclosing list in place of the +// unquote-splicing form sequence. +// +// Quasiquote forms may be nested. Substitutions are made only for unquoted +// expressions appearing at the same nesting level, which increases by one +// inside each successive quasiquotation and decreases by one inside each +// unquotation. +func Quasiquote(local, global environment.Environment, form ilos.Instance) (ilos.Instance, ilos.Instance) { + return expand(local, global, form, 0) +} + +func expand(local, global environment.Environment, form ilos.Instance, level int) (ilos.Instance, ilos.Instance) { + if !instance.Of(class.Cons, form) { + return form, nil + } // If form is a instance of then, + exp := []ilos.Instance{} + cdr := form + for instance.Of(class.Cons, cdr) { + cadr := cdr.(*instance.Cons).Car + cddr := cdr.(*instance.Cons).Cdr + // To expand `((foo ,(- 10 3)) ,@(cdr '(c)) . ,(car '(cons))) + if cadr == instance.NewSymbol("UNQUOTE") && level == 0 { + caddr := cddr.(*instance.Cons).Car + elt, err := Eval(local, global, caddr) + if err != nil { + return nil, err + } + exp = append(exp, elt) + break + } + if !instance.Of(class.Cons, cadr) { + lst, err := List(local, global, cadr) + if err != nil { + return nil, err + } + exp = append(exp, lst) + cdr = cdr.(*instance.Cons).Cdr + continue + } // If cadr is a instance of then, + caadr := cadr.(*instance.Cons).Car + cdadr := cadr.(*instance.Cons).Cdr + if caadr == instance.NewSymbol("UNQUOTE") { + cadadr := cdadr.(*instance.Cons).Car + var elt, err ilos.Instance + if level == 0 { + elt, err = Eval(local, global, cadadr) + if err != nil { + return nil, err + } + lst, err := List(local, global, elt) + if err != nil { + return nil, err + } + exp = append(exp, lst) + cdr = cdr.(*instance.Cons).Cdr + continue + } else { + elt, err = expand(local, global, cadadr, level-1) + if err != nil { + return nil, err + } + lst, err := List(local, global, caadr, elt) + if err != nil { + return nil, err + } + lstlst, err := List(local, global, lst) + if err != nil { + return nil, err + } + exp = append(exp, lstlst) + cdr = cdr.(*instance.Cons).Cdr + continue + } + } + if caadr == instance.NewSymbol("UNQUOTE-SPLICING") { + cadadr := cdadr.(*instance.Cons).Car + if level == 0 { + elt, err := Eval(local, global, cadadr) + if err != nil { + return nil, err + } + exp = append(exp, elt) + cdr = cdr.(*instance.Cons).Cdr + continue + } else { + elt, err := expand(local, global, cadadr, level-1) + if err != nil { + return nil, err + } + lst, err := List(local, global, caadr, elt) + if err != nil { + return nil, err + } + lstlst, err := List(local, global, lst) + if err != nil { + return nil, err + } + exp = append(exp, lstlst) + cdr = cdr.(*instance.Cons).Cdr + continue + } + } + if caadr == instance.NewSymbol("QUASIQUOTE") { + cadadr := cdadr.(*instance.Cons).Car + elt, err := expand(local, global, cadadr, level+1) + if err != nil { + return nil, err + } + lst, err := List(local, global, caadr, elt) + if err != nil { + return nil, err + } + lstlst, err := List(local, global, lst) + if err != nil { + return nil, err + } + exp = append(exp, lstlst) + cdr = cdr.(*instance.Cons).Cdr + continue + } + elt, err := expand(local, global, cadr, level) + if err != nil { + return nil, err + } + lst, err := List(local, global, elt) + if err != nil { + return nil, err + } + exp = append(exp, lst) + cdr = cddr + continue + } + if instance.Of(class.Null, cdr) { + exp = append(exp, Nil) + } + lst := exp[len(exp)-1] + for i := len(exp) - 2; i >= 0; i-- { + if instance.Of(class.List, lst) { + var err ilos.Instance + lst, err = Append(local, global, exp[i], lst) + if err != nil { + return nil, err + } + } else { + // To expand `((foo ,(- 10 3)) ,@(cdr '(c)) . ,(car '(cons))) + // the elements of exp is always a instance of because exp isn't appended lists in for-loop + slice := exp[i].(instance.List).Slice() + for j := len(slice) - 1; j >= 0; j-- { + lst = instance.NewCons(slice[j], lst) + } + } + } + return lst, nil +} diff --git a/runtime/macros_test.go b/runtime/macros_test.go new file mode 100644 index 0000000..2073c3d --- /dev/null +++ b/runtime/macros_test.go @@ -0,0 +1,53 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package runtime + +import "testing" + +func TestDefmacro(t *testing.T) { + defspecial(Defmacro) + defun(List) + defun2("+", Add) + defspecial(Let) + defspecial(Quasiquote) + defun(CreateList) + defun(Car) + defun(Cdr) + defun2("-", Substruct) + defspecial(Quote) + tests := []test{ + { + exp: "`(list ,(+ 1 2) 4)", + want: `'(list 3 4)`, + wantErr: false, + }, + { + exp: "(let ((name 'a)) `(list name ,name ',name))", + want: `'(list name a (quote a))`, + wantErr: false, + }, + { + exp: "`(a ,(+ 1 2) ,@(create-list 3 'x) b)", + want: `'(a 3 x x x b)`, + wantErr: false, + }, + { + exp: "`((foo ,(- 10 3)) ,@(cdr '(c)) . ,(car '(cons)))", + want: `'((foo 7) . cons)`, + wantErr: false, + }, + { + exp: "`(a `(b ,(+ 1 2) ,(foo ,(+ 1 3) d) e) f)", + want: "'(a `(b ,(+ 1 2) ,(foo 4 d) e) f)", + wantErr: false, + }, + { + exp: "(let ((name1 'x) (name2 'y)) `(a `(b ,,name1 ,',name2 d) e))", + want: "`(a `(b ,x ,'y d) e)", + wantErr: false, + }, + } + execTests(t, Defmacro, tests) +} From 48959574aaa449fe326fede61eaeffb39242e31e Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Thu, 17 Aug 2017 21:22:01 +0900 Subject: [PATCH 191/228] Added some comments --- runtime/macros.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/runtime/macros.go b/runtime/macros.go index af119bc..a273aed 100644 --- a/runtime/macros.go +++ b/runtime/macros.go @@ -158,6 +158,7 @@ func expand(local, global environment.Environment, form ilos.Instance, level int cdr = cdr.(*instance.Cons).Cdr continue } + // If the cadr is not special forms then, elt, err := expand(local, global, cadr, level) if err != nil { return nil, err @@ -183,6 +184,8 @@ func expand(local, global environment.Environment, form ilos.Instance, level int } } else { // To expand `((foo ,(- 10 3)) ,@(cdr '(c)) . ,(car '(cons))) + // If the last cell of forms is not Nil, run this statements at first + // the elements of exp is always a instance of because exp isn't appended lists in for-loop slice := exp[i].(instance.List).Slice() for j := len(slice) - 1; j >= 0; j-- { From a99846354bc98047895690849d8ba171e04c9c54 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Thu, 17 Aug 2017 22:55:53 +0900 Subject: [PATCH 192/228] Added test for defmacro --- runtime/macros_test.go | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/runtime/macros_test.go b/runtime/macros_test.go index 2073c3d..43721a0 100644 --- a/runtime/macros_test.go +++ b/runtime/macros_test.go @@ -8,6 +8,19 @@ import "testing" func TestDefmacro(t *testing.T) { defspecial(Defmacro) + defun(List) + defspecial(Quote) + tests := []test{ + { + exp: "(defmacro caar(x) (list ’car (list ’car x)))", + want: "'caar", + wantErr: false, + }, + } + execTests(t, Defmacro, tests) +} + +func TestQuasiquote(t *testing.T) { defun(List) defun2("+", Add) defspecial(Let) @@ -49,5 +62,5 @@ func TestDefmacro(t *testing.T) { wantErr: false, }, } - execTests(t, Defmacro, tests) + execTests(t, Quasiquote, tests) } From 23e47a2f3294e7e126890cdaa53be936204458ee Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Fri, 18 Aug 2017 10:46:46 +0900 Subject: [PATCH 193/228] changed from pointer to copy --- runtime/ilos/class/builtinclass.go | 28 ++++++--- runtime/ilos/class/class.go | 93 ++++++++++++++-------------- runtime/ilos/class/primitiveclass.go | 36 ----------- runtime/ilos/ilos.go | 4 +- runtime/ilos/instance/instance.go | 17 ++--- 5 files changed, 77 insertions(+), 101 deletions(-) delete mode 100644 runtime/ilos/class/primitiveclass.go diff --git a/runtime/ilos/class/builtinclass.go b/runtime/ilos/class/builtinclass.go index 573cb48..9539fa9 100644 --- a/runtime/ilos/class/builtinclass.go +++ b/runtime/ilos/class/builtinclass.go @@ -7,31 +7,39 @@ package class import "github.com/ta2gch/iris/runtime/ilos" type builtinclass struct { - parents []ilos.Class - slots []string - name string + supers []ilos.Class + slots []string + name string } -func (*builtinclass) Class() ilos.Class { +func (builtinclass) Class() ilos.Class { return BuiltInClass } -func (p *builtinclass) Parents() []ilos.Class { - return p.parents +func (p builtinclass) Supers() []ilos.Class { + return p.supers } -func (p *builtinclass) Slots() []string { +func (p builtinclass) Slots() []string { return p.slots } -func (i *builtinclass) GetSlotValue(key ilos.Instance, _ ilos.Class) (ilos.Instance, bool) { +func (p builtinclass) InitForms() map[string]ilos.Instance { + return map[string]ilos.Instance{} +} + +func (p builtinclass) InitArgs() map[ilos.Instance]string { + return map[ilos.Instance]string{} +} + +func (p builtinclass) GetSlotValue(key ilos.Instance, _ ilos.Class) (ilos.Instance, bool) { return nil, false } -func (i *builtinclass) SetSlotValue(key ilos.Instance, value ilos.Instance, _ ilos.Class) bool { +func (p builtinclass) SetSlotValue(key ilos.Instance, value ilos.Instance, _ ilos.Class) bool { return false } -func (p *builtinclass) String() string { +func (p builtinclass) String() string { return p.name } diff --git a/runtime/ilos/class/class.go b/runtime/ilos/class/class.go index f4c5421..a03889d 100644 --- a/runtime/ilos/class/class.go +++ b/runtime/ilos/class/class.go @@ -5,21 +5,22 @@ package class import "github.com/ta2gch/iris/runtime/ilos" +import "reflect" func Is(c, p ilos.Class) bool { var sub func(c, p ilos.Class) bool sub = func(c, p ilos.Class) bool { - if c == p { + if reflect.DeepEqual(c, p) { return true } - for _, d := range c.Parents() { + for _, d := range c.Supers() { if sub(d, p) { return true } } return false } - for _, d := range c.Parents() { + for _, d := range c.Supers() { if sub(d, p) { return true } @@ -27,49 +28,49 @@ func Is(c, p ilos.Class) bool { return false } -var Object = &primitiveclass{[]ilos.Class{}, ""} -var BuiltInClass = &primitiveclass{[]ilos.Class{Object}, ""} -var StandardClass = &primitiveclass{[]ilos.Class{Object}, ""} -var BasicArray = &primitiveclass{[]ilos.Class{Object}, ""} -var BasicArrayStar = &primitiveclass{[]ilos.Class{BasicArray}, ""} -var GeneralArrayStar = &primitiveclass{[]ilos.Class{BasicArrayStar}, ""} -var BasicVector = &primitiveclass{[]ilos.Class{BasicArray}, ""} -var GeneralVector = &primitiveclass{[]ilos.Class{BasicVector}, ""} -var String = &primitiveclass{[]ilos.Class{BasicVector}, ""} -var Character = &primitiveclass{[]ilos.Class{Object}, ""} -var Function = &primitiveclass{[]ilos.Class{Object}, ""} -var GenericFunction = &primitiveclass{[]ilos.Class{Function}, ""} -var StandardGenericFunction = &primitiveclass{[]ilos.Class{GenericFunction}, ""} -var List = &primitiveclass{[]ilos.Class{Object}, ""} -var Cons = &primitiveclass{[]ilos.Class{List}, ""} -var Null = &primitiveclass{[]ilos.Class{List}, ""} -var Symbol = &primitiveclass{[]ilos.Class{Object}, ""} -var Number = &primitiveclass{[]ilos.Class{Object}, ""} -var Integer = &primitiveclass{[]ilos.Class{Number}, ""} -var Float = &primitiveclass{[]ilos.Class{Number}, ""} +var Object = builtinclass{[]ilos.Class{}, []string{}, ""} +var BuiltInClass = builtinclass{[]ilos.Class{Object}, []string{}, ""} +var StandardClass = builtinclass{[]ilos.Class{Object}, []string{}, ""} +var BasicArray = builtinclass{[]ilos.Class{Object}, []string{}, ""} +var BasicArrayStar = builtinclass{[]ilos.Class{BasicArray}, []string{}, ""} +var GeneralArrayStar = builtinclass{[]ilos.Class{BasicArrayStar}, []string{}, ""} +var BasicVector = builtinclass{[]ilos.Class{BasicArray}, []string{}, ""} +var GeneralVector = builtinclass{[]ilos.Class{BasicVector}, []string{}, ""} +var String = builtinclass{[]ilos.Class{BasicVector}, []string{}, ""} +var Character = builtinclass{[]ilos.Class{Object}, []string{}, ""} +var Function = builtinclass{[]ilos.Class{Object}, []string{}, ""} +var GenericFunction = builtinclass{[]ilos.Class{Function}, []string{}, ""} +var StandardGenericFunction = builtinclass{[]ilos.Class{GenericFunction}, []string{}, ""} +var List = builtinclass{[]ilos.Class{Object}, []string{}, ""} +var Cons = builtinclass{[]ilos.Class{List}, []string{}, ""} +var Null = builtinclass{[]ilos.Class{List}, []string{}, ""} +var Symbol = builtinclass{[]ilos.Class{Object}, []string{}, ""} +var Number = builtinclass{[]ilos.Class{Object}, []string{}, ""} +var Integer = builtinclass{[]ilos.Class{Number}, []string{}, ""} +var Float = builtinclass{[]ilos.Class{Number}, []string{}, ""} -var SeriousCondition = &builtinclass{[]ilos.Class{Object}, []string{}, ""} -var Error = &builtinclass{[]ilos.Class{SeriousCondition}, []string{}, ""} -var ArithmeticError = &builtinclass{[]ilos.Class{Error}, []string{"OPERATION", "OPERANDS"}, ""} -var DivisionByZero = &builtinclass{[]ilos.Class{ArithmeticError}, []string{}, ""} -var FloatingPointOnderflow = &builtinclass{[]ilos.Class{ArithmeticError}, []string{}, ""} -var FloatingPointUnderflow = &builtinclass{[]ilos.Class{ArithmeticError}, []string{}, ""} -var ControlError = &builtinclass{[]ilos.Class{Error}, []string{}, ""} -var ParseError = &builtinclass{[]ilos.Class{Error}, []string{"STRING", "EXPECTED-CLASS"}, ""} -var ProgramError = &builtinclass{[]ilos.Class{Error}, []string{}, ""} -var DomainError = &builtinclass{[]ilos.Class{ProgramError}, []string{"OBJECT", "EXPECTED-CLASS"}, ""} -var UndefinedEntity = &builtinclass{[]ilos.Class{ProgramError}, []string{"NAME", "NAMESPACE"}, ""} -var UndefinedVariable = &builtinclass{[]ilos.Class{UndefinedEntity}, []string{}, ""} -var UndefinedFunction = &builtinclass{[]ilos.Class{UndefinedEntity}, []string{}, ""} -var SimpleError = &builtinclass{[]ilos.Class{Error}, []string{"FORMAT-STRING", "FORMAT-ARGUMENTS"}, ""} -var StreamError = &builtinclass{[]ilos.Class{Error}, []string{}, ""} -var EndOfStream = &builtinclass{[]ilos.Class{StreamError}, []string{}, ""} -var StorageExhausted = &builtinclass{[]ilos.Class{SeriousCondition}, []string{}, ""} -var StandardObject = &builtinclass{[]ilos.Class{Object}, []string{}, ""} -var Stream = &builtinclass{[]ilos.Class{Object}, []string{"STREAM"}, ""} +var SeriousCondition = builtinclass{[]ilos.Class{Object}, []string{}, ""} +var Error = builtinclass{[]ilos.Class{SeriousCondition}, []string{}, ""} +var ArithmeticError = builtinclass{[]ilos.Class{Error}, []string{"OPERATION", "OPERANDS"}, ""} +var DivisionByZero = builtinclass{[]ilos.Class{ArithmeticError}, []string{}, ""} +var FloatingPointOnderflow = builtinclass{[]ilos.Class{ArithmeticError}, []string{}, ""} +var FloatingPointUnderflow = builtinclass{[]ilos.Class{ArithmeticError}, []string{}, ""} +var ControlError = builtinclass{[]ilos.Class{Error}, []string{}, ""} +var ParseError = builtinclass{[]ilos.Class{Error}, []string{"STRING", "EXPECTED-CLASS"}, ""} +var ProgramError = builtinclass{[]ilos.Class{Error}, []string{}, ""} +var DomainError = builtinclass{[]ilos.Class{ProgramError}, []string{"OBJECT", "EXPECTED-CLASS"}, ""} +var UndefinedEntity = builtinclass{[]ilos.Class{ProgramError}, []string{"NAME", "NAMESPACE"}, ""} +var UndefinedVariable = builtinclass{[]ilos.Class{UndefinedEntity}, []string{}, ""} +var UndefinedFunction = builtinclass{[]ilos.Class{UndefinedEntity}, []string{}, ""} +var SimpleError = builtinclass{[]ilos.Class{Error}, []string{"FORMAT-STRING", "FORMAT-ARGUMENTS"}, ""} +var StreamError = builtinclass{[]ilos.Class{Error}, []string{}, ""} +var EndOfStream = builtinclass{[]ilos.Class{StreamError}, []string{}, ""} +var StorageExhausted = builtinclass{[]ilos.Class{SeriousCondition}, []string{}, ""} +var StandardObject = builtinclass{[]ilos.Class{Object}, []string{}, ""} +var Stream = builtinclass{[]ilos.Class{Object}, []string{"STREAM"}, ""} // Implementation defined -var Escape = &builtinclass{[]ilos.Class{Object}, []string{"TAG"}, ""} -var CatchTag = &builtinclass{[]ilos.Class{Escape}, []string{"OBJECT"}, ""} -var TagbodyTag = &builtinclass{[]ilos.Class{Escape}, []string{}, ""} -var BlockTag = &builtinclass{[]ilos.Class{Escape}, []string{"OBJECT"}, ""} +var Escape = builtinclass{[]ilos.Class{Object}, []string{"TAG"}, ""} +var CatchTag = builtinclass{[]ilos.Class{Escape}, []string{"OBJECT"}, ""} +var TagbodyTag = builtinclass{[]ilos.Class{Escape}, []string{}, ""} +var BlockTag = builtinclass{[]ilos.Class{Escape}, []string{"OBJECT"}, ""} diff --git a/runtime/ilos/class/primitiveclass.go b/runtime/ilos/class/primitiveclass.go deleted file mode 100644 index 7efe6a6..0000000 --- a/runtime/ilos/class/primitiveclass.go +++ /dev/null @@ -1,36 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at http://mozilla.org/MPL/2.0/. - -package class - -import "github.com/ta2gch/iris/runtime/ilos" - -type primitiveclass struct { - parents []ilos.Class - name string -} - -func (*primitiveclass) Class() ilos.Class { - return BuiltInClass -} - -func (p *primitiveclass) Parents() []ilos.Class { - return p.parents -} - -func (p *primitiveclass) Slots() []string { - return []string{} -} - -func (i *primitiveclass) GetSlotValue(key ilos.Instance, _ ilos.Class) (ilos.Instance, bool) { - return nil, false -} - -func (i *primitiveclass) SetSlotValue(key ilos.Instance, value ilos.Instance, _ ilos.Class) bool { - return false -} - -func (p *primitiveclass) String() string { - return p.name -} diff --git a/runtime/ilos/ilos.go b/runtime/ilos/ilos.go index 238be51..0b1335f 100644 --- a/runtime/ilos/ilos.go +++ b/runtime/ilos/ilos.go @@ -6,8 +6,10 @@ package ilos type Class interface { Class() Class - Parents() []Class + Supers() []Class Slots() []string + InitForms() map[string]Instance + InitArgs() map[Instance]string GetSlotValue(Instance, Class) (Instance, bool) SetSlotValue(Instance, Instance, Class) bool String() string diff --git a/runtime/ilos/instance/instance.go b/runtime/ilos/instance/instance.go index 20369e4..7f3e897 100644 --- a/runtime/ilos/instance/instance.go +++ b/runtime/ilos/instance/instance.go @@ -6,6 +6,7 @@ package instance import ( "fmt" + "reflect" "github.com/ta2gch/iris/runtime/ilos" "github.com/ta2gch/iris/runtime/ilos/class" @@ -17,18 +18,18 @@ import ( func New(c ilos.Class, s ...interface{}) ilos.Instance { p := []ilos.Instance{} - for _, q := range c.Parents() { + for _, q := range c.Supers() { p = append(p, New(q, s...)) } t := map[string]ilos.Instance{} for _, n := range c.Slots() { t[n] = s[0].(map[string]ilos.Instance)[n] } - return &instance{c, p, t} + return instance{c, p, t} } func Of(p ilos.Class, i ilos.Instance) bool { - if i.Class() == p { + if reflect.DeepEqual(i.Class(), p) { return true } return class.Is(i.Class(), p) @@ -40,11 +41,11 @@ type instance struct { slots map[string]ilos.Instance } -func (i *instance) Class() ilos.Class { +func (i instance) Class() ilos.Class { return i.class } -func (i *instance) GetSlotValue(key ilos.Instance, class ilos.Class) (ilos.Instance, bool) { +func (i instance) GetSlotValue(key ilos.Instance, class ilos.Class) (ilos.Instance, bool) { if v, ok := i.slots[string(key.(Symbol))]; ok && i.class == class { return v, ok } @@ -56,7 +57,7 @@ func (i *instance) GetSlotValue(key ilos.Instance, class ilos.Class) (ilos.Insta return nil, false } -func (i *instance) SetSlotValue(key ilos.Instance, value ilos.Instance, class ilos.Class) bool { +func (i instance) SetSlotValue(key ilos.Instance, value ilos.Instance, class ilos.Class) bool { if _, ok := i.slots[string(key.(Symbol))]; ok && i.class == class { i.slots[string(key.(Symbol))] = value return true @@ -69,7 +70,7 @@ func (i *instance) SetSlotValue(key ilos.Instance, value ilos.Instance, class il return false } -func (i *instance) Slots() map[string]ilos.Instance { +func (i instance) Slots() map[string]ilos.Instance { m := map[string]ilos.Instance{} for k, v := range i.slots { m[k] = v @@ -84,7 +85,7 @@ func (i *instance) Slots() map[string]ilos.Instance { return m } -func (i *instance) String() string { +func (i instance) String() string { c := i.Class().String() return fmt.Sprintf("#%v %v>", c[:len(c)-1], i.Slots()) } From dd094f98cd41e4e0f23f352041cef3d79ec69388 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Fri, 18 Aug 2017 11:55:13 +0900 Subject: [PATCH 194/228] Moved builtinclass.go --- runtime/defining_classes.go | 61 ++++++++++++++ runtime/environment/environment.go | 3 + runtime/ilos/class/builtinclass.go | 45 ----------- runtime/ilos/class/class.go | 112 +++++++++++--------------- runtime/ilos/ilos.go | 4 +- runtime/ilos/instance/basic-array.go | 7 +- runtime/ilos/instance/builtinclass.go | 48 +++++++++++ runtime/ilos/instance/character.go | 3 +- runtime/ilos/instance/class.go | 52 ++++++++++++ runtime/ilos/instance/error.go | 52 ++++++------ runtime/ilos/instance/function.go | 3 +- runtime/ilos/instance/instance.go | 39 ++++++--- runtime/ilos/instance/list.go | 11 ++- runtime/ilos/instance/number.go | 5 +- runtime/ilos/instance/symbol.go | 3 +- runtime/ilos/instance/tag.go | 17 ++-- 16 files changed, 287 insertions(+), 178 deletions(-) create mode 100644 runtime/defining_classes.go delete mode 100644 runtime/ilos/class/builtinclass.go create mode 100644 runtime/ilos/instance/builtinclass.go create mode 100644 runtime/ilos/instance/class.go diff --git a/runtime/defining_classes.go b/runtime/defining_classes.go new file mode 100644 index 0000000..84edefa --- /dev/null +++ b/runtime/defining_classes.go @@ -0,0 +1,61 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package runtime + +/* +import ( + "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/ilos" + "github.com/ta2gch/iris/runtime/ilos/class" + "github.com/ta2gch/iris/runtime/ilos/instance" +) + +func Defclass(local, global environment.Environment, className, scNames, slotSpecs ilos.Instance, classOpts ...ilos.Instance) (ilos.Instance, ilos.Instance) { + if err := ensure(class.Symbol, className); err != nil { + return nil, err + } + if err := ensure(class.List, scNames, slotSpecs); err != nil { + return nil, err + } + supers := []ilos.Class{} + specs := slotSpecs.(instance.List).Slice() + for _, scName := range scNames.(instance.List).Slice() { + super, ok := global.Class.Get(scName) + if !ok { + return nil, nil // TOOD: Undefined Entity + } + supers = append(supers, super.(ilos.Class)) + } + for _, slotSpec := range slotSpecs.(instance.List).Slice() { + if instance.Of(class.Symbol, slotSpec) { + slotName := slotSpec + } + slotName := slotSpec.(*instance.Cons).Car + slotOpts := slotSpec.(*instance.Cons).Cdr.(instance.List).Slice() + var readerFunctionName, writerFunctionName, boundpFunctionName ilos.Instance + for i := 0; i < len(slotOpts); i += 2 { + switch slotOpts[i] { + case instance.NewSymbol(":INITFORM"): + form := slotOpts[i+1] + case instance.NewSymbol(":INITARG"): + initargName := slotOpts[i+1] + } + } + } + for _, classOpt := range classOpts { + switch classOpt.(*instance.Cons).Car { + case instance.NewSymbol(":METACLASS"): + metaclass := classOpt.(*instance.Cons).Cdr.(*instance.Cons).Car + case instance.NewSymbol(":ABSTRACTP"): + switch classOpt.(*instance.Cons).Cdr.(*instance.Cons).Car { + case T: + case Nil: + default: + } + default: + } + } +} +*/ diff --git a/runtime/environment/environment.go b/runtime/environment/environment.go index 39eb626..ef98947 100644 --- a/runtime/environment/environment.go +++ b/runtime/environment/environment.go @@ -6,6 +6,7 @@ package environment // Environment struct is the struct for keeping functions and variables type Environment struct { + Class stack BlockTag stack TagbodyTag stack CatchTag stack @@ -22,6 +23,7 @@ type Environment struct { // New creates new environment func New() Environment { env := new(Environment) + env.Class = newStack() env.BlockTag = newStack() env.TagbodyTag = newStack() env.CatchTag = newStack() @@ -37,6 +39,7 @@ func New() Environment { } func (env *Environment) Merge(before Environment) { + env.Class = append(before.Class, env.Class...) env.BlockTag = append(before.BlockTag, env.BlockTag...) env.TagbodyTag = append(before.TagbodyTag, env.TagbodyTag...) env.CatchTag = append(before.CatchTag, env.CatchTag...) diff --git a/runtime/ilos/class/builtinclass.go b/runtime/ilos/class/builtinclass.go deleted file mode 100644 index 9539fa9..0000000 --- a/runtime/ilos/class/builtinclass.go +++ /dev/null @@ -1,45 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at http://mozilla.org/MPL/2.0/. - -package class - -import "github.com/ta2gch/iris/runtime/ilos" - -type builtinclass struct { - supers []ilos.Class - slots []string - name string -} - -func (builtinclass) Class() ilos.Class { - return BuiltInClass -} - -func (p builtinclass) Supers() []ilos.Class { - return p.supers -} - -func (p builtinclass) Slots() []string { - return p.slots -} - -func (p builtinclass) InitForms() map[string]ilos.Instance { - return map[string]ilos.Instance{} -} - -func (p builtinclass) InitArgs() map[ilos.Instance]string { - return map[ilos.Instance]string{} -} - -func (p builtinclass) GetSlotValue(key ilos.Instance, _ ilos.Class) (ilos.Instance, bool) { - return nil, false -} - -func (p builtinclass) SetSlotValue(key ilos.Instance, value ilos.Instance, _ ilos.Class) bool { - return false -} - -func (p builtinclass) String() string { - return p.name -} diff --git a/runtime/ilos/class/class.go b/runtime/ilos/class/class.go index a03889d..e07a054 100644 --- a/runtime/ilos/class/class.go +++ b/runtime/ilos/class/class.go @@ -4,73 +4,53 @@ package class -import "github.com/ta2gch/iris/runtime/ilos" -import "reflect" +import ( + "github.com/ta2gch/iris/runtime/ilos/instance" +) -func Is(c, p ilos.Class) bool { - var sub func(c, p ilos.Class) bool - sub = func(c, p ilos.Class) bool { - if reflect.DeepEqual(c, p) { - return true - } - for _, d := range c.Supers() { - if sub(d, p) { - return true - } - } - return false - } - for _, d := range c.Supers() { - if sub(d, p) { - return true - } - } - return false -} +var Object = instance.ObjectClass +var BuiltInClass = instance.BuiltInClassClass +var StandardClass = instance.StandardClassClass +var BasicArray = instance.BasicArrayClass +var BasicArrayStar = instance.BasicArrayStarClass +var GeneralArrayStar = instance.GeneralArrayStarClass +var BasicVector = instance.BasicVectorClass +var GeneralVector = instance.GeneralVectorClass +var String = instance.StringClass +var Character = instance.CharacterClass +var Function = instance.FunctionClass +var GenericFunction = instance.GenericFunctionClass +var StandardGenericFunction = instance.StandardGenericFunctionClass +var List = instance.ListClass +var Cons = instance.ConsClass +var Null = instance.NullClass +var Symbol = instance.SymbolClass +var Number = instance.NumberClass +var Integer = instance.IntegerClass +var Float = instance.FloatClass -var Object = builtinclass{[]ilos.Class{}, []string{}, ""} -var BuiltInClass = builtinclass{[]ilos.Class{Object}, []string{}, ""} -var StandardClass = builtinclass{[]ilos.Class{Object}, []string{}, ""} -var BasicArray = builtinclass{[]ilos.Class{Object}, []string{}, ""} -var BasicArrayStar = builtinclass{[]ilos.Class{BasicArray}, []string{}, ""} -var GeneralArrayStar = builtinclass{[]ilos.Class{BasicArrayStar}, []string{}, ""} -var BasicVector = builtinclass{[]ilos.Class{BasicArray}, []string{}, ""} -var GeneralVector = builtinclass{[]ilos.Class{BasicVector}, []string{}, ""} -var String = builtinclass{[]ilos.Class{BasicVector}, []string{}, ""} -var Character = builtinclass{[]ilos.Class{Object}, []string{}, ""} -var Function = builtinclass{[]ilos.Class{Object}, []string{}, ""} -var GenericFunction = builtinclass{[]ilos.Class{Function}, []string{}, ""} -var StandardGenericFunction = builtinclass{[]ilos.Class{GenericFunction}, []string{}, ""} -var List = builtinclass{[]ilos.Class{Object}, []string{}, ""} -var Cons = builtinclass{[]ilos.Class{List}, []string{}, ""} -var Null = builtinclass{[]ilos.Class{List}, []string{}, ""} -var Symbol = builtinclass{[]ilos.Class{Object}, []string{}, ""} -var Number = builtinclass{[]ilos.Class{Object}, []string{}, ""} -var Integer = builtinclass{[]ilos.Class{Number}, []string{}, ""} -var Float = builtinclass{[]ilos.Class{Number}, []string{}, ""} - -var SeriousCondition = builtinclass{[]ilos.Class{Object}, []string{}, ""} -var Error = builtinclass{[]ilos.Class{SeriousCondition}, []string{}, ""} -var ArithmeticError = builtinclass{[]ilos.Class{Error}, []string{"OPERATION", "OPERANDS"}, ""} -var DivisionByZero = builtinclass{[]ilos.Class{ArithmeticError}, []string{}, ""} -var FloatingPointOnderflow = builtinclass{[]ilos.Class{ArithmeticError}, []string{}, ""} -var FloatingPointUnderflow = builtinclass{[]ilos.Class{ArithmeticError}, []string{}, ""} -var ControlError = builtinclass{[]ilos.Class{Error}, []string{}, ""} -var ParseError = builtinclass{[]ilos.Class{Error}, []string{"STRING", "EXPECTED-CLASS"}, ""} -var ProgramError = builtinclass{[]ilos.Class{Error}, []string{}, ""} -var DomainError = builtinclass{[]ilos.Class{ProgramError}, []string{"OBJECT", "EXPECTED-CLASS"}, ""} -var UndefinedEntity = builtinclass{[]ilos.Class{ProgramError}, []string{"NAME", "NAMESPACE"}, ""} -var UndefinedVariable = builtinclass{[]ilos.Class{UndefinedEntity}, []string{}, ""} -var UndefinedFunction = builtinclass{[]ilos.Class{UndefinedEntity}, []string{}, ""} -var SimpleError = builtinclass{[]ilos.Class{Error}, []string{"FORMAT-STRING", "FORMAT-ARGUMENTS"}, ""} -var StreamError = builtinclass{[]ilos.Class{Error}, []string{}, ""} -var EndOfStream = builtinclass{[]ilos.Class{StreamError}, []string{}, ""} -var StorageExhausted = builtinclass{[]ilos.Class{SeriousCondition}, []string{}, ""} -var StandardObject = builtinclass{[]ilos.Class{Object}, []string{}, ""} -var Stream = builtinclass{[]ilos.Class{Object}, []string{"STREAM"}, ""} +var SeriousCondition = instance.SeriousConditionClass +var Error = instance.ErrorClass +var ArithmeticError = instance.ArithmeticErrorClass +var DivisionByZero = instance.DivisionByZeroClass +var FloatingPointOnderflow = instance.FloatingPointOnderflowClass +var FloatingPointUnderflow = instance.FloatingPointUnderflowClass +var ControlError = instance.ControlErrorClass +var ParseError = instance.ParseErrorClass +var ProgramError = instance.ProgramErrorClass +var DomainError = instance.DomainErrorClass +var UndefinedEntity = instance.UndefinedEntityClass +var UndefinedVariable = instance.UndefinedVariableClass +var UndefinedFunction = instance.UndefinedFunctionClass +var SimpleError = instance.SimpleErrorClass +var StreamError = instance.StreamErrorClass +var EndOfStream = instance.EndOfStreamClass +var StorageExhausted = instance.StorageExhaustedClass +var StandardObject = instance.StandardObjectClass +var Stream = instance.StreamClass // Implementation defined -var Escape = builtinclass{[]ilos.Class{Object}, []string{"TAG"}, ""} -var CatchTag = builtinclass{[]ilos.Class{Escape}, []string{"OBJECT"}, ""} -var TagbodyTag = builtinclass{[]ilos.Class{Escape}, []string{}, ""} -var BlockTag = builtinclass{[]ilos.Class{Escape}, []string{"OBJECT"}, ""} +var Escape = instance.EscapeClass +var CatchTag = instance.CatchTagClass +var TagbodyTag = instance.TagbodyTagClass +var BlockTag = instance.BlockTagClass diff --git a/runtime/ilos/ilos.go b/runtime/ilos/ilos.go index 0b1335f..032e7df 100644 --- a/runtime/ilos/ilos.go +++ b/runtime/ilos/ilos.go @@ -7,9 +7,7 @@ package ilos type Class interface { Class() Class Supers() []Class - Slots() []string - InitForms() map[string]Instance - InitArgs() map[Instance]string + Slots() []Instance GetSlotValue(Instance, Class) (Instance, bool) SetSlotValue(Instance, Instance, Class) bool String() string diff --git a/runtime/ilos/instance/basic-array.go b/runtime/ilos/instance/basic-array.go index 3f46919..54898ff 100644 --- a/runtime/ilos/instance/basic-array.go +++ b/runtime/ilos/instance/basic-array.go @@ -7,7 +7,6 @@ package instance import ( "github.com/k0kubun/pp" "github.com/ta2gch/iris/runtime/ilos" - "github.com/ta2gch/iris/runtime/ilos/class" ) // @@ -24,7 +23,7 @@ func NewGeneralArrayStar(vector []GeneralArrayStar, scalar ilos.Instance) ilos.I } func (GeneralArrayStar) Class() ilos.Class { - return class.GeneralArrayStar + return GeneralArrayStarClass } func (i GeneralArrayStar) GetSlotValue(key ilos.Instance, _ ilos.Class) (ilos.Instance, bool) { @@ -50,7 +49,7 @@ func NewGeneralVector(v []ilos.Instance) ilos.Instance { } func (GeneralVector) Class() ilos.Class { - return class.GeneralVector + return GeneralVectorClass } func (i GeneralVector) GetSlotValue(key ilos.Instance, _ ilos.Class) (ilos.Instance, bool) { @@ -76,7 +75,7 @@ func NewString(s string) ilos.Instance { } func (String) Class() ilos.Class { - return class.String + return StringClass } func (i String) GetSlotValue(key ilos.Instance, _ ilos.Class) (ilos.Instance, bool) { diff --git a/runtime/ilos/instance/builtinclass.go b/runtime/ilos/instance/builtinclass.go new file mode 100644 index 0000000..ea557e8 --- /dev/null +++ b/runtime/ilos/instance/builtinclass.go @@ -0,0 +1,48 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package instance + +import "github.com/ta2gch/iris/runtime/ilos" + +type BuiltInClass struct { + supers []ilos.Class + slots []ilos.Instance + name string +} + +func NewBuiltInClass(name string, super ilos.Class, slots ...string) ilos.Class { + slotNames := []ilos.Instance{} + for _, slot := range slots { + slotNames = append(slotNames, NewSymbol(slot)) + } + if super == nil { + return BuiltInClass{[]ilos.Class{}, slotNames, name} + } + return BuiltInClass{[]ilos.Class{super}, slotNames, name} +} + +func (BuiltInClass) Class() ilos.Class { + return BuiltInClassClass +} + +func (p BuiltInClass) Supers() []ilos.Class { + return p.supers +} + +func (p BuiltInClass) Slots() []ilos.Instance { + return p.slots +} + +func (p BuiltInClass) GetSlotValue(key ilos.Instance, _ ilos.Class) (ilos.Instance, bool) { + return nil, false +} + +func (p BuiltInClass) SetSlotValue(key ilos.Instance, value ilos.Instance, _ ilos.Class) bool { + return false +} + +func (p BuiltInClass) String() string { + return p.name +} diff --git a/runtime/ilos/instance/character.go b/runtime/ilos/instance/character.go index dac8824..5d79399 100644 --- a/runtime/ilos/instance/character.go +++ b/runtime/ilos/instance/character.go @@ -6,7 +6,6 @@ package instance import ( "github.com/ta2gch/iris/runtime/ilos" - "github.com/ta2gch/iris/runtime/ilos/class" ) // @@ -20,7 +19,7 @@ func NewCharacter(r rune) ilos.Instance { } func (Character) Class() ilos.Class { - return class.Character + return CharacterClass } func (i Character) GetSlotValue(key ilos.Instance, _ ilos.Class) (ilos.Instance, bool) { diff --git a/runtime/ilos/instance/class.go b/runtime/ilos/instance/class.go new file mode 100644 index 0000000..17a9475 --- /dev/null +++ b/runtime/ilos/instance/class.go @@ -0,0 +1,52 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package instance + +var ObjectClass = NewBuiltInClass("", nil) +var BuiltInClassClass = NewBuiltInClass("", ObjectClass) +var StandardClassClass = NewBuiltInClass("", ObjectClass) +var BasicArrayClass = NewBuiltInClass("", ObjectClass) +var BasicArrayStarClass = NewBuiltInClass("", BasicArrayClass) +var GeneralArrayStarClass = NewBuiltInClass("", BasicArrayStarClass) +var BasicVectorClass = NewBuiltInClass("", BasicArrayClass) +var GeneralVectorClass = NewBuiltInClass("", BasicVectorClass) +var StringClass = NewBuiltInClass("", BasicVectorClass) +var CharacterClass = NewBuiltInClass("", ObjectClass) +var FunctionClass = NewBuiltInClass("", ObjectClass) +var GenericFunctionClass = NewBuiltInClass("", FunctionClass) +var StandardGenericFunctionClass = NewBuiltInClass("", GenericFunctionClass) +var ListClass = NewBuiltInClass("", ObjectClass) +var ConsClass = NewBuiltInClass("", ListClass) +var NullClass = NewBuiltInClass("", ListClass) +var SymbolClass = NewBuiltInClass("", ObjectClass) +var NumberClass = NewBuiltInClass("", ObjectClass) +var IntegerClass = NewBuiltInClass("", NumberClass) +var FloatClass = NewBuiltInClass("", NumberClass) + +var SeriousConditionClass = NewBuiltInClass("", ObjectClass) +var ErrorClass = NewBuiltInClass("", SeriousConditionClass) +var ArithmeticErrorClass = NewBuiltInClass("", ErrorClass, "OPERATION", "OPERANDS") +var DivisionByZeroClass = NewBuiltInClass("", ArithmeticErrorClass) +var FloatingPointOnderflowClass = NewBuiltInClass("", ArithmeticErrorClass) +var FloatingPointUnderflowClass = NewBuiltInClass("", ArithmeticErrorClass) +var ControlErrorClass = NewBuiltInClass("", ErrorClass) +var ParseErrorClass = NewBuiltInClass("", ErrorClass, "STRING", "EXPECTED-CLASS") +var ProgramErrorClass = NewBuiltInClass("", ErrorClass) +var DomainErrorClass = NewBuiltInClass("", ProgramErrorClass, "OBJECT", "EXPECTED-CLASS") +var UndefinedEntityClass = NewBuiltInClass("", ProgramErrorClass, "NAME", "NAMESPACE") +var UndefinedVariableClass = NewBuiltInClass("", UndefinedEntityClass) +var UndefinedFunctionClass = NewBuiltInClass("", UndefinedEntityClass) +var SimpleErrorClass = NewBuiltInClass("", ErrorClass, "FORMAT-STRING", "FORMAT-ARGUMENTS") +var StreamErrorClass = NewBuiltInClass("", ErrorClass) +var EndOfStreamClass = NewBuiltInClass("", StreamErrorClass) +var StorageExhaustedClass = NewBuiltInClass("", SeriousConditionClass) +var StandardObjectClass = NewBuiltInClass("", ObjectClass) +var StreamClass = NewBuiltInClass("", ObjectClass, "STREAM") + +// Implementation defined +var EscapeClass = NewBuiltInClass("", ObjectClass, "TAG") +var CatchTagClass = NewBuiltInClass("", EscapeClass, "OBJECT") +var TagbodyTagClass = NewBuiltInClass("", EscapeClass) +var BlockTagClass = NewBuiltInClass("", EscapeClass, "OBJECT") diff --git a/runtime/ilos/instance/error.go b/runtime/ilos/instance/error.go index 30f83c1..ecafea0 100644 --- a/runtime/ilos/instance/error.go +++ b/runtime/ilos/instance/error.go @@ -10,7 +10,6 @@ import ( "strings" "github.com/ta2gch/iris/runtime/ilos" - "github.com/ta2gch/iris/runtime/ilos/class" ) func stackTrace() { @@ -35,69 +34,70 @@ func stackTrace() { } func NewArithmeticError(operation, operands ilos.Instance) ilos.Instance { - return New(class.ArithmeticError, map[string]ilos.Instance{ - "OPERATION": operation, - "OPERANDS": operands, + return New(ArithmeticErrorClass, map[ilos.Instance]ilos.Instance{ + Symbol("OPERATION"): operation, + Symbol("OPERANDS"): operands, }) } func NewDivisionByZero(operation, operands ilos.Instance) ilos.Instance { - return New(class.DivisionByZero, map[string]ilos.Instance{ - "OPERATION": operation, - "OPERANDS": operands, + return New(DivisionByZeroClass, map[ilos.Instance]ilos.Instance{ + Symbol("OPERATION"): operation, + Symbol("OPERANDS"): operands, }) } func NewParseError(str, expectedClass ilos.Instance) ilos.Instance { - return New(class.ParseError, map[string]ilos.Instance{ - "STRING": str, - "EXPECTED-CLASS": expectedClass, + return New(ParseErrorClass, map[ilos.Instance]ilos.Instance{ + Symbol("STRING"): str, + Symbol("EXPECTED-CLASS"): expectedClass, }) } func NewDomainError(object ilos.Instance, expectedClass ilos.Class) ilos.Instance { - return New(class.DomainError, map[string]ilos.Instance{"CAUSE": Symbol("DOMAIN-ERROR"), - "OBJECT": object, - "EXPECTED-CLASS": expectedClass, + return New(DomainErrorClass, map[ilos.Instance]ilos.Instance{ + Symbol("CAUSE"): Symbol("DOMAIN-ERROR"), + Symbol("OBJECT"): object, + Symbol("EXPECTED-CLASS"): expectedClass, }) } func NewUndefinedFunction(name ilos.Instance) ilos.Instance { - return New(class.UndefinedFunction, map[string]ilos.Instance{ - "NAME": name, - "NAMESPACE": Symbol("FUNCTION"), + return New(UndefinedFunctionClass, map[ilos.Instance]ilos.Instance{ + Symbol("NAME"): name, + Symbol("NAMESPACE"): Symbol("FUNCTION"), }) } func NewUndefinedVariable(name ilos.Instance) ilos.Instance { - return New(class.UndefinedVariable, map[string]ilos.Instance{ - "NAME": name, - "NAMESPACE": Symbol("VARIABLE"), + return New(UndefinedVariableClass, map[ilos.Instance]ilos.Instance{ + Symbol("NAME"): name, + Symbol("NAMESPACE"): Symbol("VARIABLE"), }) } func NewArityError() ilos.Instance { //stackTrace() - return New(class.ProgramError, map[string]ilos.Instance{}) + return New(ProgramErrorClass, map[ilos.Instance]ilos.Instance{}) } func NewIndexOutOfRange() ilos.Instance { //stackTrace() - return New(class.ProgramError, map[string]ilos.Instance{}) + return New(ProgramErrorClass, map[ilos.Instance]ilos.Instance{}) } func NewImmutableBinding() ilos.Instance { //stackTrace() - return New(class.ProgramError, map[string]ilos.Instance{}) + return New(ProgramErrorClass, map[ilos.Instance]ilos.Instance{}) } func NewSimpleError(formatString, formatArguments ilos.Instance) ilos.Instance { - return New(class.SimpleError, map[string]ilos.Instance{ - "FORMAT-STRING": formatString, - "FORMAT-ARGUMENTS": formatArguments, + return New(SimpleErrorClass, map[ilos.Instance]ilos.Instance{ + Symbol("FORMAT-STRING"): formatString, + Symbol("FORMAT-ARGUMENTS"): formatArguments, }) } func NewControlError() ilos.Instance { - return New(class.ControlError) + return New(ControlErrorClass) } diff --git a/runtime/ilos/instance/function.go b/runtime/ilos/instance/function.go index b4fbd21..0c6294c 100644 --- a/runtime/ilos/instance/function.go +++ b/runtime/ilos/instance/function.go @@ -10,7 +10,6 @@ import ( "github.com/ta2gch/iris/runtime/environment" "github.com/ta2gch/iris/runtime/ilos" - "github.com/ta2gch/iris/runtime/ilos/class" ) type Applicable interface { @@ -27,7 +26,7 @@ func NewFunction(name ilos.Instance, function interface{}) ilos.Instance { } func (Function) Class() ilos.Class { - return class.Function + return FunctionClass } func (Function) GetSlotValue(key ilos.Instance, _ ilos.Class) (ilos.Instance, bool) { diff --git a/runtime/ilos/instance/instance.go b/runtime/ilos/instance/instance.go index 7f3e897..3e19979 100644 --- a/runtime/ilos/instance/instance.go +++ b/runtime/ilos/instance/instance.go @@ -9,7 +9,6 @@ import ( "reflect" "github.com/ta2gch/iris/runtime/ilos" - "github.com/ta2gch/iris/runtime/ilos/class" ) // @@ -21,24 +20,44 @@ func New(c ilos.Class, s ...interface{}) ilos.Instance { for _, q := range c.Supers() { p = append(p, New(q, s...)) } - t := map[string]ilos.Instance{} + t := map[ilos.Instance]ilos.Instance{} for _, n := range c.Slots() { - t[n] = s[0].(map[string]ilos.Instance)[n] + t[n] = s[0].(map[ilos.Instance]ilos.Instance)[n] } return instance{c, p, t} } func Of(p ilos.Class, i ilos.Instance) bool { + is := func(c, p ilos.Class) bool { + var sub func(c, p ilos.Class) bool + sub = func(c, p ilos.Class) bool { + if reflect.DeepEqual(c, p) { + return true + } + for _, d := range c.Supers() { + if sub(d, p) { + return true + } + } + return false + } + for _, d := range c.Supers() { + if sub(d, p) { + return true + } + } + return false + } if reflect.DeepEqual(i.Class(), p) { return true } - return class.Is(i.Class(), p) + return is(i.Class(), p) } type instance struct { class ilos.Class supers []ilos.Instance - slots map[string]ilos.Instance + slots map[ilos.Instance]ilos.Instance } func (i instance) Class() ilos.Class { @@ -46,7 +65,7 @@ func (i instance) Class() ilos.Class { } func (i instance) GetSlotValue(key ilos.Instance, class ilos.Class) (ilos.Instance, bool) { - if v, ok := i.slots[string(key.(Symbol))]; ok && i.class == class { + if v, ok := i.slots[key]; ok && i.class == class { return v, ok } for _, s := range i.supers { @@ -58,8 +77,8 @@ func (i instance) GetSlotValue(key ilos.Instance, class ilos.Class) (ilos.Instan } func (i instance) SetSlotValue(key ilos.Instance, value ilos.Instance, class ilos.Class) bool { - if _, ok := i.slots[string(key.(Symbol))]; ok && i.class == class { - i.slots[string(key.(Symbol))] = value + if _, ok := i.slots[key]; ok && i.class == class { + i.slots[key] = value return true } for _, s := range i.supers { @@ -70,8 +89,8 @@ func (i instance) SetSlotValue(key ilos.Instance, value ilos.Instance, class ilo return false } -func (i instance) Slots() map[string]ilos.Instance { - m := map[string]ilos.Instance{} +func (i instance) Slots() map[ilos.Instance]ilos.Instance { + m := map[ilos.Instance]ilos.Instance{} for k, v := range i.slots { m[k] = v } diff --git a/runtime/ilos/instance/list.go b/runtime/ilos/instance/list.go index e2f8958..efe8769 100644 --- a/runtime/ilos/instance/list.go +++ b/runtime/ilos/instance/list.go @@ -8,7 +8,6 @@ import ( "fmt" "github.com/ta2gch/iris/runtime/ilos" - "github.com/ta2gch/iris/runtime/ilos/class" ) type List interface { @@ -29,7 +28,7 @@ func NewCons(car, cdr ilos.Instance) ilos.Instance { } func (*Cons) Class() ilos.Class { - return class.Cons + return ConsClass } func (i *Cons) GetSlotValue(key ilos.Instance, _ ilos.Class) (ilos.Instance, bool) { @@ -61,11 +60,11 @@ func (i *Cons) SetSlotValue(key ilos.Instance, value ilos.Instance, _ ilos.Class func (i *Cons) String() string { str := "(" + fmt.Sprint(i.Car) cdr := i.Cdr - for Of(class.Cons, cdr) { + for Of(ConsClass, cdr) { str += fmt.Sprintf(" %v", cdr.(*Cons).Car) // Checked at the top of this loop cdr = cdr.(*Cons).Cdr // Checked at the top of this loop } - if Of(class.Null, cdr) { + if Of(NullClass, cdr) { str += ")" } else { str += fmt.Sprintf(" . %v)", cdr) @@ -76,7 +75,7 @@ func (i *Cons) String() string { func (i *Cons) Slice() []ilos.Instance { s := []ilos.Instance{} var cdr ilos.Instance = i - for Of(class.Cons, cdr) { + for Of(ConsClass, cdr) { s = append(s, cdr.(*Cons).Car) cdr = cdr.(*Cons).Cdr } @@ -96,7 +95,7 @@ func NewNull() ilos.Instance { } func (*Null) Class() ilos.Class { - return class.Null + return NullClass } func (i *Null) GetSlotValue(key ilos.Instance, _ ilos.Class) (ilos.Instance, bool) { diff --git a/runtime/ilos/instance/number.go b/runtime/ilos/instance/number.go index 7ae1737..fe5d450 100644 --- a/runtime/ilos/instance/number.go +++ b/runtime/ilos/instance/number.go @@ -8,7 +8,6 @@ import ( "fmt" "github.com/ta2gch/iris/runtime/ilos" - "github.com/ta2gch/iris/runtime/ilos/class" ) // @@ -21,7 +20,7 @@ func NewInteger(i int) ilos.Instance { return Integer(i) } func (Integer) Class() ilos.Class { - return class.Integer + return IntegerClass } func (i Integer) GetSlotValue(key ilos.Instance, _ ilos.Class) (ilos.Instance, bool) { @@ -47,7 +46,7 @@ func NewFloat(i float64) ilos.Instance { } func (Float) Class() ilos.Class { - return class.Float + return FloatClass } func (i Float) GetSlotValue(key ilos.Instance, _ ilos.Class) (ilos.Instance, bool) { diff --git a/runtime/ilos/instance/symbol.go b/runtime/ilos/instance/symbol.go index 53a95c6..ef2e415 100644 --- a/runtime/ilos/instance/symbol.go +++ b/runtime/ilos/instance/symbol.go @@ -6,7 +6,6 @@ package instance import ( "github.com/ta2gch/iris/runtime/ilos" - "github.com/ta2gch/iris/runtime/ilos/class" ) // @@ -20,7 +19,7 @@ func NewSymbol(s string) ilos.Instance { } func (Symbol) Class() ilos.Class { - return class.Symbol + return SymbolClass } func (i Symbol) GetSlotValue(key ilos.Instance, _ ilos.Class) (ilos.Instance, bool) { diff --git a/runtime/ilos/instance/tag.go b/runtime/ilos/instance/tag.go index 47262dd..4d11bd6 100644 --- a/runtime/ilos/instance/tag.go +++ b/runtime/ilos/instance/tag.go @@ -6,23 +6,22 @@ package instance import ( "github.com/ta2gch/iris/runtime/ilos" - "github.com/ta2gch/iris/runtime/ilos/class" ) func NewBlockTag(tag, object ilos.Instance) ilos.Instance { - return New(class.BlockTag, map[string]ilos.Instance{ - "TAG": tag, - "OBJECT": object, + return New(BlockTagClass, map[ilos.Instance]ilos.Instance{ + Symbol("TAG"): tag, + Symbol("OBJECT"): object, }) } func NewCatchTag(tag, object ilos.Instance) ilos.Instance { - return New(class.CatchTag, map[string]ilos.Instance{ - "TAG": tag, - "OBJECT": object, + return New(CatchTagClass, map[ilos.Instance]ilos.Instance{ + Symbol("TAG"): tag, + Symbol("OBJECT"): object, }) } func NewTagbodyTag(tag ilos.Instance) ilos.Instance { - return New(class.TagbodyTag, map[string]ilos.Instance{ - "TAG": tag, + return New(TagbodyTagClass, map[ilos.Instance]ilos.Instance{ + Symbol("TAG"): tag, }) } From 77a7b8158b698e72e915b5f584959b6abdca55cd Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Fri, 18 Aug 2017 14:13:25 +0900 Subject: [PATCH 195/228] Added defclass --- runtime/defining_classes.go | 59 ++++++++++++++----- runtime/ilos/ilos.go | 4 +- .../{builtinclass.go => built-in-class.go} | 30 +++++++--- runtime/ilos/instance/error.go | 52 ++++++++-------- runtime/ilos/instance/instance.go | 18 ++++-- runtime/ilos/instance/standard-class.go | 59 +++++++++++++++++++ runtime/ilos/instance/tag.go | 16 ++--- 7 files changed, 175 insertions(+), 63 deletions(-) rename runtime/ilos/instance/{builtinclass.go => built-in-class.go} (69%) create mode 100644 runtime/ilos/instance/standard-class.go diff --git a/runtime/defining_classes.go b/runtime/defining_classes.go index 84edefa..0172d61 100644 --- a/runtime/defining_classes.go +++ b/runtime/defining_classes.go @@ -4,7 +4,6 @@ package runtime -/* import ( "github.com/ta2gch/iris/runtime/environment" "github.com/ta2gch/iris/runtime/ilos" @@ -12,6 +11,13 @@ import ( "github.com/ta2gch/iris/runtime/ilos/instance" ) +func Class(local, global environment.Environment, className ilos.Instance) (ilos.Class, ilos.Instance) { + if v, ok := global.Class.Get(className); ok { + return v.(ilos.Class), nil + } + return nil, nil +} + func Defclass(local, global environment.Environment, className, scNames, slotSpecs ilos.Instance, classOpts ...ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Symbol, className); err != nil { return nil, err @@ -20,42 +26,65 @@ func Defclass(local, global environment.Environment, className, scNames, slotSpe return nil, err } supers := []ilos.Class{} - specs := slotSpecs.(instance.List).Slice() for _, scName := range scNames.(instance.List).Slice() { - super, ok := global.Class.Get(scName) - if !ok { - return nil, nil // TOOD: Undefined Entity + super, err := Class(local, global, scName) + if err != nil { + return nil, err } supers = append(supers, super.(ilos.Class)) } + slots := []ilos.Instance{} + initforms := map[ilos.Instance]ilos.Instance{} + initargs := map[ilos.Instance]ilos.Instance{} for _, slotSpec := range slotSpecs.(instance.List).Slice() { if instance.Of(class.Symbol, slotSpec) { slotName := slotSpec + slots = append(slots, slotName) + continue } slotName := slotSpec.(*instance.Cons).Car + slots = append(slots, slotName) slotOpts := slotSpec.(*instance.Cons).Cdr.(instance.List).Slice() - var readerFunctionName, writerFunctionName, boundpFunctionName ilos.Instance for i := 0; i < len(slotOpts); i += 2 { switch slotOpts[i] { case instance.NewSymbol(":INITFORM"): - form := slotOpts[i+1] + initforms[slotName] = slotOpts[i+1] case instance.NewSymbol(":INITARG"): - initargName := slotOpts[i+1] + initargs[slotOpts[i+1]] = slotName } } } + metaclass := class.StandardClass + abstractp := Nil for _, classOpt := range classOpts { + var err ilos.Instance switch classOpt.(*instance.Cons).Car { case instance.NewSymbol(":METACLASS"): - metaclass := classOpt.(*instance.Cons).Cdr.(*instance.Cons).Car + if metaclass, err = Class(local, global, classOpt.(*instance.Cons).Cdr.(*instance.Cons).Car); err != nil { + return nil, err + } case instance.NewSymbol(":ABSTRACTP"): - switch classOpt.(*instance.Cons).Cdr.(*instance.Cons).Car { - case T: - case Nil: - default: + if abstractp, err = Eval(local, global, classOpt.(*instance.Cons).Cdr.(*instance.Cons).Car); err != nil { + return nil, err + } + } + } + global.Class.Define(className, instance.NewStandardClass(className, supers, slots, initforms, initargs, metaclass, abstractp)) + for _, slotSpec := range slotSpecs.(instance.List).Slice() { + if instance.Of(class.Symbol, slotSpec) { + continue + } + // slotName := slotSpec.(*instance.Cons).Car + slotOpts := slotSpec.(*instance.Cons).Cdr.(instance.List).Slice() + for i := 0; i < len(slotOpts); i += 2 { + switch slotOpts[i] { + // Add to generic functions + case instance.NewSymbol(":READER"): + case instance.NewSymbol(":WRITER"): + case instance.NewSymbol(":ACCESSOR"): + case instance.NewSymbol(":BOUNDP"): } - default: } } + return className, nil } -*/ diff --git a/runtime/ilos/ilos.go b/runtime/ilos/ilos.go index 032e7df..ec31f20 100644 --- a/runtime/ilos/ilos.go +++ b/runtime/ilos/ilos.go @@ -5,9 +5,11 @@ package ilos type Class interface { - Class() Class Supers() []Class Slots() []Instance + Initform(Instance) (Instance, bool) + Initarg(Instance) (Instance, bool) + Class() Class GetSlotValue(Instance, Class) (Instance, bool) SetSlotValue(Instance, Instance, Class) bool String() string diff --git a/runtime/ilos/instance/builtinclass.go b/runtime/ilos/instance/built-in-class.go similarity index 69% rename from runtime/ilos/instance/builtinclass.go rename to runtime/ilos/instance/built-in-class.go index ea557e8..7c8e712 100644 --- a/runtime/ilos/instance/builtinclass.go +++ b/runtime/ilos/instance/built-in-class.go @@ -4,12 +4,16 @@ package instance -import "github.com/ta2gch/iris/runtime/ilos" +import ( + "fmt" + + "github.com/ta2gch/iris/runtime/ilos" +) type BuiltInClass struct { + name ilos.Instance supers []ilos.Class slots []ilos.Instance - name string } func NewBuiltInClass(name string, super ilos.Class, slots ...string) ilos.Class { @@ -18,13 +22,9 @@ func NewBuiltInClass(name string, super ilos.Class, slots ...string) ilos.Class slotNames = append(slotNames, NewSymbol(slot)) } if super == nil { - return BuiltInClass{[]ilos.Class{}, slotNames, name} + return BuiltInClass{NewSymbol(name), []ilos.Class{}, slotNames} } - return BuiltInClass{[]ilos.Class{super}, slotNames, name} -} - -func (BuiltInClass) Class() ilos.Class { - return BuiltInClassClass + return BuiltInClass{NewSymbol(name), []ilos.Class{super}, slotNames} } func (p BuiltInClass) Supers() []ilos.Class { @@ -35,6 +35,18 @@ func (p BuiltInClass) Slots() []ilos.Instance { return p.slots } +func (p BuiltInClass) Initform(arg ilos.Instance) (ilos.Instance, bool) { + return arg, true +} + +func (p BuiltInClass) Initarg(arg ilos.Instance) (ilos.Instance, bool) { + return nil, false +} + +func (BuiltInClass) Class() ilos.Class { + return BuiltInClassClass +} + func (p BuiltInClass) GetSlotValue(key ilos.Instance, _ ilos.Class) (ilos.Instance, bool) { return nil, false } @@ -44,5 +56,5 @@ func (p BuiltInClass) SetSlotValue(key ilos.Instance, value ilos.Instance, _ ilo } func (p BuiltInClass) String() string { - return p.name + return fmt.Sprint(p.name) } diff --git a/runtime/ilos/instance/error.go b/runtime/ilos/instance/error.go index ecafea0..08c3e0f 100644 --- a/runtime/ilos/instance/error.go +++ b/runtime/ilos/instance/error.go @@ -34,70 +34,70 @@ func stackTrace() { } func NewArithmeticError(operation, operands ilos.Instance) ilos.Instance { - return New(ArithmeticErrorClass, map[ilos.Instance]ilos.Instance{ - Symbol("OPERATION"): operation, - Symbol("OPERANDS"): operands, + return newInstance(ArithmeticErrorClass, map[ilos.Instance]ilos.Instance{ + NewSymbol("OPERATION"): operation, + NewSymbol("OPERANDS"): operands, }) } func NewDivisionByZero(operation, operands ilos.Instance) ilos.Instance { - return New(DivisionByZeroClass, map[ilos.Instance]ilos.Instance{ - Symbol("OPERATION"): operation, - Symbol("OPERANDS"): operands, + return newInstance(DivisionByZeroClass, map[ilos.Instance]ilos.Instance{ + NewSymbol("OPERATION"): operation, + NewSymbol("OPERANDS"): operands, }) } func NewParseError(str, expectedClass ilos.Instance) ilos.Instance { - return New(ParseErrorClass, map[ilos.Instance]ilos.Instance{ - Symbol("STRING"): str, - Symbol("EXPECTED-CLASS"): expectedClass, + return newInstance(ParseErrorClass, map[ilos.Instance]ilos.Instance{ + NewSymbol("STRING"): str, + NewSymbol("EXPECTED-CLASS"): expectedClass, }) } func NewDomainError(object ilos.Instance, expectedClass ilos.Class) ilos.Instance { - return New(DomainErrorClass, map[ilos.Instance]ilos.Instance{ - Symbol("CAUSE"): Symbol("DOMAIN-ERROR"), - Symbol("OBJECT"): object, - Symbol("EXPECTED-CLASS"): expectedClass, + return newInstance(DomainErrorClass, map[ilos.Instance]ilos.Instance{ + NewSymbol("CAUSE"): NewSymbol("DOMAIN-ERROR"), + NewSymbol("OBJECT"): object, + NewSymbol("EXPECTED-CLASS"): expectedClass, }) } func NewUndefinedFunction(name ilos.Instance) ilos.Instance { - return New(UndefinedFunctionClass, map[ilos.Instance]ilos.Instance{ - Symbol("NAME"): name, - Symbol("NAMESPACE"): Symbol("FUNCTION"), + return newInstance(UndefinedFunctionClass, map[ilos.Instance]ilos.Instance{ + NewSymbol("NAME"): name, + NewSymbol("NAMESPACE"): NewSymbol("FUNCTION"), }) } func NewUndefinedVariable(name ilos.Instance) ilos.Instance { - return New(UndefinedVariableClass, map[ilos.Instance]ilos.Instance{ - Symbol("NAME"): name, - Symbol("NAMESPACE"): Symbol("VARIABLE"), + return newInstance(UndefinedVariableClass, map[ilos.Instance]ilos.Instance{ + NewSymbol("NAME"): name, + NewSymbol("NAMESPACE"): NewSymbol("VARIABLE"), }) } func NewArityError() ilos.Instance { //stackTrace() - return New(ProgramErrorClass, map[ilos.Instance]ilos.Instance{}) + return newInstance(ProgramErrorClass, map[ilos.Instance]ilos.Instance{}) } func NewIndexOutOfRange() ilos.Instance { //stackTrace() - return New(ProgramErrorClass, map[ilos.Instance]ilos.Instance{}) + return newInstance(ProgramErrorClass, map[ilos.Instance]ilos.Instance{}) } func NewImmutableBinding() ilos.Instance { //stackTrace() - return New(ProgramErrorClass, map[ilos.Instance]ilos.Instance{}) + return newInstance(ProgramErrorClass, map[ilos.Instance]ilos.Instance{}) } func NewSimpleError(formatString, formatArguments ilos.Instance) ilos.Instance { - return New(SimpleErrorClass, map[ilos.Instance]ilos.Instance{ - Symbol("FORMAT-STRING"): formatString, - Symbol("FORMAT-ARGUMENTS"): formatArguments, + return newInstance(SimpleErrorClass, map[ilos.Instance]ilos.Instance{ + NewSymbol("FORMAT-STRING"): formatString, + NewSymbol("FORMAT-ARGUMENTS"): formatArguments, }) } func NewControlError() ilos.Instance { - return New(ControlErrorClass) + return newInstance(ControlErrorClass) } diff --git a/runtime/ilos/instance/instance.go b/runtime/ilos/instance/instance.go index 3e19979..704c3a0 100644 --- a/runtime/ilos/instance/instance.go +++ b/runtime/ilos/instance/instance.go @@ -15,15 +15,25 @@ import ( // instance // -func New(c ilos.Class, s ...interface{}) ilos.Instance { +func newInstance(c ilos.Class, s ...interface{}) ilos.Instance { p := []ilos.Instance{} for _, q := range c.Supers() { - p = append(p, New(q, s...)) + p = append(p, newInstance(q, s...)) } t := map[ilos.Instance]ilos.Instance{} - for _, n := range c.Slots() { - t[n] = s[0].(map[ilos.Instance]ilos.Instance)[n] + for argName, argValue := range s[0].(map[ilos.Instance]ilos.Instance) { + if slotName, ok := c.Initarg(argName); ok { + t[slotName] = argValue + } } + /* + for _, slotName := range c.Slots() { + if _, ok := t[slotName]; !ok { + t[slotName], _ = c.Initform(slotName) + t[slotName], _ = Eval(local, global, t[slotName]) + } + } + */ return instance{c, p, t} } diff --git a/runtime/ilos/instance/standard-class.go b/runtime/ilos/instance/standard-class.go new file mode 100644 index 0000000..425d4c8 --- /dev/null +++ b/runtime/ilos/instance/standard-class.go @@ -0,0 +1,59 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package instance + +import ( + "fmt" + + "github.com/ta2gch/iris/runtime/ilos" +) + +type StandardClass struct { + name ilos.Instance + supers []ilos.Class + slots []ilos.Instance + initforms map[ilos.Instance]ilos.Instance + initargs map[ilos.Instance]ilos.Instance + metaclass ilos.Class + abstractp ilos.Instance +} + +func NewStandardClass(name ilos.Instance, supers []ilos.Class, slots []ilos.Instance, initforms, initargs map[ilos.Instance]ilos.Instance, metaclass ilos.Class, abstractp ilos.Instance) ilos.Class { + return StandardClass{name, supers, slots, initforms, initargs, metaclass, abstractp} +} + +func (p StandardClass) Supers() []ilos.Class { + return p.supers +} + +func (p StandardClass) Slots() []ilos.Instance { + return p.slots +} + +func (p StandardClass) Initform(arg ilos.Instance) (ilos.Instance, bool) { + v, ok := p.initforms[arg] + return v, ok +} + +func (p StandardClass) Initarg(arg ilos.Instance) (ilos.Instance, bool) { + v, ok := p.initargs[arg] + return v, ok +} + +func (p StandardClass) Class() ilos.Class { + return p.metaclass +} + +func (p StandardClass) GetSlotValue(key ilos.Instance, _ ilos.Class) (ilos.Instance, bool) { + return nil, false +} + +func (p StandardClass) SetSlotValue(key ilos.Instance, value ilos.Instance, _ ilos.Class) bool { + return false +} + +func (p StandardClass) String() string { + return fmt.Sprint(p.name) +} diff --git a/runtime/ilos/instance/tag.go b/runtime/ilos/instance/tag.go index 4d11bd6..a3d7d67 100644 --- a/runtime/ilos/instance/tag.go +++ b/runtime/ilos/instance/tag.go @@ -9,19 +9,19 @@ import ( ) func NewBlockTag(tag, object ilos.Instance) ilos.Instance { - return New(BlockTagClass, map[ilos.Instance]ilos.Instance{ - Symbol("TAG"): tag, - Symbol("OBJECT"): object, + return newInstance(BlockTagClass, map[ilos.Instance]ilos.Instance{ + NewSymbol("TAG"): tag, + NewSymbol("OBJECT"): object, }) } func NewCatchTag(tag, object ilos.Instance) ilos.Instance { - return New(CatchTagClass, map[ilos.Instance]ilos.Instance{ - Symbol("TAG"): tag, - Symbol("OBJECT"): object, + return newInstance(CatchTagClass, map[ilos.Instance]ilos.Instance{ + NewSymbol("TAG"): tag, + NewSymbol("OBJECT"): object, }) } func NewTagbodyTag(tag ilos.Instance) ilos.Instance { - return New(TagbodyTagClass, map[ilos.Instance]ilos.Instance{ - Symbol("TAG"): tag, + return newInstance(TagbodyTagClass, map[ilos.Instance]ilos.Instance{ + NewSymbol("TAG"): tag, }) } From 51dd24152e91fbe5a8841578aac56d74c68224d3 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Sat, 19 Aug 2017 22:22:12 +0900 Subject: [PATCH 196/228] Added defgeneric --- runtime/array_operations.go | 18 +- runtime/character_class.go | 2 +- runtime/cons.go | 2 +- runtime/defining_classes.go | 4 +- runtime/environment/environment.go | 5 + runtime/equality.go | 3 +- runtime/eval.go | 15 +- runtime/float_class.go | 2 +- runtime/functions.go | 2 +- runtime/ilos/ilos.go | 35 ++++ runtime/ilos/instance/class.go | 6 +- runtime/ilos/instance/function.go | 257 ++++++++++++++++++++++++++++- runtime/ilos/instance/instance.go | 28 ---- runtime/ilos/instance/list.go | 6 +- runtime/integer_class.go | 2 +- runtime/list_operations.go | 2 +- runtime/macros.go | 10 +- runtime/non-local_exits.go | 22 +-- runtime/number_class.go | 20 +-- runtime/sequence_functions.go | 32 ++-- runtime/string_class.go | 4 +- runtime/symbol_class.go | 2 +- runtime/util.go | 8 +- runtime/vectors.go | 6 +- 24 files changed, 379 insertions(+), 114 deletions(-) diff --git a/runtime/array_operations.go b/runtime/array_operations.go index 1cc41b4..88617ac 100644 --- a/runtime/array_operations.go +++ b/runtime/array_operations.go @@ -14,7 +14,7 @@ import ( // BasicArrayP returns t if obj is a basic-array (instance of class basic-array); // otherwise, returns nil. obj may be any ISLISP object. func BasicArrayP(local, global environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { - if instance.Of(class.BasicArray, obj) { + if ilos.InstanceOf(class.BasicArray, obj) { return T, nil } return Nil, nil @@ -23,7 +23,7 @@ func BasicArrayP(local, global environment.Environment, obj ilos.Instance) (ilos // BasicArrayStarP returns t if obj is a basic-array* (instance of class ); // otherwise, returns nil. obj may be any ISLISP object. func BasicArrayStarP(local, global environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { - if instance.Of(class.BasicArrayStar, obj) { + if ilos.InstanceOf(class.BasicArrayStar, obj) { return T, nil } return Nil, nil @@ -32,7 +32,7 @@ func BasicArrayStarP(local, global environment.Environment, obj ilos.Instance) ( // GeneralArrayStarP returns t if obj is a general-array* (instance of class ); // otherwise, returns nil. obj may be any ISLISP object. func GeneralArrayStarP(local, global environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { - if instance.Of(class.GeneralArrayStar, obj) { + if ilos.InstanceOf(class.GeneralArrayStar, obj) { return T, nil } return Nil, nil @@ -101,7 +101,7 @@ func Aref(local, global environment.Environment, basicArray ilos.Instance, dimen return nil, err } switch { - case instance.Of(class.String, basicArray): + case ilos.InstanceOf(class.String, basicArray): if len(dimensions) != 1 { return nil, instance.NewArityError() } @@ -110,7 +110,7 @@ func Aref(local, global environment.Environment, basicArray ilos.Instance, dimen return nil, instance.NewIndexOutOfRange() } return instance.NewCharacter(basicArray.(instance.String)[index]), nil - case instance.Of(class.GeneralVector, basicArray): + case ilos.InstanceOf(class.GeneralVector, basicArray): if len(dimensions) != 1 { return nil, instance.NewArityError() } @@ -158,7 +158,7 @@ func SetAref(local, global environment.Environment, obj, basicArray ilos.Instanc return nil, err } switch { - case instance.Of(class.String, basicArray): + case ilos.InstanceOf(class.String, basicArray): if err := ensure(class.Character, obj); err != nil { return nil, err } @@ -171,7 +171,7 @@ func SetAref(local, global environment.Environment, obj, basicArray ilos.Instanc } basicArray.(instance.String)[index] = rune(obj.(instance.Character)) return obj, nil - case instance.Of(class.GeneralVector, basicArray): + case ilos.InstanceOf(class.GeneralVector, basicArray): if len(dimensions) != 1 { return nil, instance.NewArityError() } @@ -219,9 +219,9 @@ func ArrayDimensions(local, global environment.Environment, basicArray ilos.Inst return nil, err } switch { - case instance.Of(class.String, basicArray): + case ilos.InstanceOf(class.String, basicArray): return List(local, global, instance.NewInteger(len(basicArray.(instance.String)))) - case instance.Of(class.GeneralVector, basicArray): + case ilos.InstanceOf(class.GeneralVector, basicArray): return List(local, global, instance.NewInteger(len(basicArray.(instance.GeneralVector)))) default: // General Array* var array instance.GeneralArrayStar diff --git a/runtime/character_class.go b/runtime/character_class.go index 92195fd..741a183 100644 --- a/runtime/character_class.go +++ b/runtime/character_class.go @@ -14,7 +14,7 @@ import ( // Characterp returns t if obj is a character (instance of class character); // otherwise, returns nil. obj may be any ISLISP object. func Characterp(local, global environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { - if instance.Of(class.Character, obj) { + if ilos.InstanceOf(class.Character, obj) { return T, nil } return Nil, nil diff --git a/runtime/cons.go b/runtime/cons.go index b07e967..560fe3a 100644 --- a/runtime/cons.go +++ b/runtime/cons.go @@ -14,7 +14,7 @@ import ( // Consp returns t if obj is a cons (instance of class cons); // otherwise, returns nil. obj may be any ISLISP object. func Consp(local, global environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { - if instance.Of(class.Cons, obj) { + if ilos.InstanceOf(class.Cons, obj) { return T, nil } return Nil, nil diff --git a/runtime/defining_classes.go b/runtime/defining_classes.go index 0172d61..4ccc157 100644 --- a/runtime/defining_classes.go +++ b/runtime/defining_classes.go @@ -37,7 +37,7 @@ func Defclass(local, global environment.Environment, className, scNames, slotSpe initforms := map[ilos.Instance]ilos.Instance{} initargs := map[ilos.Instance]ilos.Instance{} for _, slotSpec := range slotSpecs.(instance.List).Slice() { - if instance.Of(class.Symbol, slotSpec) { + if ilos.InstanceOf(class.Symbol, slotSpec) { slotName := slotSpec slots = append(slots, slotName) continue @@ -71,7 +71,7 @@ func Defclass(local, global environment.Environment, className, scNames, slotSpe } global.Class.Define(className, instance.NewStandardClass(className, supers, slots, initforms, initargs, metaclass, abstractp)) for _, slotSpec := range slotSpecs.(instance.List).Slice() { - if instance.Of(class.Symbol, slotSpec) { + if ilos.InstanceOf(class.Symbol, slotSpec) { continue } // slotName := slotSpec.(*instance.Cons).Car diff --git a/runtime/environment/environment.go b/runtime/environment/environment.go index ef98947..f902526 100644 --- a/runtime/environment/environment.go +++ b/runtime/environment/environment.go @@ -53,5 +53,10 @@ func (env *Environment) Merge(before Environment) { env.Property = before.Property } +func (env *Environment) PartialMerge(before Environment) { + env.CatchTag = append(before.CatchTag, env.CatchTag...) + env.DynamicVariable = append(before.DynamicVariable, env.DynamicVariable...) +} + // TopLevel is a global environment var TopLevel = New() diff --git a/runtime/equality.go b/runtime/equality.go index 077f352..0b73835 100644 --- a/runtime/equality.go +++ b/runtime/equality.go @@ -10,7 +10,6 @@ import ( "github.com/ta2gch/iris/runtime/environment" "github.com/ta2gch/iris/runtime/ilos" "github.com/ta2gch/iris/runtime/ilos/class" - "github.com/ta2gch/iris/runtime/ilos/instance" ) func isComparable(t reflect.Type) bool { @@ -36,7 +35,7 @@ func isComparable(t reflect.Type) bool { // them (without modifying them), and if modifying one would modify the other the same way. func Eq(local, global environment.Environment, obj1, obj2 ilos.Instance) (ilos.Instance, ilos.Instance) { v1, v2 := reflect.ValueOf(obj1), reflect.ValueOf(obj2) - if v1 == v2 || instance.Of(class.Symbol, obj1) && instance.Of(class.Symbol, obj2) && obj1 == obj2 { + if v1 == v2 || ilos.InstanceOf(class.Symbol, obj1) && ilos.InstanceOf(class.Symbol, obj2) && obj1 == obj2 { return T, nil } return Nil, nil diff --git a/runtime/eval.go b/runtime/eval.go index 3522c35..c1fc640 100644 --- a/runtime/eval.go +++ b/runtime/eval.go @@ -36,7 +36,7 @@ func evalArguments(local, global environment.Environment, arguments ilos.Instanc func evalLambda(local, global environment.Environment, car, cdr ilos.Instance) (ilos.Instance, ilos.Instance, bool) { // eval if lambda form - if instance.Of(class.Cons, car) { + if ilos.InstanceOf(class.Cons, car) { caar := car.(*instance.Cons).Car // Checked at the top of// This sentence if caar == instance.NewSymbol("LAMBDA") { fun, err := Eval(local, global, car) @@ -49,8 +49,7 @@ func evalLambda(local, global environment.Environment, car, cdr ilos.Instance) ( return nil, err, true } env := environment.New() - env.DynamicVariable = append(local.DynamicVariable, env.DynamicVariable...) - env.CatchTag = append(local.CatchTag, env.CatchTag...) + env.PartialMerge(local) ret, err := fun.(instance.Applicable).Apply(env, global, arguments.(instance.List).Slice()...) if err != nil { return nil, err, true @@ -90,8 +89,7 @@ func evalMacro(local, global environment.Environment, car, cdr ilos.Instance) (i } if mac != nil { env := environment.New() - env.DynamicVariable = append(local.DynamicVariable, env.DynamicVariable...) - env.CatchTag = append(local.DynamicVariable, env.CatchTag...) + env.PartialMerge(local) ret, err := mac.(instance.Applicable).Apply(env, global, cdr.(instance.List).Slice()...) if err != nil { return nil, err, true @@ -116,8 +114,7 @@ func evalFunction(local, global environment.Environment, car, cdr ilos.Instance) } if fun != nil { env := environment.New() - env.DynamicVariable = append(local.DynamicVariable, env.DynamicVariable...) - env.CatchTag = append(local.DynamicVariable, env.CatchTag...) + env.PartialMerge(local) arguments, err := evalArguments(local, global, cdr) if err != nil { return nil, err, true @@ -176,14 +173,14 @@ func Eval(local, global environment.Environment, obj ilos.Instance) (ilos.Instan if obj == Nil { return Nil, nil } - if instance.Of(class.Symbol, obj) { + if ilos.InstanceOf(class.Symbol, obj) { ret, err := evalVariable(local, global, obj) if err != nil { return nil, err } return ret, nil } - if instance.Of(class.Cons, obj) { + if ilos.InstanceOf(class.Cons, obj) { ret, err := evalCons(local, global, obj) if err != nil { return nil, err diff --git a/runtime/float_class.go b/runtime/float_class.go index f70ccfd..e711194 100644 --- a/runtime/float_class.go +++ b/runtime/float_class.go @@ -26,7 +26,7 @@ var ( // Floatp returns t if obj is a float (instance of class float); // otherwise, returns nil. The obj may be any ISLISP object. func Floatp(local, global environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { - if instance.Of(class.Float, obj) { + if ilos.InstanceOf(class.Float, obj) { return T, nil } return Nil, nil diff --git a/runtime/functions.go b/runtime/functions.go index 6f9629b..c16158c 100644 --- a/runtime/functions.go +++ b/runtime/functions.go @@ -20,7 +20,7 @@ import ( // and a function object that is denoted by function-name—if in operator // position—or by (function function-name) elsewhere. func Functionp(local, global environment.Environment, fun ilos.Instance) (ilos.Instance, ilos.Instance) { - if instance.Of(class.Function, fun) { + if ilos.InstanceOf(class.Function, fun) { return T, nil } return Nil, nil diff --git a/runtime/ilos/ilos.go b/runtime/ilos/ilos.go index ec31f20..f3147e1 100644 --- a/runtime/ilos/ilos.go +++ b/runtime/ilos/ilos.go @@ -4,6 +4,10 @@ package ilos +import ( + "reflect" +) + type Class interface { Supers() []Class Slots() []Instance @@ -21,3 +25,34 @@ type Instance interface { SetSlotValue(Instance, Instance, Class) bool String() string } + +func SubclassOf(super, sub Class) bool { + is := func(c, p Class) bool { + var sub func(c, p Class) bool + sub = func(c, p Class) bool { + if reflect.DeepEqual(c, p) { + return true + } + for _, d := range c.Supers() { + if sub(d, p) { + return true + } + } + return false + } + for _, d := range c.Supers() { + if sub(d, p) { + return true + } + } + return false + } + return is(sub, super) +} + +func InstanceOf(p Class, i Instance) bool { + if reflect.DeepEqual(i.Class(), p) { + return true + } + return SubclassOf(p, i.Class()) +} diff --git a/runtime/ilos/instance/class.go b/runtime/ilos/instance/class.go index 17a9475..51879ad 100644 --- a/runtime/ilos/instance/class.go +++ b/runtime/ilos/instance/class.go @@ -4,6 +4,10 @@ package instance +import ( + "github.com/ta2gch/iris/runtime/ilos" +) + var ObjectClass = NewBuiltInClass("", nil) var BuiltInClassClass = NewBuiltInClass("", ObjectClass) var StandardClassClass = NewBuiltInClass("", ObjectClass) @@ -19,7 +23,7 @@ var GenericFunctionClass = NewBuiltInClass("", FunctionClass) var StandardGenericFunctionClass = NewBuiltInClass("", GenericFunctionClass) var ListClass = NewBuiltInClass("", ObjectClass) var ConsClass = NewBuiltInClass("", ListClass) -var NullClass = NewBuiltInClass("", ListClass) +var NullClass = BuiltInClass{NewSymbol(""), []ilos.Class{ListClass, SymbolClass}, []ilos.Instance{}} var SymbolClass = NewBuiltInClass("", ObjectClass) var NumberClass = NewBuiltInClass("", ObjectClass) var IntegerClass = NewBuiltInClass("", NumberClass) diff --git a/runtime/ilos/instance/function.go b/runtime/ilos/instance/function.go index 0c6294c..54f6670 100644 --- a/runtime/ilos/instance/function.go +++ b/runtime/ilos/instance/function.go @@ -7,6 +7,7 @@ package instance import ( "fmt" "reflect" + "sort" "github.com/ta2gch/iris/runtime/environment" "github.com/ta2gch/iris/runtime/ilos" @@ -29,11 +30,11 @@ func (Function) Class() ilos.Class { return FunctionClass } -func (Function) GetSlotValue(key ilos.Instance, _ ilos.Class) (ilos.Instance, bool) { +func (Function) GetSlotValue(_ ilos.Instance, _ ilos.Class) (ilos.Instance, bool) { return nil, false } -func (Function) SetSlotValue(key ilos.Instance, value ilos.Instance, _ ilos.Class) bool { +func (Function) SetSlotValue(_, _ ilos.Instance, _ ilos.Class) bool { return false } @@ -57,3 +58,255 @@ func (f Function) Apply(local, global environment.Environment, arguments ...ilos return a, b } + +type method struct { + qualifier ilos.Instance + classList []ilos.Class + function Function +} + +type GenericFunction struct { + funcSpec ilos.Instance + lambdaList ilos.Instance + methodCombination ilos.Instance + genericFunctionClass ilos.Class + methods []method +} + +func NewGenericFunction(funcSpec, lambdaList, methodCombination ilos.Instance, genericFunctionClass ilos.Class) ilos.Instance { + return GenericFunction{funcSpec, lambdaList, methodCombination, genericFunctionClass, []method{}} +} + +func (GenericFunction) Class() ilos.Class { + return GenericFunctionClass +} + +func (f GenericFunction) GetSlotValue(_ ilos.Instance, _ ilos.Class) (ilos.Instance, bool) { + return nil, false +} + +func (f GenericFunction) SetSlotValue(_, _ ilos.Instance, _ ilos.Class) bool { + return false +} + +func (f GenericFunction) String() string { + return fmt.Sprintf("#%v", f.Class()) +} + +func (f GenericFunction) Apply(local, global environment.Environment, arguments ...ilos.Instance) (ilos.Instance, ilos.Instance) { + parameters := f.lambdaList.(List).Slice() + variadic := false + { + test := func(i int) bool { return parameters[i] == NewSymbol(":REST") || parameters[i] == NewSymbol("&REST") } + if sort.Search(len(parameters), test) < len(parameters) { + variadic = true + } + } + if (variadic && len(parameters)-2 > len(arguments)) || (!variadic && len(parameters) != len(arguments)) { + return nil, NewArityError() + } + methods := []method{} + for _, method := range f.methods { + matched := true + for i, c := range method.classList { + if !ilos.InstanceOf(c, arguments[i]) { + matched = false + break + } + } + if matched { + methods = append(methods, method) + } + } + before := NewSymbol(":BEFORE") + around := NewSymbol(":AROUND") + after := NewSymbol(":AFTER") + sort.Slice(methods, func(a, b int) bool { + for i := range methods[a].classList { + if ilos.SubclassOf(methods[a].classList[i], methods[b].classList[i]) { + return false + } + if ilos.SubclassOf(methods[b].classList[i], methods[a].classList[i]) { + return true + } + } + t := map[ilos.Instance]int{around: 4, before: 3, nil: 2, after: 1} + return t[methods[a].qualifier] > t[methods[b].qualifier] + }) + + nextMethodPisNil := NewFunction(NewSymbol("NEXT-METHOD-P"), func(local, global environment.Environment) (ilos.Instance, ilos.Instance) { + return Nil, nil + }) + nextMethodPisT := NewFunction(NewSymbol("NEXT-METHOD-P"), func(local, global environment.Environment) (ilos.Instance, ilos.Instance) { + return NewSymbol("T"), nil + }) + if f.methodCombination == NewSymbol("NIL") { + var callNextMethod func(local, global environment.Environment) (ilos.Instance, ilos.Instance) // To Recursive + callNextMethod = func(local, global environment.Environment) (ilos.Instance, ilos.Instance) { // CALL-NEXT-METHOD + depth, _ := local.DynamicVariable.Get(NewSymbol("IRIS/DEPTH")) // Get previous depth + index := int(depth.(Integer)) + 1 // Get index of next method + local.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) // Set current depth + // If Generic Function has no next-mehtods, NEXT-METHOD-P local function returns nil + local.Function.Define(NewSymbol("NEXT-METHOD-P"), NewFunction(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil)) + if int(depth.(Integer))+1 < len(methods) { // If Generic Function has next method, set these functionss + local.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) + local.Function.Define(NewSymbol("NEXT-METHOD-P"), NewFunction(NewSymbol("NEXT-METHOD-P"), nextMethodPisT)) + } + return methods[index].function.Apply(local, global, arguments...) // Call next method + } + local.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(0)) // Set current depth + // If Generic Function has no next-mehtods, NEXT-METHOD-P local function returns nil + local.Function.Define(NewSymbol("NEXT-METHOD-P"), NewFunction(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil)) + if 1 < len(methods) { // If Generic Function has next method, set these functionss + local.Function.Define(NewSymbol("NEXT-METHOD-P"), NewFunction(NewSymbol("NEXT-METHOD-P"), nextMethodPisT)) + local.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) + } + return methods[0].function.Apply(local, global, arguments...) //Call first of method + } + // if f.methodCombination == NewSymbol("STANDARD") + { + test := func(i int) bool { return methods[i].qualifier == around } + width := len(methods) + if index := sort.Search(width, test); index < width { // if has :around methods + // This callNextMethod is called in :around methods + var callNextMethod func(local, global environment.Environment) (ilos.Instance, ilos.Instance) + callNextMethod = func(local, global environment.Environment) (ilos.Instance, ilos.Instance) { + depth, _ := local.DynamicVariable.Get(NewSymbol("IRIS/DEPTH")) // Get previous depth + for index, method := range methods[:int(depth.(Integer))+1] { + if method.qualifier == around { // If have :around method + local.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) // Set Current depth + // If Generic Function has no next-mehtods, NEXT-METHOD-P local function returns nil + local.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) + { // If Generic Function has next method, set these functionss + width := len(methods) - index - 1 + test := func(i int) bool { return methods[index+i+1].qualifier == nil || methods[index+i+1].qualifier == around } + if sort.Search(width, test) < width { + local.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) + local.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) + } + } + return methods[int(depth.(Integer))].function.Apply(local, global, arguments...) // Call next method + } + } + // If has no :around method then, + // Do All :before mehtods + for _, method := range methods { + if method.qualifier == before { + if _, err := method.function.Apply(local, global, arguments...); err != nil { + return nil, err + } + } + } + // Do the first of primary methods + // this callNextMethod is called in primary methods + var callNextMethod func(local, global environment.Environment) (ilos.Instance, ilos.Instance) + callNextMethod = func(local, global environment.Environment) (ilos.Instance, ilos.Instance) { + depth, _ := local.DynamicVariable.Get(NewSymbol("IRIS/DEPTH")) // Get previous depth + index := int(depth.(Integer)) // Convert depth to integer + { + width := len(methods) - index - 1 + test := func(i int) bool { return methods[index+i+1].qualifier == nil } + index = sort.Search(width, test) // Get index of next mehotd + local.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) // Set current depth + } + // If Generic Function has no next-mehtods, NEXT-METHOD-P local function returns nil + local.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) + { // If Generic Function has next method, set these functionss + width := len(methods) - index - 1 + test := func(i int) bool { return methods[index+i+1].qualifier == nil } + if sort.Search(width, test) < width { + local.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) + local.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) + } + } + return methods[index].function.Apply(local, global, arguments...) // Call next method + } // callNextMethod ends here + index := 0 // index of the first primary method + { // index != 0 is always true because this function has :around methods + width := len(methods) - index - 1 + test := func(i int) bool { return methods[index+i+1].qualifier == nil } + index = sort.Search(width, test) + local.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) + } + // If Generic Function has no next-mehtods, NEXT-METHOD-P local function returns nil + local.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) + { // If Generic Function has next method, set these functionss + test := func(i int) bool { return methods[index+i+1].qualifier == nil } + width := len(methods) - index - 1 + if sort.Search(width, test) < width { + local.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) + local.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) + } + } + // Do primary methods + ret, err := methods[index].function.Apply(local, global, arguments...) + if err != nil { + return nil, err + } + // Do all :after methods + for i := len(methods) - 1; i >= 0; i-- { + if methods[i].qualifier == after { + if _, err := methods[i].function.Apply(local, global, arguments...); err != nil { + return nil, err + } + } + } + return ret, err + } + local.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) // Set Current depth + // If Generic Function has no next-mehtods, NEXT-METHOD-P local function returns nil + local.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) + { // If Generic Function has next method, set these functionss + test := func(i int) bool { return methods[index+i+1].qualifier == nil } + width := len(methods) - index - 1 + if sort.Search(width, test) < width { + local.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) + local.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) + } + } + return methods[index].function.Apply(local, global, arguments...) + } + } + { // Function has no :around methods + // This callNextMethod is called in primary methods + var callNextMethod func(local, global environment.Environment) (ilos.Instance, ilos.Instance) + callNextMethod = func(local, global environment.Environment) (ilos.Instance, ilos.Instance) { + depth, _ := local.DynamicVariable.Get(NewSymbol("IRIS/DEPTH")) // Get previous depth + index := int(depth.(Integer)) // Convert depth to integer + { + test := func(i int) bool { return methods[index+i+1].qualifier == nil } + width := len(methods) - index - 1 + index = sort.Search(width, test) + } + local.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) // Set Current depth + // If Generic Function has no next-mehtods, NEXT-METHOD-P local function returns nil + local.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) + { // If Generic Function has next method, set these functionss + test := func(i int) bool { return methods[index+i+1].qualifier == nil } + width := len(methods) - index - 1 + if sort.Search(width, test) < width { + local.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) + local.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) + } + } + return methods[int(depth.(Integer))].function.Apply(local, global, arguments...) + } // callNextMethod ends here + index := 0 // index of the first primary method + { + test := func(i int) bool { return methods[i].qualifier == nil } + width := len(methods) + index := sort.Search(width, test) + local.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) + } + local.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) + { // If Generic Function has next method, set these functions + test := func(i int) bool { return methods[index+i+1].qualifier == nil } + width := len(methods) - index - 1 + if sort.Search(width, test) < width { + local.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) + local.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) + } + } + return methods[index].function.Apply(local, global, arguments...) + } +} diff --git a/runtime/ilos/instance/instance.go b/runtime/ilos/instance/instance.go index 704c3a0..b06cbf1 100644 --- a/runtime/ilos/instance/instance.go +++ b/runtime/ilos/instance/instance.go @@ -6,7 +6,6 @@ package instance import ( "fmt" - "reflect" "github.com/ta2gch/iris/runtime/ilos" ) @@ -37,33 +36,6 @@ func newInstance(c ilos.Class, s ...interface{}) ilos.Instance { return instance{c, p, t} } -func Of(p ilos.Class, i ilos.Instance) bool { - is := func(c, p ilos.Class) bool { - var sub func(c, p ilos.Class) bool - sub = func(c, p ilos.Class) bool { - if reflect.DeepEqual(c, p) { - return true - } - for _, d := range c.Supers() { - if sub(d, p) { - return true - } - } - return false - } - for _, d := range c.Supers() { - if sub(d, p) { - return true - } - } - return false - } - if reflect.DeepEqual(i.Class(), p) { - return true - } - return is(i.Class(), p) -} - type instance struct { class ilos.Class supers []ilos.Instance diff --git a/runtime/ilos/instance/list.go b/runtime/ilos/instance/list.go index efe8769..5d410dd 100644 --- a/runtime/ilos/instance/list.go +++ b/runtime/ilos/instance/list.go @@ -60,11 +60,11 @@ func (i *Cons) SetSlotValue(key ilos.Instance, value ilos.Instance, _ ilos.Class func (i *Cons) String() string { str := "(" + fmt.Sprint(i.Car) cdr := i.Cdr - for Of(ConsClass, cdr) { + for ilos.InstanceOf(ConsClass, cdr) { str += fmt.Sprintf(" %v", cdr.(*Cons).Car) // Checked at the top of this loop cdr = cdr.(*Cons).Cdr // Checked at the top of this loop } - if Of(NullClass, cdr) { + if ilos.InstanceOf(NullClass, cdr) { str += ")" } else { str += fmt.Sprintf(" . %v)", cdr) @@ -75,7 +75,7 @@ func (i *Cons) String() string { func (i *Cons) Slice() []ilos.Instance { s := []ilos.Instance{} var cdr ilos.Instance = i - for Of(ConsClass, cdr) { + for ilos.InstanceOf(ConsClass, cdr) { s = append(s, cdr.(*Cons).Car) cdr = cdr.(*Cons).Cdr } diff --git a/runtime/integer_class.go b/runtime/integer_class.go index 0b09a99..929c9de 100644 --- a/runtime/integer_class.go +++ b/runtime/integer_class.go @@ -23,7 +23,7 @@ func convInt(z ilos.Instance) (int, ilos.Instance) { // Integerp returns t if obj is an integer (instance of class integer); // otherwise, returns nil. obj may be any ISLISP object. func Integerp(local, global environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { - if instance.Of(class.Integer, obj) { + if ilos.InstanceOf(class.Integer, obj) { return T, nil } return Nil, nil diff --git a/runtime/list_operations.go b/runtime/list_operations.go index b20a75a..42b602f 100644 --- a/runtime/list_operations.go +++ b/runtime/list_operations.go @@ -16,7 +16,7 @@ import ( // Listp returns t if obj is a list (instance of class list); otherwise, returns nil. // obj may be any ISLISP object. func Listp(local, global environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { - if instance.Of(class.Cons, obj) { + if ilos.InstanceOf(class.Cons, obj) { return T, nil } return Nil, nil diff --git a/runtime/macros.go b/runtime/macros.go index a273aed..3070552 100644 --- a/runtime/macros.go +++ b/runtime/macros.go @@ -50,12 +50,12 @@ func Quasiquote(local, global environment.Environment, form ilos.Instance) (ilos } func expand(local, global environment.Environment, form ilos.Instance, level int) (ilos.Instance, ilos.Instance) { - if !instance.Of(class.Cons, form) { + if !ilos.InstanceOf(class.Cons, form) { return form, nil } // If form is a instance of then, exp := []ilos.Instance{} cdr := form - for instance.Of(class.Cons, cdr) { + for ilos.InstanceOf(class.Cons, cdr) { cadr := cdr.(*instance.Cons).Car cddr := cdr.(*instance.Cons).Cdr // To expand `((foo ,(- 10 3)) ,@(cdr '(c)) . ,(car '(cons))) @@ -68,7 +68,7 @@ func expand(local, global environment.Environment, form ilos.Instance, level int exp = append(exp, elt) break } - if !instance.Of(class.Cons, cadr) { + if !ilos.InstanceOf(class.Cons, cadr) { lst, err := List(local, global, cadr) if err != nil { return nil, err @@ -171,12 +171,12 @@ func expand(local, global environment.Environment, form ilos.Instance, level int cdr = cddr continue } - if instance.Of(class.Null, cdr) { + if ilos.InstanceOf(class.Null, cdr) { exp = append(exp, Nil) } lst := exp[len(exp)-1] for i := len(exp) - 2; i >= 0; i-- { - if instance.Of(class.List, lst) { + if ilos.InstanceOf(class.List, lst) { var err ilos.Instance lst, err = Append(local, global, exp[i], lst) if err != nil { diff --git a/runtime/non-local_exits.go b/runtime/non-local_exits.go index 546e262..ce97962 100644 --- a/runtime/non-local_exits.go +++ b/runtime/non-local_exits.go @@ -44,7 +44,7 @@ func Block(local, global environment.Environment, tag ilos.Instance, body ...ilo if err != nil { return nil, err } - if instance.Of(class.Number, tag) || instance.Of(class.Character, tag) { + if ilos.InstanceOf(class.Number, tag) || ilos.InstanceOf(class.Character, tag) { return nil, instance.NewDomainError(tag, class.Object) } if !local.BlockTag.Define(tag, nil) { @@ -55,7 +55,7 @@ func Block(local, global environment.Environment, tag ilos.Instance, body ...ilo for _, cadr := range body { sucess, fail = Eval(local, global, cadr) if fail != nil { - if instance.Of(class.BlockTag, fail) { + if ilos.InstanceOf(class.BlockTag, fail) { tag1, _ := fail.GetSlotValue(instance.NewSymbol("TAG"), class.Escape) // Checked at the head of// This condition if tag == tag1 { obj, _ := fail.GetSlotValue(instance.NewSymbol("OBJECT"), class.BlockTag) // Checked at the head of// This condition @@ -74,7 +74,7 @@ func ReturnFrom(local, global environment.Environment, tag, object ilos.Instance if err != nil { return nil, err } - if instance.Of(class.Number, tag) || instance.Of(class.Character, tag) { + if ilos.InstanceOf(class.Number, tag) || ilos.InstanceOf(class.Character, tag) { return nil, instance.NewDomainError(tag, class.Object) } object, err = Eval(local, global, object) @@ -93,7 +93,7 @@ func Catch(local, global environment.Environment, tag ilos.Instance, body ...ilo if err != nil { return nil, err } - if instance.Of(class.Number, tag) || instance.Of(class.Character, tag) { + if ilos.InstanceOf(class.Number, tag) || ilos.InstanceOf(class.Character, tag) { return nil, instance.NewDomainError(tag, class.Object) } if !local.CatchTag.Define(tag, nil) { @@ -104,7 +104,7 @@ func Catch(local, global environment.Environment, tag ilos.Instance, body ...ilo for _, cadr := range body { sucess, fail = Eval(local, global, cadr) if fail != nil { - if instance.Of(class.CatchTag, fail) { + if ilos.InstanceOf(class.CatchTag, fail) { tag1, _ := fail.GetSlotValue(instance.NewSymbol("TAG"), class.Escape) // Checked at the head of// This condition if tag == tag1 { obj, _ := fail.GetSlotValue(instance.NewSymbol("OBJECT"), class.CatchTag) // Checked at the head of// This condition @@ -123,7 +123,7 @@ func Throw(local, global environment.Environment, tag, object ilos.Instance) (il if err != nil { return nil, err } - if instance.Of(class.Number, tag) || instance.Of(class.Character, tag) { + if ilos.InstanceOf(class.Number, tag) || ilos.InstanceOf(class.Character, tag) { return nil, instance.NewDomainError(tag, class.Object) } object, err = Eval(local, global, object) @@ -140,18 +140,18 @@ func Throw(local, global environment.Environment, tag, object ilos.Instance) (il func Tagbody(local, global environment.Environment, body ...ilos.Instance) (ilos.Instance, ilos.Instance) { for idx, cadr := range body { cddr := instance.GeneralVector(body[idx+1:]) - if !instance.Of(class.Cons, cadr) { + if !ilos.InstanceOf(class.Cons, cadr) { if !local.TagbodyTag.Define(cadr, cddr) { return nil, instance.NewImmutableBinding() } } } for _, cadr := range body { - if instance.Of(class.Cons, cadr) { + if ilos.InstanceOf(class.Cons, cadr) { _, fail := Eval(local, global, cadr) if fail != nil { TAG: - if instance.Of(class.TagbodyTag, fail) { + if ilos.InstanceOf(class.TagbodyTag, fail) { tag, _ := fail.GetSlotValue(instance.NewSymbol("TAG"), class.Escape) // Checked at the top of// This loop found := false for _, tag1 := range body { @@ -163,7 +163,7 @@ func Tagbody(local, global environment.Environment, body ...ilos.Instance) (ilos if found { forms, _ := local.TagbodyTag.Get(tag) // Checked in the function, tagbodyGo for _, form := range forms.(instance.GeneralVector) { - if instance.Of(class.Cons, form) { + if ilos.InstanceOf(class.Cons, form) { _, fail = Eval(local, global, form) if fail != nil { goto TAG @@ -220,7 +220,7 @@ func Go(local, global environment.Environment, tag ilos.Instance) (ilos.Instance func UnwindProtect(local, global environment.Environment, form ilos.Instance, cleanupForms ...ilos.Instance) (ilos.Instance, ilos.Instance) { ret1, err1 := Eval(local, global, form) ret2, err2 := Progn(local, global, cleanupForms...) - if instance.Of(class.Escape, err2) { + if ilos.InstanceOf(class.Escape, err2) { return nil, instance.NewControlError() } if err2 != nil { diff --git a/runtime/number_class.go b/runtime/number_class.go index 13e983c..8d66d43 100644 --- a/runtime/number_class.go +++ b/runtime/number_class.go @@ -17,7 +17,7 @@ import ( // Numberp returns t if obj is a number (instance of class number); otherwise, // returns nil. The obj may be any ISLISP object. func Numberp(local, global environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { - if instance.Of(class.Number, obj) { + if ilos.InstanceOf(class.Number, obj) { return T, nil } return Nil, nil @@ -34,7 +34,7 @@ func ParseNumber(local, global environment.Environment, str ilos.Instance) (ilos return nil, err } ret, err := parser.ParseAtom(string(str.(instance.String))) - if err != nil || !instance.Of(class.Number, ret) { + if err != nil || !ilos.InstanceOf(class.Number, ret) { return nil, instance.NewParseError(str, class.Number) } return ret, err @@ -52,13 +52,13 @@ func NumberEqual(local, global environment.Environment, x1, x2 ilos.Instance) (i } ret := false switch { - case instance.Of(class.Integer, x1) && instance.Of(class.Integer, x2): + case ilos.InstanceOf(class.Integer, x1) && ilos.InstanceOf(class.Integer, x2): ret = x1 == x2 - case instance.Of(class.Integer, x1) && instance.Of(class.Float, x2): + case ilos.InstanceOf(class.Integer, x1) && ilos.InstanceOf(class.Float, x2): ret = float64(x1.(instance.Integer)) == float64(x2.(instance.Float)) - case instance.Of(class.Float, x1) && instance.Of(class.Integer, x2): + case ilos.InstanceOf(class.Float, x1) && ilos.InstanceOf(class.Integer, x2): ret = float64(x1.(instance.Float)) == float64(x2.(instance.Integer)) - case instance.Of(class.Float, x1) && instance.Of(class.Float, x2): + case ilos.InstanceOf(class.Float, x1) && ilos.InstanceOf(class.Float, x2): ret = x1 == x2 } if ret { @@ -85,13 +85,13 @@ func NumberGreaterThan(local, global environment.Environment, x1, x2 ilos.Instan } ret := false switch { - case instance.Of(class.Integer, x1) && instance.Of(class.Integer, x2): + case ilos.InstanceOf(class.Integer, x1) && ilos.InstanceOf(class.Integer, x2): ret = float64(x1.(instance.Integer)) > float64(x2.(instance.Integer)) - case instance.Of(class.Integer, x1) && instance.Of(class.Float, x2): + case ilos.InstanceOf(class.Integer, x1) && ilos.InstanceOf(class.Float, x2): ret = float64(x1.(instance.Integer)) > float64(x2.(instance.Float)) - case instance.Of(class.Float, x1) && instance.Of(class.Integer, x2): + case ilos.InstanceOf(class.Float, x1) && ilos.InstanceOf(class.Integer, x2): ret = float64(x1.(instance.Float)) > float64(x2.(instance.Integer)) - case instance.Of(class.Float, x1) && instance.Of(class.Float, x2): + case ilos.InstanceOf(class.Float, x1) && ilos.InstanceOf(class.Float, x2): ret = float64(x1.(instance.Float)) > float64(x2.(instance.Float)) } if ret { diff --git a/runtime/sequence_functions.go b/runtime/sequence_functions.go index c4f6830..cb4d985 100644 --- a/runtime/sequence_functions.go +++ b/runtime/sequence_functions.go @@ -26,11 +26,11 @@ import ( // (error-id. domain-error). func Length(local, global environment.Environment, sequence ilos.Instance) (ilos.Instance, ilos.Instance) { switch { - case instance.Of(class.String, sequence): + case ilos.InstanceOf(class.String, sequence): return instance.NewInteger(len(sequence.(instance.String))), nil - case instance.Of(class.GeneralVector, sequence): + case ilos.InstanceOf(class.GeneralVector, sequence): return instance.NewInteger(len(sequence.(instance.GeneralVector))), nil - case instance.Of(class.List, sequence): + case ilos.InstanceOf(class.List, sequence): return instance.NewInteger(len(sequence.(instance.List).Slice())), nil } // TODO: class.Seq @@ -49,21 +49,21 @@ func Elt(local, global environment.Environment, sequence, z ilos.Instance) (ilos return nil, err } switch { - case instance.Of(class.String, sequence): + case ilos.InstanceOf(class.String, sequence): seq := sequence.(instance.String) idx := int(z.(instance.Integer)) if idx > 0 && len(seq) <= idx { return nil, instance.NewIndexOutOfRange() } return instance.NewCharacter(seq[idx]), nil - case instance.Of(class.GeneralVector, sequence): + case ilos.InstanceOf(class.GeneralVector, sequence): seq := sequence.(instance.GeneralVector) idx := int(z.(instance.Integer)) if idx > 0 && len(seq) <= idx { return nil, instance.NewIndexOutOfRange() } return seq[idx], nil - case instance.Of(class.List, sequence): + case ilos.InstanceOf(class.List, sequence): seq := sequence.(instance.List).Slice() idx := int(z.(instance.Integer)) if idx > 0 && len(seq) <= idx { @@ -85,7 +85,7 @@ func SetElt(local, global environment.Environment, obj, sequence, z ilos.Instanc return nil, err } switch { - case instance.Of(class.String, sequence): + case ilos.InstanceOf(class.String, sequence): seq := sequence.(instance.String) idx := int(z.(instance.Integer)) if idx > 0 && len(seq) <= idx { @@ -96,7 +96,7 @@ func SetElt(local, global environment.Environment, obj, sequence, z ilos.Instanc } seq[idx] = rune(obj.(instance.Character)) return obj, nil - case instance.Of(class.GeneralVector, sequence): + case ilos.InstanceOf(class.GeneralVector, sequence): seq := sequence.(instance.GeneralVector) idx := int(z.(instance.Integer)) if idx > 0 && len(seq) <= idx { @@ -104,13 +104,13 @@ func SetElt(local, global environment.Environment, obj, sequence, z ilos.Instanc } seq[idx] = obj return obj, nil - case instance.Of(class.List, sequence): + case ilos.InstanceOf(class.List, sequence): seq := sequence.(instance.List).Slice() idx := int(z.(instance.Integer)) if idx > 0 && len(seq) <= idx { return nil, instance.NewIndexOutOfRange() } - for idx != 0 && instance.Of(class.Cons, sequence) { + for idx != 0 && ilos.InstanceOf(class.Cons, sequence) { idx-- sequence = sequence.(*instance.Cons).Cdr } @@ -137,19 +137,19 @@ func Subseq(local, global environment.Environment, sequence, z1, z2 ilos.Instanc start := int(z1.(instance.Integer)) end := int(z2.(instance.Integer)) switch { - case instance.Of(class.String, sequence): + case ilos.InstanceOf(class.String, sequence): seq := sequence.(instance.String) if !(0 <= start && start < len(seq) && 0 <= end && end < len(seq) && start <= end) { return nil, instance.NewIndexOutOfRange() } return seq[start:end], nil - case instance.Of(class.GeneralVector, sequence): + case ilos.InstanceOf(class.GeneralVector, sequence): seq := sequence.(instance.GeneralVector) if !(0 <= start && start < len(seq) && 0 <= end && end < len(seq) && start <= end) { return nil, instance.NewIndexOutOfRange() } return seq[start:end], nil - case instance.Of(class.List, sequence): + case ilos.InstanceOf(class.List, sequence): seq := sequence.(instance.List).Slice() if !(0 < start && start < len(seq) && 0 < end && end < len(seq) && start <= end) { return nil, instance.NewIndexOutOfRange() @@ -187,11 +187,11 @@ func mapInto(local, global environment.Environment, destination, function ilos.I max := 0.0 for _, seq := range sequences { switch { - case instance.Of(class.String, seq): + case ilos.InstanceOf(class.String, seq): max = math.Max(max, float64(len(seq.(instance.String)))) - case instance.Of(class.GeneralVector, seq): + case ilos.InstanceOf(class.GeneralVector, seq): max = math.Max(max, float64(len(seq.(instance.GeneralVector)))) - case instance.Of(class.List, seq): + case ilos.InstanceOf(class.List, seq): max = math.Max(max, float64(len(seq.(instance.List).Slice()))) } } diff --git a/runtime/string_class.go b/runtime/string_class.go index 50e83d2..e442f19 100644 --- a/runtime/string_class.go +++ b/runtime/string_class.go @@ -16,7 +16,7 @@ import ( // Stringp returns t if obj is a string (instance of class string); // otherwise, returns nil. obj may be any ISLISP object. func Stringp(local, global environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { - if instance.Of(class.String, obj) { + if ilos.InstanceOf(class.String, obj) { return T, nil } return Nil, nil @@ -27,7 +27,7 @@ func Stringp(local, global environment.Environment, obj ilos.Instance) (ilos.Ins // An error shall be signaled if the requested string cannot be allocated (error-id. cannot-create-string). // An error shall be signaled if i is not a non-negative integer or if initial-character is not a character (error-id. domain-error). func CreateString(local, global environment.Environment, i ilos.Instance, initialElement ...ilos.Instance) (ilos.Instance, ilos.Instance) { - if !instance.Of(class.Integer, i) || int(i.(instance.Integer)) < 0 { + if !ilos.InstanceOf(class.Integer, i) || int(i.(instance.Integer)) < 0 { return nil, instance.NewDomainError(i, class.Integer) } if len(initialElement) > 1 { diff --git a/runtime/symbol_class.go b/runtime/symbol_class.go index 4d39870..27626df 100644 --- a/runtime/symbol_class.go +++ b/runtime/symbol_class.go @@ -18,7 +18,7 @@ import ( // Symbolp returns t if obj is a symbol (instance of class symbol); // otherwise, returns nil. The obj may be any ISLISP object. func Symbolp(local, global environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { - if instance.Of(class.Symbol, obj) { + if ilos.InstanceOf(class.Symbol, obj) { return T, nil } return Nil, nil diff --git a/runtime/util.go b/runtime/util.go index 12b09c4..79912e7 100644 --- a/runtime/util.go +++ b/runtime/util.go @@ -20,7 +20,7 @@ import ( ) func isProperList(i ilos.Instance) bool { - if instance.Of(class.Cons, i) { + if ilos.InstanceOf(class.Cons, i) { return isProperList(i.(*instance.Cons).Cdr) // Checked at the top of this statements } if i == Nil { @@ -31,9 +31,9 @@ func isProperList(i ilos.Instance) bool { func convFloat64(x ilos.Instance) (float64, bool, ilos.Instance) { switch { - case instance.Of(class.Integer, x): + case ilos.InstanceOf(class.Integer, x): return float64(x.(instance.Integer)), false, nil - case instance.Of(class.Float, x): + case ilos.InstanceOf(class.Float, x): return float64(x.(instance.Float)), true, nil default: return 0.0, false, instance.NewDomainError(x, class.Number) @@ -79,7 +79,7 @@ func defglobal(name string, value ilos.Instance) { } func ensure(c ilos.Class, i ...ilos.Instance) ilos.Instance { for _, o := range i { - if !instance.Of(c, o) { + if !ilos.InstanceOf(c, o) { return instance.NewDomainError(o, c) } } diff --git a/runtime/vectors.go b/runtime/vectors.go index 4db62ab..9ee0a5c 100644 --- a/runtime/vectors.go +++ b/runtime/vectors.go @@ -14,7 +14,7 @@ import ( // BasicVectorP returns t if obj is a basic-vector (instance of class basic-vector); // otherwise, returns nil. obj may be any ISLISP object. func BasicVectorP(local, global environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { - if instance.Of(class.BasicVector, obj) { + if ilos.InstanceOf(class.BasicVector, obj) { return T, nil } return Nil, nil @@ -23,7 +23,7 @@ func BasicVectorP(local, global environment.Environment, obj ilos.Instance) (ilo // GeneralVectorP returns t if obj is a general-vector (instance of class general-vector); // otherwise, returns nil. obj may be any ISLISP object. func GeneralVectorP(local, global environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { - if instance.Of(class.GeneralVector, obj) { + if ilos.InstanceOf(class.GeneralVector, obj) { return T, nil } return Nil, nil @@ -36,7 +36,7 @@ func GeneralVectorP(local, global environment.Environment, obj ilos.Instance) (i // An error shall be signaled if i is not a non-negative integer (error-id. domain-error). // initial-element may be any ISLISP object. func CreateVector(local, global environment.Environment, i ilos.Instance, initialElement ...ilos.Instance) (ilos.Instance, ilos.Instance) { - if !instance.Of(class.Integer, i) || int(i.(instance.Integer)) < 0 { + if !ilos.InstanceOf(class.Integer, i) || int(i.(instance.Integer)) < 0 { return nil, instance.NewDomainError(i, class.Integer) } if len(initialElement) > 1 { From 2ffe94cfcb8271bb2c710a616a4ad1ccf08024df Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Sun, 20 Aug 2017 23:42:15 +0900 Subject: [PATCH 197/228] Add files via upload --- logo.png | Bin 0 -> 24232 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 logo.png diff --git a/logo.png b/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..abea7a8a9ad66ff2337f4eefc70da6485f1fb8da GIT binary patch literal 24232 zcmcG01y@^Lv~94W#i2;C;Oh>EQVVK*kr8Hf8hIEvy3|o(7(WAcf8+;3B)X>&=G@0E=Y8BsT^&snqN-c ze|UNMS$S}fWo&M?yP)c;*S=hNl66vga3b&hsJ!}s{}FPw))|0^frBcY%lY3c(i)8D zB_a2-HAC1gN;eErLHCsJXZ_2-XGm$t1s!jJ4}~Bj{U3egFG{9gSXfq;g}Se0xPMgq=CA>p|0ggsgKX!KZRZ~+_Rdu>62=(yb040+ZgA@f0_zuL{dhdF+xv%R8EnJKR z`e*ZYn4OF3>gjUq^*q}5JrNNDBO_%XBwrB}3IVsawsLcG&+2&|C%0Wu>)r|`OuPY~ zEH~e_-mW}u#mg@&ECkS*dSeppEe15!5PE1_(zFofD9b+}o>%+sW zE-W-%ZgL^>zQQ^ibe=v=pjU2tKDO8QI`2UkE)JmrM%A|Ncd(wfi;R^F6K;^#Ix075 zdvQ>4w$C@-adY%=;SdxR1&szx_L#%G3d~6xbPx1tH_4UiXug{!j!*ul3i(<*C8`5ej zDoh%`){4^Y4o*+Ulv(;{S3GtzMV{6%Du09>Bvp7_jZ54vIm!Ff>{7V6Z)GuPX^B;} zE!d`oB8A~g$0|uSQ9VK}H+p|$KHg&BHI?^7^^y6ul$Ms3m!o~&bmrI8*0v_-g~Jex z$(D(dKtn?-*KUxbQm$GAhQn~R%^NzJ6;ihr>nUwviEO*FWSWM{PbV%-|7unUY2&!g(Ed>QRWQH(7&3)UeR zWOCIU+f-oThrRs!!J?3awb;kKxmwz*K}Oy2pXAnN-zf_NmDpsB(*AI1#--2zkD`Dj zS)6%SAG8{MMU({Wacs6l5u%>A#DYHZq0u5Qd<19=O3ou&d43s8^z@3j+wtVAEDnR zu^CV4&<%FiwPRl4?>{Jn7fJEh>@79(Qbm5lK-1OLb#y8C^2yZH)YjIPe`KAnr@vp) z&8?w@dbvr+=gIv9m~UP8ExT^&gwqA?MoVRNE-NMJfRAGIN>+{$>F2C$%9-Qdg4?=! z@2vzV9VQEkEI9?*16?$@q-U#6Eo@1Ql8wLQGM1d}9Ue})c&j9m^9-zA-ZwQhU8Js` z!;V{-UsS2d`C^JEe0R;qWK%Rs4R{Wk_5-D~S z7P3}1`WxlIRFH*7tFM1q%`4F{IJqR7yzAjQGg(g>xRa>_0}7j?{A9e3e@;(^$eL4 z*Gw)i*u`yPxQvjBr}_9f59SLxI{M7)>@HvQCN?!SwNJbLN}SrVlC-t8wNtVX#{Py0 zmD~94fVdNGRz$NKhTX!HVH%C{03jA!P9D%}5P2aD7#4{-v*dW~NK+ibg_c*EQ))l} zIdG`gCB4TFmxM{7v%jd+GC4&bgX5NcnD{~qd1V+o8<0Fl#b*lTW>cPB68P|;1&Q-t z&o%Y+?M1HWRf;mW(2Uo+g6@YZL&m>4#x}F1BG7UqnfUAhZD6mGIPsB#^wCp56v;6a z8W{_Y6}zKzyXLX5yoALSnfeICDS~s^{PFv~!s%p4yANt736JI0Co37;czzj*VZ5Xz z?qSucvv7A$>8Uf4)O9*NJ)Pw`uA7t_`Xt;(!X>NSuJBwfxN`K@fRwkD1Z*0ehzu%3l3O9@2IQClmn8fN&j@uCHxUG~{b{u*!0P!2 z6`b{&Ar|8%k0zHd^sN_zjIBBM;z98n^vOroh{!11MgQdmmPz=}^*Tp1M!JefppsH0 z{xL9Fq%;*HsSZzb#OfDmT(d+cH+P;UyaG;grzjJtB*M-kK~IzJ;F~1;+_AYI_+TvR zv^kn5(`4NuI%#`*)`Cx;fOXtdsqePz;xVw<2(h(2o^5}*UN>a?rhAYL+0FKS0Y)P> zTjrZ2)`7h5!=%_QMTjT_)CE;a8CHwKy3G>$l+NRlO2d&!B8s$OLjual{iu$spjz0v zj21!sL6jEDsZ$xR3w&V=7sCyLfK`xAI>cS@JqfWektHiry-0$R(H{-1t$!Bv z{w$wzXFqNS%}7mz@d}PAC@FFHzC6jM^I(Z-P@OB9Zrt45Bqb$Dka;Iu_kEKLRF)UI zzB}I>85scw+FvvkCXA+WA7;PaXX|EGlcGe0$(%$oiX#?5_VSG5k5)*&Z6~s<{IG;F zpw!?O%+LMAfd!dZgx*{!BP}xP&Lvz5)MT@4CCbG+?9rr3U4hhYhNVNk(4V%*?}oE8 zuT4-EQ%T@{uSbTmSts?jfk10>?346RatZ~#O6ux)Q#uqy+)#)@%0X!VTUW5=RY$|z z@moYg3X7YQx2o#IojEM6j{Y0SGR`AsPuoye=j`IrQ|La)_2tW#_M7^uWyc}rl|BUr zBiPYDfdmqMVeE^V<$ZFKb-~_w+!|q_=u$;Z@Q578BJ3yrAzt}oreih!4*RaZTEVF zhX>mM_$AdmYyP(_@!|ZZKNeh8X+@T4=2;#)*R%TV?&lj~=1w|!?d`soJ0te(&o?j6 zkHGaQH^z{_r@g(h(r$mEFj?>0{?+~@ZP7X#1>1N($*~lt&YR{IRM%6|xfbXmm*T@; z+y$h^FMn8MDc|X;3_fXKIy~OQ;?U;h9X$Eis&Lb=bQ!*X&qb&iK~WwEB5r3G;7~K0 z3xDtay}}~Raleqe)+~`@L}JHT?ECl!?bJC+Eg+qvlM2qw&hoOct=&Gt`E?AZatgiv zsD{G=ng{$A92;6%Dx6)_(y~-Gx6u~}z9mp5(eW2}Z1!}sm@JYr9J6I7@dh((S%#_z1lJuY!pV+eF!Sri1M2W1<5~C0926gY4uI9EgoM z3)5^(yKi>tmoz0F-hoC63CLNOo>kp_tODtsOwfDQ4{(k0=vcx$OoKR}%jg1P9%lgH zZk=mZDr#AH&dX=)ECB^c7~9AGOizDQ?%;mP?}4|smAY_1YWSR=5RHdDZ1<`oc^L^$ zFYZxl4f*TRbE^LABRh*nipq4^!!{L;@>bMK4-w6o)H5P%9W-|lL z4@JoRog}T}I6Q-bTCt-MaN&nY}p9Fnd zqs-PrZTRfaj12)U-Vh$UqXhrjh(;Dy+|PD%;h5~dpQHL=pTJ+u%tsj#6Qx~$xIx&^ zs4>}6I!CGBN%*)IaCVN8|8^?u$-BEg6u3Ph!LBf|z zugmbKQa7NgWrF&ftSkKapEZ9Nn#D5Jwf8b3Cn__zU zC)W0*0a%x67HK)(a5g{9TgyljitKO(6oO!(n#@>B(?ZyoIH4@R7g97UxesqB3M3_( z@+KnMl*?EtuycXHb$lgkt_WXu+q#JQSLUPll0i9Xu-B(HIRwBb3*7xv1ivfB0Uy{Ili$!x4-45Fqp|<_0rlR*d_lXMK5#6Mai`+cT(BDuERnt4K zn;c(ZPHvE>sw%qm*sikwM-t|DBq58d%6UIYIcua$z?GI<8mp?75f3LZ{ywmrp_MR?X z0N4=sY_^Ye{F&8)oHwmfdjNw2BH-O(ks7u${cM5S>>30_Jew?NQOtZe3QQ!RZW(ha z9Q)RzHvm-7q&4euNLy{vN1vslN*@pay{6_uE38pEK8eEi2NiIA^}5j{CVFSDHidK+ zdJJ#yDp5B4vlmHg$C6@9DJz@)6p{yJX*2xUNzPvH?UXDc zV%#YJ$<1Rzfe{T2{DN-NoKmmN1TSdpDi&&~^(2P`0pE3@X6oOg45zEhmGtZ<E(!W+mt{6IRaGp-Sr=7R z%2-J%Y~~5+ruCjMItaW@$ahfeSN{9m2-A> zu4`zB_}PFJjyq`S9?7%+@en2P^@_F}uL|9m3&0SWRrP*d8gWt4N`i~%K zsg?K}Gh)q}6o7S_nx5`ymg>0X9q$Fukh+>0KHJ#hZ`;SKN%;o5<%jb=GBUoeIeB?` zb#)1;>%oQz2?={mm6mChhh4WbhQVielU(`ZduL~7{r#ba1mSt)8-M>QkYj4pS&Rd~ z&}=NL_3L^U8UYHHwwBiSF=p}?8hHTI&P+{3wuWIc7;{UddC_>wm~{`*Kd9oAM%^(PIJX;1G`0$adOv!wqAZTaB}}xnwVnFDKK`R?gfHi3XB$k1k{VWh9)Iwz%mD#I zj%h$eiUiNVz(7D>OUap&J7>c89z95`sq(N%SWr+$Rkhx6dk~eSajm>|RGPhe+yWqC zs!S5`lP7zOJJZO-B)N#5AAnM&!rt4O2``Za)4|={{q^OUwf*U$3}BiT7Ep{UTdAbP z`hn3%PfJT;)o(NE2^Xt3vCN$_C7jntDsaWsEy?!gIh*)G(zS{;Ze(kwGc=4IN4{CN zQ9(LY%AjqY-1$KzNcjhvSWc4`zXSLYLH&CDp=V4+zb?!2@W~OPKK*lF;Xe9E*z;FI z@Caj9@mHh3(LlnXCW*Sc%<10jmnnz)ZIhEFrIl!Dja>$c{?)_0n+(IA{3UUfUl?GH zi7;>VXcB?mt3w^*uV2qH-Bt_(eE^a=JRBu^OkG!Zd1{KPC(2du%e*vEFvXOK?Bts_ zZ&ti6W!qP?KS1F`-Q0N7dATd4h|>Xrl!%m6?)k|WzOb&n{S}}CJswiGRgO@n+%BppdugMwVeg2mZ^;ZHRuubAXa$x(l~XalT_gR5gcpVToh7* zmKC4&`jxGd(A-Xoi&l&z8K|_hu5lP0B$JQXyoCV^`dOmbV_6#{RlAZsT{ok?f}o>~ z$kO@CBRNm;@mqy9i=jStAo+sOPmXlBY-pHdi$u0(<@3dm_3j8G;x9g3MGb@nTwo|U zYmkw{R;5xSbwma}G&MKt`#xU-K;LXAiMg<_5TGYiRaJ+QS>Gvpe}r|EQRk8r+P}Pq z^%HG^H%TiJq<3YQ&-Xx93=9QWVPLg*oOL2L*so@NyTPX3<}A)CNbq?AR;=&SdHd^Q zdpj^L00BEDHt+a7kH)Qd{v^~PG&I}i!`(*2aRL}@*ok}ZPIjYRrV7gOUmf4y8YRHA zF^eAi%h4H@TH=8|&L-)>e|2jfvdm4%W!}?7fB6zAXiuKt5{pP)8XmdoDL>^#nkIn+ z(zxL%RFUZn@8__`Q{AxRsZ11pw0Yc4-lQ*9QLy4RXz`s+tFN~ZGDo7QDe8<7L|*C` zW0A|?tM<6u`B&xCjtMi;)0b3M3SSO$>gr>Zn6UPkG-XT!m4*3eMx8X3bH!Axc^b_Y z0VO4+=grZ-Zu8o&yl>_eN!*tPatSVT?Wgg00qHl*O#L0j+2}2I;KPrm68<)_L%rOO z-R?^RM@ik!Gc7)!r|Ih>6rDLmhtja|%l@UXe4bf_{N*s9(z3)>&ps6mF^lfFU7{pG#w_p*URumD43Z)j zUKCGuPbdNN$2a`75&ORtFT5JkK;jf)E@7YdYsW}m57di?v-Me~2vqTo3-b$l;5w%) zH4UZFO^RM#UH~p_dTPpq9JRoX$}Fk;=g*%N6|xOed9;*0N7c~Ii6)2^-`BN{g?j7k zZwDn^YGyVQl(&%-XtsSVZvXO5u}CJ+gH`2(H#zVh)z zu^MjIuoA9tu{=fhhy6|c=YuU}`3eIow0KwdF)MayPI{{oM-GW3PyCAO@&?3U!{KZZ zk%|rSTUKdCPkyi)1W1>=zy#br999)S<|c)_F&K!W-cO>-rc-iE9(L7EGUR!z9m~qW zO@R~0^ByyqMiBjj8s9^BSY-*OD5z1A%BvkRs5T`?S)h1EnP1e^t#~h#7WT=+U@$8v z`?W%GhOsvdRuZo8J5rykCyu`5s@w0eVih&3)>cKDb_IsdZ0y#{6RWB9Q8$=6i&epe zGB{ZtMbFmy0YEpt4xHGCD~3m`hTWmX0&503zGT|WXU}6Cj*E{TGD+>$FX=Rf0Hxgc zm){QcUmpT6ge7nFc8j^09UWQK%#m1-a;S!m=Eh%-YLCI#Re!DM5ZKGOH7?ze)CsrL z+FO%L*n@LxFk$mq(#-BJQIhpbw5Rg`(zFhDjD}TN-s5su)s49DITSty#33Ty*A-Pa zliBA?su4N!BufNZucC6IGfFfYU^N)q@pJr(06oZ4^m^F8+1ZKt>1A2C*YQDR{#&@c zV`ZzUqZJS{M|*pGfEJ<5@-gGGz`aMu`6mxAugF;k+&@tOSHg6VF?4QjPNM_Hp(KZ3 zAaktC&?OHR1U{N$2ZE;_^_>kU=nM5mkZBdmx&scgmI*OJCKhbx8lBKjmY=1zd^l3v zvCSIR*7bFPvUw?&quK(eE%l;wH+yI;@QG4$wkUJus{cNc?eSH+l>1WPYuSLY)9f42w%WbpcLV(UMgZxPHEC^*b~tZ69%X>+)uQ$Sha2)A^UYC;og2B zK{in%U8u6&F8$axV#}%KE;e$>qmx<7Tz^<>C+-Ft6l-3l8v6NsfHs#?x$bi2CjDop-wMkIrZKe+`bzk^OV4}k@ecmVSkC4e$`4UQPoU>3j7 zh?4kJivDx{RTyp5@e)7XYLHR>-Nw0-e8Z0cJ8T@Mq#{dzGnZ^7uZ%BF%s#R@0ffhK zfcM06>9rYbY+}>KJr|Sl!gdz=)7T0hJ)5%Agiaz? z>SF{6&QIT>N1~Y{D&q>N`)>1(#r$swBkb?nAwFA>@K4Kk~i{>d_Mg(Pr_zB>VEa zbox84*%gUzUy=$ODU&O56t8f^&`3}X+VZ_8ecwG-5c9uYfcF4w3ICkW^oDAaPh3$& zl{(NOt@ni}c>VGo5O1-ev1o7KGV3(51z-=Dxre)?i~qMn0F#ybDa52!XnD{C?d10H z9jl%ouqOf==SY@Nb4|^}>FwjQ56A$I7(E0a-8{d213-m2;I*^cLl&oekiDd=pmIB+S1XM0V&PAT_^W0ZP}cQtk{n zmnA7Z$bsWWhapC1*sIACyT0!~``TrFM|&*rjQU!bjAkHq>*Bv8EuS^HzEZNjUenm@ zoCyzWrJqetL@|y`Awg-7yh%pZ1&@ztz!e@X;&YT{UBs-RK%?#x`xgk)Fr$7d>78Oz z>DdiZQqq(CedHjqBFkVg3W$x3jm|FvztvNWHvs@3@)P~8^nvZ)g^3ab?5x2dA&ZNP zK-uQA*5S9ZvQksSfp11mfCdP)q1Ge;tq~ z?*R%hwta8uIB=CY#!n>C_zdgrD7+)oz>K8F9j5MR9~0DF_Qdd#;b}Qw22z+}U0frqdpd zQCYr;PJ_Rr(B#;`N|oT)9-IoW3rJwkdS!e6BARj!$Mmtega@e-TzR@AQ^lPe)E`HEx^0xCOn49O+F_n zt?1KZ0Ak%8&CJ(h=OGM(RJJ`FOqZ!626UEhK{`%v^^AL^BO*J0zn_XSn@&xp8nA+G;A0Xazx8eNA$CsX!5)WEf zwZ9;R&7-6HOywZH;`l_XL`BF>82>f#{`6J&;n-eY;Mv*toZz&2IVJz#S5H0^5!Ub2 zYgYgoicE_3h7c#U$YZNN7H#yq61l0QG6A80@Y7j0P=PylFDXl(wp@+^GtW>wm_D}q zc%a_?FkR*20ytRWY2`&V#oSL%OXaMmYmYWkN3n8je;`WWOuY9JSXIIHpA>2z# zlHPI2R8gU8@lk*mc?X9?N8LiRT+h6q1qp?mjY~wI%#Du?sk$R+(%_NcH|}InI?B%) zeja$1p(`ydB4(8#PpY}hhq}4BovySBEVJgu#>R46&v;#?uMTV5zwQ@j3-_K@JmrM; zXDU7I<-hciiH!QsJ4)CHSZNIVhjuBBk+uXN1=8W+5utwNb9F>4#${>L^O6D0ZK_*a ztDb9%6Q{PFUEkHoB{mMTTzY~rZgbnTI5)nqzcy9gJrlh%#MO&W`TjT7Gxv>;vN|88=LC?OakRL7x`e*QW?XJ8eb;p$(C|r_}A+%CkBFX_Pk2?B;!EP$% z3~g9k%n#+FpBoM1zp5Vh1l6T%?IALAHy|3E--yj-1*-76A>k;A>Lu>H8bc6q>RO>1 zuRn`lhKxCg3aw{J4R1U;87%v1>2q;;GSY32ESq5j3&Tdn~M3szCtGgdeLBZlM%v*6Q0mDF(U z<|=AgqNHf3-+I}xpC85jLxhz3JY~AGvdQ^Nu4O@n%L66{LJgRFdv)Avs7aJ ziQr6gZ$}zqFhQm5ddlang{_smeLYp;n`3QdhCt6ci$nodBFMvRLjt>~HBMKn8R!02jLd$^i6k|I-(cpS) zI9UMdztaCKaKs8e6J-&jc|*~6+4HSsa7a~_(lTtkgeh$&X~9q2p-xOptJC~WpB%ol z3{Ug?zwzoqkdA{-HEe1*{GQupHH=#-4ScNx3t{#a6U?zm!aNXhrn|uk7UK$UfA!Xe zxla9;nW=`T*ey4Aiu<`Y{4Gw#Eu7um35={*rA)zjW4pwgF0^bYQYYHKub$U2WXu}^ z1bW{P8)O}2sD;iA5u#v8X{M&Rr0Z&&gc=1}<=rvRUB00}&rZF8D~4gH4(7*tBS3?S zyw7ovzdmvH^*xxwZeY`v_9v_=a$&T$d8lWSZm{=(ZrXe+5u8_U!vv&AgCqsU`M~T)q?+ zS*qsL+HN7~$F9`1l=+HYYkpmOoOy0s;&3=vPRqGzf^d$GIvOW2a{pRF8yL!WQLP@C zP8IlGz||&lHnW2c4eEPmxJnuQ9&32C4-6f4!aeF%KRQufnGGo{Ov~E}oI!xXeUF%d zmNiGvA8jSj6V2gDeL!cHlshcBEf0RM!rtY1`;#Fd;TKvhCVB#ID!I-wf`(Fxv!DVS z*oZ6qcGZ{d^(o752OV0sG-+B`ZcZ6NCuu{NJx2S@RJmM6T=C{)`7j*q=wlA(-@tfd zh%A|<@wkwKFSU35dSad4Zr?OtgQ_>h=IGab?Zu^u;ia;XRv>C zJ>QZI*1oVPGkjo{e)P#Xe6w9Z>!dOw#N*k+G^8P~l$Q25*J`REW9;A}nahDp5rR&# z(Cl_fz$&B|Yw!5F7O)aRW*49C;nRRLD>V1XzLm|$E2eH%spE^Zin`#6j_4!=A_)px zHI9FBsjuPks3B=6-rdvT+}NB@ehT_Cx!nVv^QB4{u_WgHapzTfbR3WbZ_jI4ek3z# z5KC!nn0EHKN;XQ{-iOXhl8Ea_;zKUZ1Nj3^Hk~li=#OK91I5$GO3%6%CkS8t{bbyJ z6$sHAcn-k$M&_fjchrSeXX8}Vdxobzk#(7d3`ZJ`T?|P2{O@g5L z5jA!vB56Nad-35eI=@qpATp4(IJCD`=H^l=!6pQ~mt!LBp0_8}`raE9zFRMyh~5}N zTV}3xT!a$#rFF0d{E2WHZxBG3+473hCa!k)?{s$+joqho?54GRQ%6{C%WD!16pS;I zBFTb|NZV(*K6^yZ)=Fa_k?lUo4#_x;)o+vXic}AP8RF3o(Wmgf6zHqkV72BPC|3&m}X$t z14n~=esL3?jGGLZB5b+6`)uk59$zvP?C03$uu<#60Ia5>iL`wHU#fO>GxFYi3ogZn{&GE5eHKCqpr5k23+wd zY_<0<&5v)=JY$DAU`u9g)tKDcSABO<&CS?^ctL<^#&WW#{h_S=+vNyvEnn_o<7c}8 z$FZ!x00f%<8(4rU?JG45809D1oJ{IyG`Ze(@Pkxg7fl3iK=vRFrP;(ZBF~>zeSXTO z#9k`M!meSF2`Gq{?t8jr z3lW4hHZNm;Y8+uZ$?=D9$*wDV?+`bggfcSr5d3=iusIC6Ei=S;FPEAZuKdYyFBxM?zU#s;{bF~q_19><%oo7LYL=_%bvN~@vL zajjt5TeP$?8^R%3Sy=!-M?sD>cO)ug_)F*p0fXu%3?b(c?%Agsph@4ZEYuviz4&n6KaQ0w85S%iAcDT96=B9Xeg0DSs|+=npm&WO9QpQTxEeQ=M>c+J#=)X( z$X%YPYB8JM|Dn74p4_eOPWNOr=~R(uRi0KZP~W4FQvyT7u_?^dPp4U|D20sfo95@N zt^`As;E@^ldBFV!2o6B&*;^sUrS3%PA->5eTx(&)xKps zld$#-!?(A>3MQ2V%gA56kKHOznDW`QBOIkLPfW=SJ&QqmBgXx6RHK;eN_*u}B<8Z_hjZmVeqHSh*># zwDe@L;q+bmT~9;%^KrUe)BZnZ?F}MgZQ_7~pH3`LlEB6Gr)YfZ$pQ*6s2@$L>|8u&-(m4 zJ~N|GX|K#sNI=yJuTv1sm2mgZ*wZ}Tm^=fb2Jlh+f z_o|+OY4d)4z6IQ3CWiv~{jp^s<%QG$%9>B;BLa3$}K7P6?2(Lta- z1yw7COk1Z6xa5tW@8e!h$ZyXirB;~S4BHvQ{pFxc%cf&lIs-LX^U0_`fyMN*zZm& zfzrI|QPwJ-EDr12H*m?4-93RvrU$0kwch|dc!l+maqeT(CsCw}cF_`9vX zhS0w*B#82AS9HE^TVyBjY}&c;dk5uRQ1EzDv|93WkAvN zxA)p42FNN-G|J|C);C+>OWo@U3m1)Bqs=T%an*I0I4LrAj-l~MFiezDge~7K=y}3n z<7okpx;FgmI8SsMgW^`QA9+st%w{h67JAYM%h2HdvzG}~$g*Zh`wc%w60M$1Dq2%$ ztu?e(uw1jYC_mqLv-ih-ZxbQ+fbj3M^mGw`68INQ!iVLx0LxM8G$!PBu{AKyEN&Rf z=!gMd7db$JB^z%69n>OPqoC+C{lys|S|`e0(0PQwP;hNIdG(uTsF{(&$eGOgXWDQ5 z_d+NYlrTmlILL>Zz7d}hE(~lh*0ifR6FF7XcEX30RFE|Q%|SqNP$rz=<$g7vmZhti`o;V=^f%|d&ERX%lzl9LN+IE+|`m_UdBE02V77IGD zba>D^ag7+tMMTnC%QE{V&tuwjH&i3U&8Yi>!Gp7|PqF~|h!cPJpC9Gi6e~%%=aS8GWDvL9#$Vkb#>aKTN|mf%7W5T5)u;M zr%ke|mWx5_s@5BTy(1!^>%fhh7ei;h^|&15q{JoVeNWe8fs4|AdLhtH1}gvrJgZBk z5!z|MU6^1R{nWendubU-Ap#Njgg^G6bY^+f?~5$3ngagpTPRBp3~8FHCM9mi459Sw z!>0Bm4Y*YH`a3@_U4H+<0^J&*&3@W=*KR@3OF%E|fsKVs(cRr$1&~9lPa~^3P9xl` zEoWVPE-_>4pIo;Sl|Or5np$UGB84)8{&2AqjkG`8`SC9dMID3kArIR%*iAl4>c#ni zHvyL$I?345F!baIM78ADRy*!WACV*H3nfp~pnveQWZsCK4KfyQoe+M4%t|v19D&2K zJ@ZUro5jrj>TKuo0fZhfIj5|?_d|ew1uLr7vKCK;Op!3*2AoR)q^$Onro$CL)^gY- z$^PW1|10MyLcd%#RvIG61nRu*r%~gUU3<#n)vzf$guoMjeJg}lPGVgA1yO3u+qS}t z;CJVu&sV(#ziv8qS?$GveQflI4ns^Fdr>NfsY|azZ5QR@2glpUforr9cAFWjAwc}- zp{X}I!USa)(t&{Ow~$q^cLebVhScvzYVQ2*Az+) zBqH|jj7Q>jaVcd|&gSC_f$GqV{ql-TE!oN17zu~SoU2?`8sD-9M*93NDq4HX%eB=h z_~Q{<%!gi&r#pUEf~qf;36B2EAPQVl2&+5G+O(I~N9uV5-OYMDackGs)g=joaHOA5 z_G|&DN8aZm9w6s%+bLy*?ZPVKr_0P)^p4~^1l5*YL5%1b_0ty>pVi8a2u4qhKN2zf z0Z`hH)pa&?vXI2YiIkappkj<5n8PxT#UyEE^Ex(m0{-ILlSRkW6m}TTK(Y!7F?zmb zIAtn*xMKuk1y#d5<7M{|Y}m@cR%AA_Ne=W~El_H3t0S~52xwsJk;@Qk+<*K?RPZMJHAI#pLvF#klq#!`k1M&$mubmEHyTVh~ zQPkEZ4uj}mdxVduUfg`gybyW46tSKur#JJa@ofk^f2=W0yf~9xbFD-hJyi>jpny29 zDu%Cr6@K8_fQo%kc~|E`Fg|-=f#JTIKW#OVvQA*cU~M=I|zhD8<`*`GOm!iuLy zx23Ja$fH({wBl~8XX{FbK0=~IgOK$8T@6~~B8!o#s(QJ`dGqS?$-H@X>+{Xx?r^Fx zLGW3bVgE2kjD2Mu-9I|r-sdu1P|!G)qN*WqpOgJY;Om#arVOyBjg&fySmoVUsTx11 zht{f1O?GP4;fL}Ah)i#iPd~sKs3t1u*&Xg=hL|f&{@z}G@Eq2lAfI40n1x0F z&k`!k50B5cdShJ_g~v+q8IqaHu*p21(lbl&v3tT+C+)_@7-#CCucuzuvLGHX2RFz*DPxh4K zFo4Z}7rD&_m!SY6$iFOqi~ zE?w}kaGmh`5|yQ@cvj7tz+r|s?!Zh(daU-xL0_Yjy;reDVOTiHjUxhJsk7OtO(8XW z%x;8%F@Skx8GuO9z~R8v=jGLr6!vah#dr{T5tQiKQ#`{J@abU)o{8$A#FCjY617yCqU~Z^+@GsDlrUHPjq2BIN%<(#xsS=3ht(&5Q~0)8q2v zMY)X#@#C}T+yP0iN*+kCt1ri^z}c>5x-5#GQ@l~oRwp9a(fF`gPJzl7X4%^evnRu2R zZv9>)N@lr6omh{4`vI!`w^jBTwx2J0qaVqvr!?^$yBHn_s5x9w&7~ToH>aG+e_UTj z^|u~}m<_bCOI_VoYo8>D@!5o@+Pag}6yaipP5lkGp5KUscRYb2{GLac_(oeBg}k$S zazHO#Xs0VeD8cu9HF*l;YtIvCaY>2Pa9uJ?4~`fha+VlHFsZGD$jlC;an~j>mnF=@ zgBpuTVy%?Q!_Y<79N&I~pEU79tKCN%eO?NZ$jJ;L(9Q~#Q?Ewo@J6!^Hyi#M_t-h# z0ztOWRd}82&xFQskTx9PimNVSHi#0O+EAMNLa27Lh+BYtG;ialnBo(B1T!3tijzFN zSikr?-8$Ffg;VcS&&eWLC)xevCr|NST0o>;TFNMvDGu&h1roFM3>S;;LA1*-CXYY^ z9Ww70j7<~P`D&QuM!zIi#FiaFc*Gy*WK-s=M$czD{;;T$pI?WUu@0)sF4q_DlXD0Fs|f&W@GJ)YR0H1At(b zU1ou`%D@Hhr!w{XD_@IYcd*wsFEwrt^ZHG5Hs+QZ6#|H~7amIy+dq|yiC`x89ibsM^D=2LQCSPEboj{(k9gX55QtR#-~R<5&|VQX=tYxlQ;=9JhrlHVijR$^&38Gw zs{P38?TDK_X25HP2wl1`pbOkCm8RRAam8T`$0dR2_@Z8tDLy9Wa zU#eOLK)y-@RQx~Q2A}JR{~b@(G3Q{$9r|QOFbK@$+#Ssuvy^~BY&KL9YBwpvb{xBQ zZDOc!Ji?GJiikl-)Os4)dfV|I=&Z2bM9K1RuTKGATmz|Zp zy<6wvzP&wKs2}1+|NV;&-;ov`EnvxYvApmL99<7{thqBz=si4b&0Ulv9ku4UuX#Vr*m|DcgQ)3XptPZ^D>K;{%*ngM-i~YT`zfKAQ8DGuhxWu9@st-v5bcv zf##3EDXeBS*nNokM^E<=p|jUE7jcPs&K)9qp?0eH3v(QP8*sX-LI=tLS6@+ETiejU z`${MmxY0x%{1K@89R}j0L6|z-Z}^pz*XbrvB{cdx_OzBrVbe&&v?Y}hf8yY@KN8bKz>z(JRpPen0z&BDDU|_dS20n= z@X%HEPU~PPLY~)q2kMBW(UA@d<{gY!w68bw=JJ^zxE1*ZAX3tnz;RjOi)5nkJqjF^ z{wqSW_6Q#lSET+57oCmpq5)UsVtF6SKwTpiwtjE`F&x|LwGz zZSy0hrL+`Fd_vO%@1DnOh)X|2YPYr#w}<5xY$-*BCqOmr>t`v}O)d>}`g0)K=z=V6s(Y)@HRH%!8L^2so7 z#B+T)B`~SfS%&VyZ5UUq zOc_GSS$&6+u%ljerj{1&O2&pW@UvS5jRjz2K=vn3tlxnUlaQ=Qe2UO=SaF;VE%kRh z-bzzRKEpG@A(e)Nd3j77N5T8Gf3u0d+81iCJq%PdvaB|-ByE;Iq&7W@)2U}sU!G$U zWq0y8?|<`k09`0Kn5rkwI2UD_RT^m(E$rGVY14j}`U8cH;O0iBt$lIBVko|eLAx54 z+-t#(8iXTqdpcaLb3j92wyrWOvq;xkAO$Xniya6;o8Pm{b;82sg-@Rg%#+KrMq&qp z4u9S8go2%)bYEcRhZPn#ia%_;UQA~R4x*a&;%`5btPyZYb1eNB=-x)9|EI^YcWCbY zU(kQ<`;y4H=$W7ozqDI-^Kumu*VDA470QMvE0`pVoE7)@x$P5`k2(7Gz~95Tn&`lo z+XIoKj-auHA5%Z^`ZYjXxiUeG)x`>?E<11=yz}sl&2xS2D{ad3Cm9wQi^;serwMi4 zE~`%FJ-kyEK)Z(dM;5|JgrQ7&gU>n$fuwVwV0MOkp{&s~A6BP}o~3;~8Z7e^$5rDk zV?*ZPbE=K>_ENfZ*rN8Or3XZ&EINfA)L^(mY|$}~sZ0fPf9%B3f8~8U44E>O4Da@t z2Sp{AbwAhJ?FUOnZ=Kn(5Fe`uozT!%tUXHtuo1N>o%{~Sd2jPX<`a4ilYk6S_$y;Vs+A5EQCA= zf+YMm#6n56O~3Tr-<2GRXLnC6PGiS{gxkSj@W>>zYe((~&x?Ue<+CnPEy|GfSiGm2 zlpz`3jt8Oi)=1${(p)%24zsWaWi}=+MukY;aXo9rZ;x0pj%jyu^U3xR9+{LYGh_4; zp&2jV-!x@2ld87h5{XZqi*@a>WZKBd1VV7>6kyTribikdc851Cy+niV5K3p=MDw3K z5W$y&_GfIq=bLe<#nMDhWp;YQ`ZBe{6}Top#!m*aC9~&`tx^TS{a5+x@Q1`X5B}{> zzNCvdm+h(h_kmVBXKYDeep(saTZGK1ZhA?C;vO@ocn+7l001hQLW%^)_LU_c73K27 z#ku0{G(1AHqc0-7M&uAC{zTg4k^T4*SaTfK3R~zD*3Jso);^}kgt+BCGnPnSU*a8e zr2O+ovXWq`aC{t^8>OS(sPzX`*FrBvns1Yi;n2`{>sTRvNXVFAQ%QqrVr&Doyi- zUU7y))zn((9c_OJh4@PvS=VEF^mUc`nt7Qb`38F_oja1vl;)qQ@w+-XIy%03rFOar zY#bTVzHk5cA9tEu;i$(t3@17~M;kj9nKn$_d!|{Sn|jc^`)0QGcOEf@@z=EqmjWym z)ua%eWL2s{m`TuVl^2Cm3R9wgwab+8vo!Q^fx4S|!{kIfyp=ej5|cKFs1t|XpLpyn z6~K_JSSw#eLU{N9m7dO>HZZtadghBSAAZ=n>D4zx!&)Q7mHfbX#c!!S0_2QJGq^2S z04X8U;D6(n5S-enDs5N_b~i8hQ$If|2!K8CNa1BWA1W*{5Y6ziZbk~%ok1WQ&a3*h zM-tF5+VzFu^ErOXwEC9C-y2KPtlRaJ{+9-%*$)UILPBQ@D}IH;13Q@AOn7X7IQpF( zk@bDG6gbNwPwCi%U~e3&s|Cv#&Ggfh{*#@#nH|>S8iYt%%@up^a{;y>&%Nm_O%p(d zt;^h;-&SrQk>U!c?CljF?f3+C5EI5u-)d^wY!`T98UO629 zMS`4rdpl$0kFyODT|6zYZfMcj`H_SBV?z{ah!f?HyL}W0)8{?oG%sQbZPlig581@? zspAf%5%A~yx?nF&J$obNeFEMfG9YUpig9i`U(ddYyE%&k!D{z;xrgZm=Rinv-FUfo zE7w`sEy6rQHT)e>Ig0NY(`rB%z58XfODLyH$xnO?IxW{*1_aUh3sO1m~1Gtd{u z-(a8oDx+>dM{+5h(I=SuPd~&-jv=pyon%sB;#bAP(z~QhNq4$ItP2-g+35@8)8Fka z`2KnXP%kD(JPV6fZbST^coSUBcD-kKmOQ}~nz-<|T^KIcw{eHZbcf>-cr2vnpeKjkhTm*;;CMFOoy6t6v4cvVwE&}9(Zo7nlfm4W8wLoF2tolG$ zrvBCJcW@01Y7swd;1@}df#`)xEQSeq zfV?GUHN)3}{Q7?Ll7#U`#o(!FP9JGAm#B%3y;dsUvK{dkBVpUGA76_Lj-=&0yzuTg z6ttmZ_LpQw%=s0XO>7#^jX#$4?9(I)M^mX;{&ye^sn1~ZRu9VTF=|dVnT%k6hsA2R zq8^W+%+QW1i=kyBqB36VP5_Ayw#14j#BDS*G{BQ`IdpS1^zG#&2z@+zyO|G)f_ZRK zRr!uJ-@g3>n|uw)!*&470{Br>$ns|>m*1Vp6>vagu_#q!2Bw94AyB75zA93Vv}Ik# zv9WH^py^Sq+e_yB;3KYO4@!&7+JQmCELRD%*yQrm{)j5$yV5kbe)zmQHM-REL%qqv zK*IzFFPQ34rvgA9Z!w0X6L(djv9A)y;9xit82-{{moS2bdwcVi{*a zM|jq$X>NR+iX?1yX6EeoiRz3U3X}@;olmbFEEwYJH7!UVCWUJAY#tSr7z|x?@R2yo zPH+~`;CVa0KTet6QMXbko&8D^lk3oQbb#}F$wmFp#hoxmVMDxCl^R*lmuy3uCeZdv zh&*B{PW>_m-`_3l6E`FtJ06;gaC#rvCQZV?%%iGz|C3i5<$q9KQ>LryQ`%}lCISKH z((X&GWmui}YN=c!RQ&v$?8)aCeVPF^&QX3UQF@UFHYYTAIv~d1%_WZwS9rg2GgGS^D zT{j{!6R_K>nMQjMhmi0*GdO7K9WdXxyqNti9Z?!lp<#6wmD)e@qgDe7DX=?|cyAS; z!c!%M=;7T!jz5@YG-vm&Ny!t7D{hUZ1xqs1+KO!(rPo-npS^~l>wdgUuthB|FigyL zq%odHanXq=zU(q)`2otF7}1H>9~jR}A0IA%VHOUuY&p{Ts-*IoVEgVs>v9!1U62rk zo=bb-Ls@^6Fst|j7^qN&)hZdJ;!NtJcL3N*#{r8*n`1k8$VL=^?y@Y zk(o!xIW*B_2=^_L_MmB}%|hj6^pDM+Q=?GNsgu8l?f=2C#0skjc-faia9ayaK3t&r zY!Pizvkb-iJl3z2W2+TEg-lSg1n#BQJA&1{C>}UeD=#Y{NZI`@0aYD6-;3Zxnd9hf*-Lc%PK&F{tgg%mvbB_JUJ#lkhu zU<>iCALZv9@mHB&)Nk;pp~L6K&o(v|a8dOFM2HQW)!zT_^Xk_&C9(BFj1i<}EX zj2auZI_Yhy1PZIh5ZAG6k2%hb4dBXZ36znvw6=Q|{^r0+VVk~JXA8J4f$s#goLu?G z$H$;=rJ`TaYUUF!5fC(5#}+oA7>O;NeG$am|ExibMKH53HHn5lnL$30MSB#Lt W zoj1;{PbmKGYrBr*-xee+E*-SLV}cjH=o?5Z{c~r?dRzo^a7W>h=~}c;iv^DA*7&Oz zy>QnjY<6(pJBIuJgZhS!+c53fBq!ufC*2UYt5J(Tqf_BVKXNx(YYxOQFNi8Va4M&V zpm_QC{DDL4rM)a?6`n45t`+pGxyd-3k2y3oBO&Ph zoFzU9@IHB_`cO3q7Z&}hqu%q`(}X6RRQVw^Ej?SCf|K{d>gjVKx{sS?Sx?YOw1>FL zvw@0nk5LZxMDuUnYg&X?V@F_|*H+e6@h!aM?__1?%Ku20u#CWfkY@4))zJi`{nb6v zN-!q@JvB+-H&f&TYisPD6M2Y7QB(~3_rS;RmCPk!y#%>gju;h0squj24LPcpow`jE zGwBicSf1-i-slfTyS$L_CSDnoYeSmUEaPU=&sX@6$CiBbk9CO`pnZh?W9y8@2Ffbu%`{YId6!bZRE`?_)Uz8Ry~}*vU>dt4JcJ>;x#ExpES%@n& z1y*+?m7eGV=HoVzjeEzq5K$*{oOZoz0?j^Nzby5l{fds+l)wxgAmoU`UdjA!RYpW4 zh8GrZ-PUXX00i-{A@xt5c&)WQITqql$qT;H$KPkCu4X2F=8WNbU+Y=E{d$l~_C%x! z4xx)lp7f5P%JndSn_eu0CA>N#e_l*V&4VH>5EPyGi#pHl779E|9a|GU!iOAqTUV0=tRv zaVdb!0n%Q3_~hdcenbzW=ej+w9#`b6W4SH(-{-iWrP1H0B z`(C_JF6yz4MkBOH@k0LztGxz1fd^<6et$LFcs}41%eL#v5Um+=r!&4-S(QSMN|nM0 zN@qP(%uPQK9GZjiyDZJV@wrKU_;1Hg{MWqCO?7>i-?fv9QkNA29@ItNw+0kvCG$eJ30jmYH6p-{trkxp5 zrfO*{U6k3SOJ_TEM&BkT=1v<=rJ5FGlCi0AmybTWbfs0{tHOR8Tlqj(mpx+PaZKoFT$J2Sbvb$Ju zew4j`bI|sDu`zMOCu4hY^YeNwgEbAXE)wRWwObKge_c+vdfaoUIw5H(j}{)dK5)+w zqX!wDJjz(+ILRyL6x3cYd~IatXYsiLlm&8ru*!#GbHOnpg}j~j0?86lnowo-eTBib z$oC7J&}#2)#1zT{-jWnOXZZB#BdVG*y;G^Z9dWFc*wM{Mh)@$7fpWoO9K|uP(6H!zk8Nt*+FWWu7^V_;l%< zio9eT&X;d@mBNl+&(5Z=8CXjR*VxObdcPwl^17)15_zc;c{)EkJZS@aSMkpVapo|y zBo?_|y%TR4<&y$%qvR6B0#oqlv?JiPeljPywx$!4h zGuf*#sy}TRI5jjqOL2hO#rz|uA=3^%OFCIXb#L0wt?#qef4nrU`sS>?hCgq$v;_y| z!u^{3CEY#O=$5~IVL_z2aGwW$+@WYK9N-@VGBqQcOe)e9cmWk2#H^ufS1sw@Yw?Qu z3`>-@y`=enWMZ+Fh)1dq)5J%A3Dt!~LS(&XiSxMWyH{l!a z8Yx^Ir_KSxEiOeQ2FoE^CSr`YQAbY>iu7w*js+uMlO9Xj#W5(PHA6#vuhM};pA;M2 zS=hPi;^m{0!Di$iFr>J(?Uu#NV`I`)kXk^bB$TO!?^GnfW1zp_PH*8}_liw>#BoK^ z^T0Xr1$N_JzhBC^i8^wLhf7PW$(WMs4LJnTJVmC8G~abxf1%6%Y5I>`MnpZ!Qigb_ z8&_7fZTp6#Hi43^6!+UZgECDQU{pr@UqX;oXL9<3*IKi{-3wP&m31YE64Lq$>r6k0 zl=G2Z&Au@@kib!{>W2#l?U5Bb=6Y!P@DBIM#rP1j{jGcL+v;SpvUPT?fYKa?&sMow zjmuoK(FbuW+mtC?M1SrCYekxyCrTI|5<)+FI@47rdu<}vGvKG^wm=$<3o(rjPwK~4%KLsxmaO^YbMuNqP z5el@J`bHcpNggGi`E14cOM0LG39xM9A?2%xzJt_JQGRFxDKpzw?>pmSb_U~f&`6Z(Cv+*rpUlxmCnmgBy9;fl_e#TA9u-QRr`3! z?&&ZN7M*n?^;smnS(jsfz!@u(kI@~Q+?Hk* zn>$#1cc<9t;}cHyJql$A3CZZEx}b*MrZ%qxvBBs<9UU0fpiY7 zz}}5aY!tI-mxRa1NEGF=8l90h2Ap9h#@``p7yb1!4kl3U0})0zY^v)jb3N(KKnz;C zA_eP)zVe^@@x%y5SRZzVV4t-5E-I&&-k#xfP`qsw=*e55{ zu62BZf+z8F*T%RM?vNkx4l?}Q)6-KXL}rC^*m;x#1x9em`T0gChkn0Hk6`l!C&gXvL{GG)}u%G9JkdwmX&W*nEAuO5ZppDx&@)?xnpc2Vv&pL(XJhi$E@L5SSxC;p!A zhxwPh%USc?(x=(#e96ism8m%QQB0NYnDXom z0rw$G^8Ar>DI0=-MY2<@bhV?El^ks^x4W2-3inijuX^YF8rJKcLzVT3J?y=!-)zz4 zI5Y$<%%yXuqO9$tIHw6+$h}H$j%q`MfBp`nQvnk;GUq`sE#+ESZa185uxl)JIBy`O z?GAa*w%4{b>#?Be4r%rv zCsbD-@9xI6WxG08ym_lUjfETTQF!rbJTWCjro7zmM5dp=eQ|O9(1mVc^Ynyp!>8%fn2gyu z6D5xIn^Px(7f(q&AW&9?CJ3oqJ0nCcycS0mN_P9z5($JAg~4J84wrxg|1yORH)wU! T2Fd~TJmiVII;vdm#k>ClOMHU) literal 0 HcmV?d00001 From 7063d94b97c978a9a55ee14da0217300845722fc Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Sun, 20 Aug 2017 23:44:29 +0900 Subject: [PATCH 198/228] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 189cef5..1f48e99 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Iris is a interpreter of ISLisp implemented with golang [![Build Status](https://travis-ci.org/ta2gch/iris.svg?branch=master)](https://travis-ci.org/ta2gch/iris) - +![logo](logo.png) ## Introduction @@ -26,4 +26,4 @@ $ go test ./... This software is licensed under the Mozilla Public License v2.0 ## Copyright -Copyright (c) 2017 TANIGUCHI Masaya \ No newline at end of file +Copyright (c) 2017 TANIGUCHI Masaya From f07534c9316d8daf38914c0af85bd630db48031e Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Mon, 21 Aug 2017 10:14:58 +0900 Subject: [PATCH 199/228] Added defmethod & defgeneric --- runtime/conditional_expressions.go | 8 +- runtime/defining_classes.go | 148 ++++++++++++++++++++++-- runtime/defining_classes_test.go | 83 +++++++++++++ runtime/dynamic_variables.go | 7 +- runtime/generic_functions.go | 87 ++++++++++++++ runtime/ilos/ilos.go | 25 ++-- runtime/ilos/instance/built-in-class.go | 3 - runtime/ilos/instance/class.go | 2 +- runtime/ilos/instance/error.go | 9 ++ runtime/ilos/instance/function.go | 59 ++++++++-- runtime/ilos/instance/instance.go | 43 ++++--- runtime/ilos/instance/list.go | 45 +++++++ runtime/ilos/instance/symbol.go | 2 + runtime/iteration.go | 7 +- runtime/list_operations.go | 38 +++--- runtime/macros.go | 5 +- runtime/namedfunc.go | 5 +- runtime/sequence_functions.go | 4 +- runtime/test.go | 2 +- runtime/variables.go | 14 +-- 20 files changed, 484 insertions(+), 112 deletions(-) create mode 100644 runtime/defining_classes_test.go create mode 100644 runtime/generic_functions.go diff --git a/runtime/conditional_expressions.go b/runtime/conditional_expressions.go index 9aae43b..5be4bdd 100644 --- a/runtime/conditional_expressions.go +++ b/runtime/conditional_expressions.go @@ -93,8 +93,7 @@ func Case(local, global environment.Environment, key ilos.Instance, pattern ...i if err := ensure(class.List, form[0]); err != nil { return nil, err } - keys := form[0].(instance.List).Slice() - for _, k := range keys { + for _, k := range form[0].(instance.List).Slice() { if k == key { return Progn(local, global, form[1:]...) } @@ -140,9 +139,8 @@ func CaseUsing(local, global environment.Environment, key, pred ilos.Instance, p if err := ensure(class.List, form[0]); err != nil { return nil, err } - keys := form[0].(instance.List).Slice() - for _, k := range keys { - ret, err := pred.(instance.Function).Apply(local, global, k, key) + for _, k := range form[0].(instance.List).Slice() { + ret, err := pred.(instance.Applicable).Apply(local, global, k, key) if err != nil { return nil, err } diff --git a/runtime/defining_classes.go b/runtime/defining_classes.go index 4ccc157..f742c3e 100644 --- a/runtime/defining_classes.go +++ b/runtime/defining_classes.go @@ -5,6 +5,9 @@ package runtime import ( + "fmt" + "reflect" + "github.com/ta2gch/iris/runtime/environment" "github.com/ta2gch/iris/runtime/ilos" "github.com/ta2gch/iris/runtime/ilos/class" @@ -15,7 +18,27 @@ func Class(local, global environment.Environment, className ilos.Instance) (ilos if v, ok := global.Class.Get(className); ok { return v.(ilos.Class), nil } - return nil, nil + return nil, instance.NewUndefinedClass(className) +} + +func checkSuperClass(a, b ilos.Class) bool { + if reflect.DeepEqual(a, class.StandardObject) || reflect.DeepEqual(b, class.StandardObject) { + return false + } + if ilos.SubclassOf(a, b) || ilos.SubclassOf(b, a) { + return true + } + for _, c := range a.Supers() { + if checkSuperClass(c, b) { + return true + } + } + for _, c := range b.Supers() { + if checkSuperClass(a, c) { + return true + } + } + return false } func Defclass(local, global environment.Environment, className, scNames, slotSpecs ilos.Instance, classOpts ...ilos.Instance) (ilos.Instance, ilos.Instance) { @@ -25,12 +48,17 @@ func Defclass(local, global environment.Environment, className, scNames, slotSpe if err := ensure(class.List, scNames, slotSpecs); err != nil { return nil, err } - supers := []ilos.Class{} + supers := []ilos.Class{class.StandardObject} for _, scName := range scNames.(instance.List).Slice() { super, err := Class(local, global, scName) if err != nil { return nil, err } + for _, before := range supers { + if checkSuperClass(before, super) { + return nil, instance.NewArityError() + } + } supers = append(supers, super.(ilos.Class)) } slots := []ilos.Instance{} @@ -60,31 +88,137 @@ func Defclass(local, global environment.Environment, className, scNames, slotSpe var err ilos.Instance switch classOpt.(*instance.Cons).Car { case instance.NewSymbol(":METACLASS"): - if metaclass, err = Class(local, global, classOpt.(*instance.Cons).Cdr.(*instance.Cons).Car); err != nil { + if metaclass, err = Class(local, global, classOpt.(instance.List).Nth(1)); err != nil { return nil, err } case instance.NewSymbol(":ABSTRACTP"): - if abstractp, err = Eval(local, global, classOpt.(*instance.Cons).Cdr.(*instance.Cons).Car); err != nil { + if abstractp, err = Eval(local, global, classOpt.(instance.List).Nth(1)); err != nil { return nil, err } } } - global.Class.Define(className, instance.NewStandardClass(className, supers, slots, initforms, initargs, metaclass, abstractp)) + classObject := instance.NewStandardClass(className, supers, slots, initforms, initargs, metaclass, abstractp) + global.Class.Define(className, classObject) for _, slotSpec := range slotSpecs.(instance.List).Slice() { if ilos.InstanceOf(class.Symbol, slotSpec) { continue } - // slotName := slotSpec.(*instance.Cons).Car + slotName := slotSpec.(*instance.Cons).Car slotOpts := slotSpec.(*instance.Cons).Cdr.(instance.List).Slice() + var readerFunctionName, writerFunctionName, boundpFunctionName ilos.Instance for i := 0; i < len(slotOpts); i += 2 { switch slotOpts[i] { - // Add to generic functions case instance.NewSymbol(":READER"): + readerFunctionName = slotOpts[i+1] case instance.NewSymbol(":WRITER"): + writerFunctionName = instance.NewSymbol(fmt.Sprintf("(SETF %v)", slotOpts[i+1])) case instance.NewSymbol(":ACCESSOR"): + readerFunctionName = slotOpts[i+1] + writerFunctionName = instance.NewSymbol(fmt.Sprintf("(SETF %v)", slotOpts[i+1])) case instance.NewSymbol(":BOUNDP"): + boundpFunctionName = slotOpts[i+1] + } + } + if readerFunctionName != nil { + lambdaList, err := List(local, global, instance.NewSymbol("INSTANCE")) + if err != nil { + return nil, err + } + if _, ok := global.Function.Get(readerFunctionName); !ok { + Defgeneric(local, global, readerFunctionName, lambdaList) + } + fun, _ := global.Function.Get(readerFunctionName) + fun.(*instance.GenericFunction).AddMethod(nil, lambdaList, []ilos.Class{classObject}, instance.NewFunction(readerFunctionName, func(local, global environment.Environment, instance ilos.Instance) (ilos.Instance, ilos.Instance) { + slot, ok := instance.GetSlotValue(slotName, classObject) + if ok { + return slot, nil + } + return Nil, nil + })) + } + if writerFunctionName != nil { + lambdaList, err := List(local, global, instance.NewSymbol("INSTANCE")) + if err != nil { + return nil, err + } + if _, ok := global.Function.Get(writerFunctionName); !ok { + Defgeneric(local, global, writerFunctionName, lambdaList) + + } + fun, _ := global.Function.Get(writerFunctionName) + fun.(*instance.GenericFunction).AddMethod(nil, lambdaList, []ilos.Class{classObject}, instance.NewFunction(writerFunctionName, func(local, global environment.Environment, obj, instance ilos.Instance) (ilos.Instance, ilos.Instance) { + ok := instance.SetSlotValue(obj, slotName, classObject) + if ok { + return obj, nil + } + return Nil, nil + })) + } + if boundpFunctionName != nil { + lambdaList, err := List(local, global, instance.NewSymbol("INSTANCE")) + if err != nil { + return nil, err + } + if _, ok := global.Function.Get(boundpFunctionName); !ok { + Defgeneric(local, global, boundpFunctionName, lambdaList) } + fun, _ := global.Function.Get(boundpFunctionName) + fun.(*instance.GenericFunction).AddMethod(nil, lambdaList, []ilos.Class{classObject}, instance.NewFunction(boundpFunctionName, func(local, global environment.Environment, instance ilos.Instance) (ilos.Instance, ilos.Instance) { + _, ok := instance.GetSlotValue(slotName, classObject) + if ok { + return T, nil + } + return Nil, nil + })) } } return className, nil } + +func create(local, global environment.Environment, c ilos.Instance, i ...ilos.Instance) (ilos.Instance, ilos.Instance) { + p := []ilos.Instance{} + for _, q := range c.(ilos.Class).Supers() { + s, err := create(local, global, q, i...) + if err != nil { + return nil, err + } + p = append(p, s) + } + return initializeObject(local, global, instance.NewInstance(c.(ilos.Class), p), i...) +} + +func Create(local, global environment.Environment, c ilos.Instance, i ...ilos.Instance) (ilos.Instance, ilos.Instance) { + if err := ensure(class.StandardClass, c); err != nil { + return nil, err + } + //pp.Print(create(local, global, c, i...)) + return create(local, global, c, i...) +} + +func initializeObject(local, global environment.Environment, object ilos.Instance, inits ...ilos.Instance) (ilos.Instance, ilos.Instance) { + for _, super := range object.(instance.Instance).Supers { + initializeObject(local, global, super, inits...) + } + for i := 0; i < len(inits); i += 2 { + argName := inits[i] + argValue := inits[i+1] + if slotName, ok := object.Class().Initarg(argName); ok { + object.SetSlotValue(slotName, argValue, object.Class()) + } + } + for _, slotName := range object.Class().Slots() { + if _, ok := object.GetSlotValue(slotName, object.Class()); !ok { + form, _ := object.Class().Initform(slotName) + value, _ := Eval(local, global, form) + object.SetSlotValue(slotName, value, object.Class()) + } + } + return object, nil +} + +func InitializeObject(local, global environment.Environment, object ilos.Instance, inits ...ilos.Instance) (ilos.Instance, ilos.Instance) { + if err := ensure(class.StandardObject, object); err != nil { + return nil, err + } + return initializeObject(local, global, object, inits...) +} diff --git a/runtime/defining_classes_test.go b/runtime/defining_classes_test.go new file mode 100644 index 0000000..fb2fa57 --- /dev/null +++ b/runtime/defining_classes_test.go @@ -0,0 +1,83 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package runtime + +import "testing" + +func TestDefclass(t *testing.T) { + defspecial(Defclass) + defspecial(Defgeneric) + defspecial(Defmethod) + defspecial(Quote) + defun(Sqrt) + defun2("+", Add) + defun2("-", Substruct) + defun2("*", Multiply) + defspecial(Let) + defun(List) + defspecial(defun) + defun(Create) + defglobal("NIL", Nil) + defspecial(Class) + tests := []test{ + { + exp: `(defclass Foo () (a))`, + want: `'foo`, + wantErr: false, + }, + { + exp: `(defclass Bar1 (Foo) (b1))`, + want: `'Bar1`, + wantErr: false, + }, + { + exp: `(defclass Bar2 (Foo Bar1) (b1))`, + want: `'Bar2`, + wantErr: true, + }, + { + exp: ` + (defclass () + ((x :accessor point-x :initform 0.0 :initarg x) + (y :accessor point-y :initform 0.0 :initarg y))) + `, + want: `'`, + wantErr: false, + }, + { + exp: ` + (defclass () + ((x :accessor point-x :initform 0.0 :initarg x) + (y :accessor point-y :initform 0.0 :initarg y) + (z :accessor point-z :initform 0.0 :initarg z))) + `, + want: `'`, + wantErr: false, + }, + { + exp: ` + (defgeneric distance (p1 p2)) + `, + want: `'distance`, + wantErr: false, + }, + { + exp: ` + (defmethod distance ((p1 ) (p2 )) + (let ((dx (- (point-x p1) (point-x p2))) + (dy (- (point-y p1) (point-y p2)))) + (sqrt (+ (* dx dx) (* dy dy))))) + `, + want: `'distance`, + wantErr: false, + }, + { + exp: `(distance (create (class ) 'x 100) (create (class ) 'y 100))`, + want: `(sqrt 20000)`, + wantErr: false, + }, + } + execTests(t, Defclass, tests) +} diff --git a/runtime/dynamic_variables.go b/runtime/dynamic_variables.go index b286fdb..59e2ea5 100644 --- a/runtime/dynamic_variables.go +++ b/runtime/dynamic_variables.go @@ -86,15 +86,14 @@ func DynamicLet(local, global environment.Environment, varForm ilos.Instance, bo if err := ensure(class.List, cadr); err != nil { return nil, err } - s := cadr.(instance.List).Slice() - if len(s) != 2 { + if cadr.(instance.List).Length() != 2 { return nil, instance.NewArityError() } - f, err := Eval(local, global, s[1]) + f, err := Eval(local, global, cadr.(instance.List).Nth(1)) if err != nil { return nil, err } - vfs[s[0]] = f + vfs[cadr.(instance.List).Nth(0)] = f } for v, f := range vfs { if !local.DynamicVariable.Define(v, f) { diff --git a/runtime/generic_functions.go b/runtime/generic_functions.go new file mode 100644 index 0000000..bcaf042 --- /dev/null +++ b/runtime/generic_functions.go @@ -0,0 +1,87 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package runtime + +import ( + "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/ilos" + "github.com/ta2gch/iris/runtime/ilos/class" + "github.com/ta2gch/iris/runtime/ilos/instance" +) + +func Defmethod(local, global environment.Environment, arguments ...ilos.Instance) (ilos.Instance, ilos.Instance) { + if len(arguments) < 2 { + return nil, instance.NewArityError() + } + name := arguments[0] + var qualifier ilos.Instance + i := 0 + if arguments[1] == instance.NewSymbol(":AROUND") || arguments[1] == instance.NewSymbol(":BEFORE") || arguments[1] == instance.NewSymbol(":AFTER") { + qualifier = arguments[1] + i++ + } + parameterList := []ilos.Instance{} + for _, pp := range arguments[i+1].(instance.List).Slice() { + if ilos.InstanceOf(class.Symbol, pp) { + parameterList = append(parameterList, pp) + } else { + parameterList = append(parameterList, pp.(instance.List).Nth(0)) + } + } + lambdaList, err := List(local, global, parameterList...) + if err != nil { + return nil, err + } + classList := []ilos.Class{} + for _, pp := range arguments[i+1].(instance.List).Slice() { + if pp == instance.NewSymbol(":REST") && pp == instance.NewSymbol("&REST") { + break + } + if ilos.InstanceOf(class.Symbol, pp) { + classList = append(classList, class.Object) + } else { + class, ok := global.Class.Get(pp.(instance.List).Nth(1)) + if !ok { + return nil, instance.NewUndefinedClass(pp.(instance.List).Nth(1)) + } + classList = append(classList, class.(ilos.Class)) + } + } + fun, err := newNamedFunction(local, global, name, lambdaList, arguments[i+2:]...) + if err != nil { + return nil, err + } + gen, ok := global.Function.Get(name) + if !ok { + return nil, instance.NewUndefinedFunction(name) + } + if !gen.(*instance.GenericFunction).AddMethod(qualifier, lambdaList, classList, fun) { + return nil, instance.NewUndefinedFunction(name) + } + return name, nil +} + +func Defgeneric(local, global environment.Environment, funcSpec, lambdaList ilos.Instance, optionsOrMethodDescs ...ilos.Instance) (ilos.Instance, ilos.Instance) { + var methodCombination ilos.Instance + genericFunctionClass := class.StandardGenericFunction + forms := []ilos.Instance{} + for _, optionOrMethodDesc := range optionsOrMethodDescs { + switch optionOrMethodDesc.(instance.List).Nth(0) { + case instance.NewSymbol(":METHOD-COMBINATION"): + methodCombination = optionOrMethodDesc.(instance.List).Nth(1) + case instance.NewSymbol(":GENERIC-FUNCTION-CLASS"): + class, ok := global.Class.Get(optionOrMethodDesc.(instance.List).Nth(1)) + if !ok { + return nil, instance.NewUndefinedClass(optionOrMethodDesc.(instance.List).Nth(1)) + } + genericFunctionClass = class.(ilos.Class) + case instance.NewSymbol(":METHOD"): + forms = append(forms, instance.NewCons(instance.NewSymbol("DEFMETHOD"), optionOrMethodDesc.(instance.List).NthCdr(1))) + } + } + global.Function.Define(funcSpec, instance.NewGenericFunction(funcSpec, lambdaList, methodCombination, genericFunctionClass)) + Progn(local, global, forms...) + return funcSpec, nil +} diff --git a/runtime/ilos/ilos.go b/runtime/ilos/ilos.go index f3147e1..7aaa5fc 100644 --- a/runtime/ilos/ilos.go +++ b/runtime/ilos/ilos.go @@ -27,27 +27,24 @@ type Instance interface { } func SubclassOf(super, sub Class) bool { - is := func(c, p Class) bool { - var sub func(c, p Class) bool - sub = func(c, p Class) bool { - if reflect.DeepEqual(c, p) { - return true - } - for _, d := range c.Supers() { - if sub(d, p) { - return true - } - } - return false + var subclassof func(p, c Class) bool + subclassof = func(p, c Class) bool { + if reflect.DeepEqual(c, p) { + return true } for _, d := range c.Supers() { - if sub(d, p) { + if subclassof(p, d) { return true } } return false } - return is(sub, super) + for _, d := range sub.Supers() { + if subclassof(super, d) { + return true + } + } + return false } func InstanceOf(p Class, i Instance) bool { diff --git a/runtime/ilos/instance/built-in-class.go b/runtime/ilos/instance/built-in-class.go index 7c8e712..08d15de 100644 --- a/runtime/ilos/instance/built-in-class.go +++ b/runtime/ilos/instance/built-in-class.go @@ -21,9 +21,6 @@ func NewBuiltInClass(name string, super ilos.Class, slots ...string) ilos.Class for _, slot := range slots { slotNames = append(slotNames, NewSymbol(slot)) } - if super == nil { - return BuiltInClass{NewSymbol(name), []ilos.Class{}, slotNames} - } return BuiltInClass{NewSymbol(name), []ilos.Class{super}, slotNames} } diff --git a/runtime/ilos/instance/class.go b/runtime/ilos/instance/class.go index 51879ad..8cb8e94 100644 --- a/runtime/ilos/instance/class.go +++ b/runtime/ilos/instance/class.go @@ -8,7 +8,7 @@ import ( "github.com/ta2gch/iris/runtime/ilos" ) -var ObjectClass = NewBuiltInClass("", nil) +var ObjectClass = BuiltInClass{NewSymbol(""), []ilos.Class{}, []ilos.Instance{}} var BuiltInClassClass = NewBuiltInClass("", ObjectClass) var StandardClassClass = NewBuiltInClass("", ObjectClass) var BasicArrayClass = NewBuiltInClass("", ObjectClass) diff --git a/runtime/ilos/instance/error.go b/runtime/ilos/instance/error.go index 08c3e0f..321bd68 100644 --- a/runtime/ilos/instance/error.go +++ b/runtime/ilos/instance/error.go @@ -9,6 +9,7 @@ import ( "runtime" "strings" + "github.com/k0kubun/pp" "github.com/ta2gch/iris/runtime/ilos" ) @@ -55,6 +56,7 @@ func NewParseError(str, expectedClass ilos.Instance) ilos.Instance { } func NewDomainError(object ilos.Instance, expectedClass ilos.Class) ilos.Instance { + pp.Println(object, expectedClass) return newInstance(DomainErrorClass, map[ilos.Instance]ilos.Instance{ NewSymbol("CAUSE"): NewSymbol("DOMAIN-ERROR"), NewSymbol("OBJECT"): object, @@ -76,6 +78,13 @@ func NewUndefinedVariable(name ilos.Instance) ilos.Instance { }) } +func NewUndefinedClass(name ilos.Instance) ilos.Instance { + return newInstance(UndefinedVariableClass, map[ilos.Instance]ilos.Instance{ + NewSymbol("NAME"): name, + NewSymbol("NAMESPACE"): NewSymbol("CLASS"), + }) +} + func NewArityError() ilos.Instance { //stackTrace() return newInstance(ProgramErrorClass, map[ilos.Instance]ilos.Instance{}) diff --git a/runtime/ilos/instance/function.go b/runtime/ilos/instance/function.go index 54f6670..ffa3f5c 100644 --- a/runtime/ilos/instance/function.go +++ b/runtime/ilos/instance/function.go @@ -74,26 +74,47 @@ type GenericFunction struct { } func NewGenericFunction(funcSpec, lambdaList, methodCombination ilos.Instance, genericFunctionClass ilos.Class) ilos.Instance { - return GenericFunction{funcSpec, lambdaList, methodCombination, genericFunctionClass, []method{}} + return &GenericFunction{funcSpec, lambdaList, methodCombination, genericFunctionClass, []method{}} } -func (GenericFunction) Class() ilos.Class { - return GenericFunctionClass +func (f *GenericFunction) AddMethod(qualifier, lambdaList ilos.Instance, classList []ilos.Class, function ilos.Instance) bool { + if f.lambdaList.(List).Length() != lambdaList.(List).Length() { + return false + } + for i, param := range f.lambdaList.(List).Slice() { + if param == NewSymbol(":REST") || param == NewSymbol("&REST") { + if lambdaList.(List).Nth(i) != NewSymbol(":REST") && lambdaList.(List).Nth(i) != NewSymbol("&REST") { + return false + } + } + } + for _, method := range f.methods { + if method.qualifier == qualifier { + method.function = function.(Function) + return true + } + } + f.methods = append(f.methods, method{qualifier, classList, function.(Function)}) + return true +} + +func (f *GenericFunction) Class() ilos.Class { + return f.genericFunctionClass } -func (f GenericFunction) GetSlotValue(_ ilos.Instance, _ ilos.Class) (ilos.Instance, bool) { +func (f *GenericFunction) GetSlotValue(_ ilos.Instance, _ ilos.Class) (ilos.Instance, bool) { return nil, false } -func (f GenericFunction) SetSlotValue(_, _ ilos.Instance, _ ilos.Class) bool { +func (f *GenericFunction) SetSlotValue(_, _ ilos.Instance, _ ilos.Class) bool { return false } -func (f GenericFunction) String() string { +func (f *GenericFunction) String() string { return fmt.Sprintf("#%v", f.Class()) } -func (f GenericFunction) Apply(local, global environment.Environment, arguments ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func (f *GenericFunction) Apply(local, global environment.Environment, arguments ...ilos.Instance) (ilos.Instance, ilos.Instance) { parameters := f.lambdaList.(List).Slice() variadic := false { @@ -138,7 +159,7 @@ func (f GenericFunction) Apply(local, global environment.Environment, arguments return Nil, nil }) nextMethodPisT := NewFunction(NewSymbol("NEXT-METHOD-P"), func(local, global environment.Environment) (ilos.Instance, ilos.Instance) { - return NewSymbol("T"), nil + return T, nil }) if f.methodCombination == NewSymbol("NIL") { var callNextMethod func(local, global environment.Environment) (ilos.Instance, ilos.Instance) // To Recursive @@ -291,12 +312,23 @@ func (f GenericFunction) Apply(local, global environment.Environment, arguments } return methods[int(depth.(Integer))].function.Apply(local, global, arguments...) } // callNextMethod ends here + // Do All :before mehtods + for _, method := range methods { + if method.qualifier == before { + if _, err := method.function.Apply(local, global, arguments...); err != nil { + return nil, err + } + } + } index := 0 // index of the first primary method { test := func(i int) bool { return methods[i].qualifier == nil } width := len(methods) index := sort.Search(width, test) local.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) + if index == len(methods) { + return nil, NewUndefinedFunction(f.funcSpec) + } } local.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) { // If Generic Function has next method, set these functions @@ -307,6 +339,15 @@ func (f GenericFunction) Apply(local, global environment.Environment, arguments local.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } } - return methods[index].function.Apply(local, global, arguments...) + ret, err := methods[index].function.Apply(local, global, arguments...) + // Do all :after methods + for i := len(methods) - 1; i >= 0; i-- { + if methods[i].qualifier == after { + if _, err := methods[i].function.Apply(local, global, arguments...); err != nil { + return nil, err + } + } + } + return ret, err } } diff --git a/runtime/ilos/instance/instance.go b/runtime/ilos/instance/instance.go index b06cbf1..647b593 100644 --- a/runtime/ilos/instance/instance.go +++ b/runtime/ilos/instance/instance.go @@ -6,6 +6,7 @@ package instance import ( "fmt" + "reflect" "github.com/ta2gch/iris/runtime/ilos" ) @@ -25,32 +26,28 @@ func newInstance(c ilos.Class, s ...interface{}) ilos.Instance { t[slotName] = argValue } } - /* - for _, slotName := range c.Slots() { - if _, ok := t[slotName]; !ok { - t[slotName], _ = c.Initform(slotName) - t[slotName], _ = Eval(local, global, t[slotName]) - } - } - */ - return instance{c, p, t} + return Instance{c, p, t} +} + +func NewInstance(class ilos.Class, supers []ilos.Instance) ilos.Instance { + return Instance{class, supers, map[ilos.Instance]ilos.Instance{}} } -type instance struct { +type Instance struct { class ilos.Class - supers []ilos.Instance + Supers []ilos.Instance slots map[ilos.Instance]ilos.Instance } -func (i instance) Class() ilos.Class { +func (i Instance) Class() ilos.Class { return i.class } -func (i instance) GetSlotValue(key ilos.Instance, class ilos.Class) (ilos.Instance, bool) { - if v, ok := i.slots[key]; ok && i.class == class { +func (i Instance) GetSlotValue(key ilos.Instance, class ilos.Class) (ilos.Instance, bool) { + if v, ok := i.slots[key]; ok && reflect.DeepEqual(i.class, class) { return v, ok } - for _, s := range i.supers { + for _, s := range i.Supers { if v, ok := s.GetSlotValue(key, class); ok { return v, ok } @@ -58,12 +55,12 @@ func (i instance) GetSlotValue(key ilos.Instance, class ilos.Class) (ilos.Instan return nil, false } -func (i instance) SetSlotValue(key ilos.Instance, value ilos.Instance, class ilos.Class) bool { - if _, ok := i.slots[key]; ok && i.class == class { +func (i Instance) SetSlotValue(key ilos.Instance, value ilos.Instance, class ilos.Class) bool { + if reflect.DeepEqual(i.class, class) { i.slots[key] = value return true } - for _, s := range i.supers { + for _, s := range i.Supers { if ok := s.SetSlotValue(key, value, class); ok { return ok } @@ -71,14 +68,14 @@ func (i instance) SetSlotValue(key ilos.Instance, value ilos.Instance, class ilo return false } -func (i instance) Slots() map[ilos.Instance]ilos.Instance { +func (i Instance) Slots() map[ilos.Instance]ilos.Instance { m := map[ilos.Instance]ilos.Instance{} for k, v := range i.slots { m[k] = v } - for _, c := range i.supers { - if _, ok := c.(*instance); ok { - for k, v := range c.(*instance).Slots() { + for _, c := range i.Supers { + if _, ok := c.(Instance); ok { + for k, v := range c.(Instance).Slots() { m[k] = v } } @@ -86,7 +83,7 @@ func (i instance) Slots() map[ilos.Instance]ilos.Instance { return m } -func (i instance) String() string { +func (i Instance) String() string { c := i.Class().String() return fmt.Sprintf("#%v %v>", c[:len(c)-1], i.Slots()) } diff --git a/runtime/ilos/instance/list.go b/runtime/ilos/instance/list.go index 5d410dd..ef2c4a2 100644 --- a/runtime/ilos/instance/list.go +++ b/runtime/ilos/instance/list.go @@ -12,6 +12,10 @@ import ( type List interface { Slice() []ilos.Instance + Nth(i int) ilos.Instance + SetNth(obj ilos.Instance, i int) + NthCdr(i int) ilos.Instance + Length() int } // @@ -82,6 +86,31 @@ func (i *Cons) Slice() []ilos.Instance { return s } +func (i *Cons) Length() int { + return 1 + i.Cdr.(List).Length() +} + +func (i *Cons) Nth(n int) ilos.Instance { + if n == 0 { + return i.Car + } + return i.Cdr.(List).Nth(n - 1) +} + +func (i *Cons) SetNth(obj ilos.Instance, n int) { + if n == 0 { + i.Car = obj + } + i.Cdr.(List).SetNth(obj, n-1) +} + +func (i *Cons) NthCdr(n int) ilos.Instance { + if n == 0 { + return i.Cdr + } + return i.Cdr.(List).NthCdr(n - 1) +} + // // Null // @@ -113,3 +142,19 @@ func (*Null) String() string { func (*Null) Slice() []ilos.Instance { return []ilos.Instance{} } + +func (i *Null) Nth(n int) ilos.Instance { + return Nil +} + +func (i *Null) SetNth(obj ilos.Instance, n int) { + panic("NOT a cons") +} + +func (i *Null) NthCdr(n int) ilos.Instance { + return Nil +} + +func (i *Null) Length() int { + return 0 +} diff --git a/runtime/ilos/instance/symbol.go b/runtime/ilos/instance/symbol.go index ef2e415..e006edf 100644 --- a/runtime/ilos/instance/symbol.go +++ b/runtime/ilos/instance/symbol.go @@ -33,3 +33,5 @@ func (i Symbol) SetSlotValue(key ilos.Instance, value ilos.Instance, _ ilos.Clas func (i Symbol) String() string { return string(i) } + +var T = NewSymbol("T") diff --git a/runtime/iteration.go b/runtime/iteration.go index 6254c83..5f491ca 100644 --- a/runtime/iteration.go +++ b/runtime/iteration.go @@ -97,12 +97,11 @@ func For(local, global environment.Environment, iterationSpecs, endTestAndResult if err := ensure(class.List, is); err != nil { return nil, err } - i := is.(instance.List).Slice() - switch len(i) { + switch is.(instance.List).Length() { case 2: case 3: - var1 := i[0] - step := i[2] + var1 := is.(instance.List).Nth(0) + step := is.(instance.List).Nth(2) if local.Variable.Set(var1, step) { return nil, instance.NewImmutableBinding() } diff --git a/runtime/list_operations.go b/runtime/list_operations.go index 42b602f..fa95079 100644 --- a/runtime/list_operations.go +++ b/runtime/list_operations.go @@ -130,7 +130,7 @@ func Member(local, global environment.Environment, obj, list ilos.Instance) (ilo } for idx, elt := range list.(instance.List).Slice() { if obj == elt { // eql - return List(local, global, list.(instance.List).Slice()[idx:]...) + return list.(instance.List).NthCdr(idx), nil } } return Nil, nil @@ -156,9 +156,9 @@ func Mapcar(local, global environment.Environment, function, list1 ilos.Instance for i := 0; i < int(max); i++ { arguments := make([]ilos.Instance, len(lists)) for j, list := range lists { - arguments[j] = list.(instance.List).Slice()[i] + arguments[j] = list.(instance.List).Nth(i) } - ret, err := function.(instance.Function).Apply(local, global, arguments...) + ret, err := function.(instance.Applicable).Apply(local, global, arguments...) if err != nil { return nil, err } @@ -184,9 +184,9 @@ func Mapc(local, global environment.Environment, function, list1 ilos.Instance, for i := 0; i < int(max); i++ { arguments := make([]ilos.Instance, len(lists)) for j, list := range lists { - arguments[j] = list.(instance.List).Slice()[i] + arguments[j] = list.(instance.List).Nth(i) } - if _, err := function.(instance.Function).Apply(local, global, arguments...); err != nil { + if _, err := function.(instance.Applicable).Apply(local, global, arguments...); err != nil { return nil, err } } @@ -212,9 +212,9 @@ func Mapcan(local, global environment.Environment, function, list1 ilos.Instance for i := 0; i < int(max); i++ { arguments := make([]ilos.Instance, len(lists)) for j, list := range lists { - arguments[j] = list.(instance.List).Slice()[i] + arguments[j] = list.(instance.List).Nth(i) } - ret, err := function.(instance.Function).Apply(local, global, arguments...) + ret, err := function.(instance.Applicable).Apply(local, global, arguments...) if err != nil { return nil, err } @@ -242,13 +242,9 @@ func Maplist(local, global environment.Environment, function, list1 ilos.Instanc for i := 0; i < int(max); i++ { arguments := make([]ilos.Instance, len(lists)) for j, list := range lists { - var err ilos.Instance - arguments[j], err = List(local, global, list.(instance.List).Slice()[i:]...) - if err != nil { - return nil, err - } + arguments[j] = list.(instance.List).NthCdr(i) } - ret, err := function.(instance.Function).Apply(local, global, arguments...) + ret, err := function.(instance.Applicable).Apply(local, global, arguments...) if err != nil { return nil, err } @@ -274,13 +270,9 @@ func Mapl(local, global environment.Environment, function, list1 ilos.Instance, for i := 0; i < int(max); i++ { arguments := make([]ilos.Instance, len(lists)) for j, list := range lists { - var err ilos.Instance - arguments[j], err = List(local, global, list.(instance.List).Slice()[i:]...) - if err != nil { - return nil, err - } + arguments[j] = list.(instance.List).NthCdr(i) } - if _, err := function.(instance.Function).Apply(local, global, arguments...); err != nil { + if _, err := function.(instance.Applicable).Apply(local, global, arguments...); err != nil { return nil, err } } @@ -306,13 +298,9 @@ func Mapcon(local, global environment.Environment, function, list1 ilos.Instance for i := 0; i < int(max); i++ { arguments := make([]ilos.Instance, len(lists)) for j, list := range lists { - var err ilos.Instance - arguments[j], err = List(local, global, list.(instance.List).Slice()[i:]...) - if err != nil { - return nil, err - } + arguments[j] = list.(instance.List).NthCdr(i) } - ret, err := function.(instance.Function).Apply(local, global, arguments...) + ret, err := function.(instance.Applicable).Apply(local, global, arguments...) if err != nil { return nil, err } diff --git a/runtime/macros.go b/runtime/macros.go index 3070552..c7b6337 100644 --- a/runtime/macros.go +++ b/runtime/macros.go @@ -187,9 +187,8 @@ func expand(local, global environment.Environment, form ilos.Instance, level int // If the last cell of forms is not Nil, run this statements at first // the elements of exp is always a instance of because exp isn't appended lists in for-loop - slice := exp[i].(instance.List).Slice() - for j := len(slice) - 1; j >= 0; j-- { - lst = instance.NewCons(slice[j], lst) + for j := exp[i].(instance.List).Length() - 1; j >= 0; j-- { + lst = instance.NewCons(exp[i].(instance.List).Nth(j), lst) } } } diff --git a/runtime/namedfunc.go b/runtime/namedfunc.go index 55f2d93..15f6b7a 100644 --- a/runtime/namedfunc.go +++ b/runtime/namedfunc.go @@ -15,13 +15,12 @@ func checkLambdaList(lambdaList ilos.Instance) ilos.Instance { if err := ensure(class.List, lambdaList); err != nil { return err } - cdr := lambdaList.(instance.List).Slice() - for i, cadr := range cdr { + for i, cadr := range lambdaList.(instance.List).Slice() { if err := ensure(class.Symbol, cadr); err != nil { return err } if cadr == instance.NewSymbol(":REST") || cadr == instance.NewSymbol("&REST") { - if len(cdr) != i+2 { + if lambdaList.(instance.List).Length() != i+2 { return instance.NewArityError() } } diff --git a/runtime/sequence_functions.go b/runtime/sequence_functions.go index cb4d985..6216942 100644 --- a/runtime/sequence_functions.go +++ b/runtime/sequence_functions.go @@ -31,7 +31,7 @@ func Length(local, global environment.Environment, sequence ilos.Instance) (ilos case ilos.InstanceOf(class.GeneralVector, sequence): return instance.NewInteger(len(sequence.(instance.GeneralVector))), nil case ilos.InstanceOf(class.List, sequence): - return instance.NewInteger(len(sequence.(instance.List).Slice())), nil + return instance.NewInteger(sequence.(instance.List).Length()), nil } // TODO: class.Seq return nil, instance.NewDomainError(sequence, class.Object) @@ -204,7 +204,7 @@ func mapInto(local, global environment.Environment, destination, function ilos.I return nil, err } } - ret, err := function.(instance.Function).Apply(local, global, arguments...) + ret, err := function.(instance.Applicable).Apply(local, global, arguments...) if err != nil { return nil, err } diff --git a/runtime/test.go b/runtime/test.go index 3a6e565..592960b 100644 --- a/runtime/test.go +++ b/runtime/test.go @@ -28,7 +28,7 @@ func execTests(t *testing.T, function interface{}, tests []test) { t.Run(tt.exp, func(t *testing.T) { got, err := Eval(local, global, readFromString(tt.exp)) want, _ := Eval(local, global, readFromString(tt.want)) - if !reflect.DeepEqual(got, want) { + if !tt.wantErr && !reflect.DeepEqual(got, want) { t.Errorf("%v() got = %v, want %v", name, got, want) } if (err != nil) != tt.wantErr { diff --git a/runtime/variables.go b/runtime/variables.go index 9b330d5..51d2c57 100644 --- a/runtime/variables.go +++ b/runtime/variables.go @@ -56,15 +56,14 @@ func Let(local, global environment.Environment, varForm ilos.Instance, bodyForm if err := ensure(class.List, cadr); err != nil { return nil, err } - s := cadr.(instance.List).Slice() - if len(s) != 2 { + if cadr.(instance.List).Length() != 2 { return nil, instance.NewArityError() } - f, err := Eval(local, global, s[1]) + f, err := Eval(local, global, cadr.(instance.List).Nth(1)) if err != nil { return nil, err } - vfs[s[0]] = f + vfs[cadr.(instance.List).Nth(0)] = f } for v, f := range vfs { if !local.Variable.Define(v, f) { @@ -96,15 +95,14 @@ func LetStar(local, global environment.Environment, varForm ilos.Instance, bodyF if err := ensure(class.List, cadr); err != nil { return nil, err } - s := cadr.(instance.List).Slice() - if len(s) != 2 { + if cadr.(instance.List).Length() != 2 { return nil, instance.NewArityError() } - f, err := Eval(local, global, s[1]) + f, err := Eval(local, global, cadr.(instance.List).Nth(1)) if err != nil { return nil, err } - if !local.Variable.Define(s[0], f) { + if !local.Variable.Define(cadr.(instance.List).Nth(0), f) { return nil, instance.NewImmutableBinding() } } From a91ada49fa7a940a54dbc047e3887304b6b0b8fb Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Mon, 21 Aug 2017 15:05:08 +0900 Subject: [PATCH 200/228] Moved Create & IninializeObject --- runtime/defining_classes.go | 44 +++++-------------------------- runtime/defining_classes_test.go | 8 +++--- runtime/ilos/instance/instance.go | 42 ++++++++++++++++++++++++----- 3 files changed, 48 insertions(+), 46 deletions(-) diff --git a/runtime/defining_classes.go b/runtime/defining_classes.go index f742c3e..3598944 100644 --- a/runtime/defining_classes.go +++ b/runtime/defining_classes.go @@ -76,7 +76,11 @@ func Defclass(local, global environment.Environment, className, scNames, slotSpe for i := 0; i < len(slotOpts); i += 2 { switch slotOpts[i] { case instance.NewSymbol(":INITFORM"): - initforms[slotName] = slotOpts[i+1] + closure, err := newNamedFunction(local, global, instance.NewSymbol("CLOSURE"), Nil, slotOpts[i+1]) + if err != nil { + return nil, err + } + initforms[slotName] = closure case instance.NewSymbol(":INITARG"): initargs[slotOpts[i+1]] = slotName } @@ -175,50 +179,16 @@ func Defclass(local, global environment.Environment, className, scNames, slotSpe return className, nil } -func create(local, global environment.Environment, c ilos.Instance, i ...ilos.Instance) (ilos.Instance, ilos.Instance) { - p := []ilos.Instance{} - for _, q := range c.(ilos.Class).Supers() { - s, err := create(local, global, q, i...) - if err != nil { - return nil, err - } - p = append(p, s) - } - return initializeObject(local, global, instance.NewInstance(c.(ilos.Class), p), i...) -} - func Create(local, global environment.Environment, c ilos.Instance, i ...ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.StandardClass, c); err != nil { return nil, err } - //pp.Print(create(local, global, c, i...)) - return create(local, global, c, i...) -} - -func initializeObject(local, global environment.Environment, object ilos.Instance, inits ...ilos.Instance) (ilos.Instance, ilos.Instance) { - for _, super := range object.(instance.Instance).Supers { - initializeObject(local, global, super, inits...) - } - for i := 0; i < len(inits); i += 2 { - argName := inits[i] - argValue := inits[i+1] - if slotName, ok := object.Class().Initarg(argName); ok { - object.SetSlotValue(slotName, argValue, object.Class()) - } - } - for _, slotName := range object.Class().Slots() { - if _, ok := object.GetSlotValue(slotName, object.Class()); !ok { - form, _ := object.Class().Initform(slotName) - value, _ := Eval(local, global, form) - object.SetSlotValue(slotName, value, object.Class()) - } - } - return object, nil + return instance.Create(local, global, c, i...) } func InitializeObject(local, global environment.Environment, object ilos.Instance, inits ...ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.StandardObject, object); err != nil { return nil, err } - return initializeObject(local, global, object, inits...) + return instance.InitializeObject(local, global, object, inits...) } diff --git a/runtime/defining_classes_test.go b/runtime/defining_classes_test.go index fb2fa57..ea782db 100644 --- a/runtime/defining_classes_test.go +++ b/runtime/defining_classes_test.go @@ -39,9 +39,11 @@ func TestDefclass(t *testing.T) { }, { exp: ` + (let ((v 50)) (defclass () - ((x :accessor point-x :initform 0.0 :initarg x) - (y :accessor point-y :initform 0.0 :initarg y))) + ((x :accessor point-x :initform v :initarg x) + (y :accessor point-y :initform v :initarg y))) + ) `, want: `'`, wantErr: false, @@ -75,7 +77,7 @@ func TestDefclass(t *testing.T) { }, { exp: `(distance (create (class ) 'x 100) (create (class ) 'y 100))`, - want: `(sqrt 20000)`, + want: `(sqrt 5000)`, wantErr: false, }, } diff --git a/runtime/ilos/instance/instance.go b/runtime/ilos/instance/instance.go index 647b593..cb2ae5b 100644 --- a/runtime/ilos/instance/instance.go +++ b/runtime/ilos/instance/instance.go @@ -8,6 +8,7 @@ import ( "fmt" "reflect" + "github.com/ta2gch/iris/runtime/environment" "github.com/ta2gch/iris/runtime/ilos" ) @@ -29,13 +30,42 @@ func newInstance(c ilos.Class, s ...interface{}) ilos.Instance { return Instance{c, p, t} } -func NewInstance(class ilos.Class, supers []ilos.Instance) ilos.Instance { - return Instance{class, supers, map[ilos.Instance]ilos.Instance{}} +func Create(local, global environment.Environment, c ilos.Instance, i ...ilos.Instance) (ilos.Instance, ilos.Instance) { + p := []ilos.Instance{} + for _, q := range c.(ilos.Class).Supers() { + s, err := Create(local, global, q, i...) + if err != nil { + return nil, err + } + p = append(p, s) + } + return InitializeObject(local, global, Instance{c.(ilos.Class), p, map[ilos.Instance]ilos.Instance{}}, i...) +} + +func InitializeObject(local, global environment.Environment, object ilos.Instance, inits ...ilos.Instance) (ilos.Instance, ilos.Instance) { + for _, super := range object.(Instance).supers { + InitializeObject(local, global, super, inits...) + } + for i := 0; i < len(inits); i += 2 { + argName := inits[i] + argValue := inits[i+1] + if slotName, ok := object.Class().Initarg(argName); ok { + object.SetSlotValue(slotName, argValue, object.Class()) + } + } + for _, slotName := range object.Class().Slots() { + if _, ok := object.GetSlotValue(slotName, object.Class()); !ok { + form, _ := object.Class().Initform(slotName) + value, _ := form.(Applicable).Apply(local, global) + object.SetSlotValue(slotName, value, object.Class()) + } + } + return object, nil } type Instance struct { class ilos.Class - Supers []ilos.Instance + supers []ilos.Instance slots map[ilos.Instance]ilos.Instance } @@ -47,7 +77,7 @@ func (i Instance) GetSlotValue(key ilos.Instance, class ilos.Class) (ilos.Instan if v, ok := i.slots[key]; ok && reflect.DeepEqual(i.class, class) { return v, ok } - for _, s := range i.Supers { + for _, s := range i.supers { if v, ok := s.GetSlotValue(key, class); ok { return v, ok } @@ -60,7 +90,7 @@ func (i Instance) SetSlotValue(key ilos.Instance, value ilos.Instance, class ilo i.slots[key] = value return true } - for _, s := range i.Supers { + for _, s := range i.supers { if ok := s.SetSlotValue(key, value, class); ok { return ok } @@ -73,7 +103,7 @@ func (i Instance) Slots() map[ilos.Instance]ilos.Instance { for k, v := range i.slots { m[k] = v } - for _, c := range i.Supers { + for _, c := range i.supers { if _, ok := c.(Instance); ok { for k, v := range c.(Instance).Slots() { m[k] = v From 706931d9a71330ba53ab025668c5808e8dd1ce74 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Mon, 21 Aug 2017 16:53:27 +0900 Subject: [PATCH 201/228] Bugfix for :boundp method --- runtime/defining_classes.go | 21 +++++++-------- runtime/defining_classes_test.go | 11 +++++--- runtime/ilos/ilos.go | 4 --- runtime/ilos/instance/basic-array.go | 24 ----------------- runtime/ilos/instance/built-in-class.go | 12 ++------- runtime/ilos/instance/character.go | 8 ------ runtime/ilos/instance/function.go | 22 +++------------- runtime/ilos/instance/instance.go | 15 ++++++----- runtime/ilos/instance/list.go | 34 ------------------------- runtime/ilos/instance/number.go | 16 ------------ runtime/ilos/instance/standard-class.go | 8 ------ runtime/ilos/instance/symbol.go | 8 ------ runtime/non-local_exits.go | 10 ++++---- 13 files changed, 37 insertions(+), 156 deletions(-) diff --git a/runtime/defining_classes.go b/runtime/defining_classes.go index 3598944..abad011 100644 --- a/runtime/defining_classes.go +++ b/runtime/defining_classes.go @@ -8,6 +8,7 @@ import ( "fmt" "reflect" + "github.com/k0kubun/pp" "github.com/ta2gch/iris/runtime/environment" "github.com/ta2gch/iris/runtime/ilos" "github.com/ta2gch/iris/runtime/ilos/class" @@ -115,7 +116,7 @@ func Defclass(local, global environment.Environment, className, scNames, slotSpe case instance.NewSymbol(":READER"): readerFunctionName = slotOpts[i+1] case instance.NewSymbol(":WRITER"): - writerFunctionName = instance.NewSymbol(fmt.Sprintf("(SETF %v)", slotOpts[i+1])) + writerFunctionName = slotOpts[i+1] case instance.NewSymbol(":ACCESSOR"): readerFunctionName = slotOpts[i+1] writerFunctionName = instance.NewSymbol(fmt.Sprintf("(SETF %v)", slotOpts[i+1])) @@ -132,16 +133,16 @@ func Defclass(local, global environment.Environment, className, scNames, slotSpe Defgeneric(local, global, readerFunctionName, lambdaList) } fun, _ := global.Function.Get(readerFunctionName) - fun.(*instance.GenericFunction).AddMethod(nil, lambdaList, []ilos.Class{classObject}, instance.NewFunction(readerFunctionName, func(local, global environment.Environment, instance ilos.Instance) (ilos.Instance, ilos.Instance) { - slot, ok := instance.GetSlotValue(slotName, classObject) + fun.(*instance.GenericFunction).AddMethod(nil, lambdaList, []ilos.Class{classObject}, instance.NewFunction(readerFunctionName, func(local, global environment.Environment, object ilos.Instance) (ilos.Instance, ilos.Instance) { + slot, ok := object.(instance.Instance).GetSlotValue(slotName, classObject) if ok { return slot, nil } - return Nil, nil + return Nil, nil // TODO: shoud throw an error. })) } if writerFunctionName != nil { - lambdaList, err := List(local, global, instance.NewSymbol("INSTANCE")) + lambdaList, err := List(local, global, instance.NewSymbol("Y"), instance.NewSymbol("X")) if err != nil { return nil, err } @@ -150,8 +151,8 @@ func Defclass(local, global environment.Environment, className, scNames, slotSpe } fun, _ := global.Function.Get(writerFunctionName) - fun.(*instance.GenericFunction).AddMethod(nil, lambdaList, []ilos.Class{classObject}, instance.NewFunction(writerFunctionName, func(local, global environment.Environment, obj, instance ilos.Instance) (ilos.Instance, ilos.Instance) { - ok := instance.SetSlotValue(obj, slotName, classObject) + fun.(*instance.GenericFunction).AddMethod(nil, lambdaList, []ilos.Class{class.Object, classObject}, instance.NewFunction(writerFunctionName, func(local, global environment.Environment, obj, object ilos.Instance) (ilos.Instance, ilos.Instance) { + ok := object.(instance.Instance).SetSlotValue(obj, slotName, classObject) if ok { return obj, nil } @@ -167,13 +168,13 @@ func Defclass(local, global environment.Environment, className, scNames, slotSpe Defgeneric(local, global, boundpFunctionName, lambdaList) } fun, _ := global.Function.Get(boundpFunctionName) - fun.(*instance.GenericFunction).AddMethod(nil, lambdaList, []ilos.Class{classObject}, instance.NewFunction(boundpFunctionName, func(local, global environment.Environment, instance ilos.Instance) (ilos.Instance, ilos.Instance) { - _, ok := instance.GetSlotValue(slotName, classObject) + pp.Print(fun.(*instance.GenericFunction).AddMethod(nil, lambdaList, []ilos.Class{classObject}, instance.NewFunction(boundpFunctionName, func(local, global environment.Environment, object ilos.Instance) (ilos.Instance, ilos.Instance) { + _, ok := object.(instance.Instance).GetSlotValue(slotName, classObject) if ok { return T, nil } return Nil, nil - })) + }))) } } return className, nil diff --git a/runtime/defining_classes_test.go b/runtime/defining_classes_test.go index ea782db..a8689a1 100644 --- a/runtime/defining_classes_test.go +++ b/runtime/defining_classes_test.go @@ -51,9 +51,9 @@ func TestDefclass(t *testing.T) { { exp: ` (defclass () - ((x :accessor point-x :initform 0.0 :initarg x) - (y :accessor point-y :initform 0.0 :initarg y) - (z :accessor point-z :initform 0.0 :initarg z))) + ((x :boundp point-x :initarg x) + (y :boundp point-y :initarg y) + (z :boundp point-z :initarg z))) `, want: `'`, wantErr: false, @@ -80,6 +80,11 @@ func TestDefclass(t *testing.T) { want: `(sqrt 5000)`, wantErr: false, }, + { + exp: `(point-x (create (class )))`, + want: `nil`, + wantErr: false, + }, } execTests(t, Defclass, tests) } diff --git a/runtime/ilos/ilos.go b/runtime/ilos/ilos.go index 7aaa5fc..ced1bfb 100644 --- a/runtime/ilos/ilos.go +++ b/runtime/ilos/ilos.go @@ -14,15 +14,11 @@ type Class interface { Initform(Instance) (Instance, bool) Initarg(Instance) (Instance, bool) Class() Class - GetSlotValue(Instance, Class) (Instance, bool) - SetSlotValue(Instance, Instance, Class) bool String() string } type Instance interface { Class() Class - GetSlotValue(Instance, Class) (Instance, bool) - SetSlotValue(Instance, Instance, Class) bool String() string } diff --git a/runtime/ilos/instance/basic-array.go b/runtime/ilos/instance/basic-array.go index 54898ff..32b7c62 100644 --- a/runtime/ilos/instance/basic-array.go +++ b/runtime/ilos/instance/basic-array.go @@ -26,14 +26,6 @@ func (GeneralArrayStar) Class() ilos.Class { return GeneralArrayStarClass } -func (i GeneralArrayStar) GetSlotValue(key ilos.Instance, _ ilos.Class) (ilos.Instance, bool) { - return nil, false -} - -func (i GeneralArrayStar) SetSlotValue(key ilos.Instance, value ilos.Instance, _ ilos.Class) bool { - return false -} - func (i GeneralArrayStar) String() string { return "" } @@ -52,14 +44,6 @@ func (GeneralVector) Class() ilos.Class { return GeneralVectorClass } -func (i GeneralVector) GetSlotValue(key ilos.Instance, _ ilos.Class) (ilos.Instance, bool) { - return nil, false -} - -func (i GeneralVector) SetSlotValue(key ilos.Instance, value ilos.Instance, _ ilos.Class) bool { - return false -} - func (i GeneralVector) String() string { return pp.Sprint([]ilos.Instance(i)) } @@ -78,14 +62,6 @@ func (String) Class() ilos.Class { return StringClass } -func (i String) GetSlotValue(key ilos.Instance, _ ilos.Class) (ilos.Instance, bool) { - return nil, false -} - -func (i String) SetSlotValue(key ilos.Instance, value ilos.Instance, _ ilos.Class) bool { - return false -} - func (i String) String() string { return "\"" + string(i) + "\"" } diff --git a/runtime/ilos/instance/built-in-class.go b/runtime/ilos/instance/built-in-class.go index 08d15de..d4e8882 100644 --- a/runtime/ilos/instance/built-in-class.go +++ b/runtime/ilos/instance/built-in-class.go @@ -33,25 +33,17 @@ func (p BuiltInClass) Slots() []ilos.Instance { } func (p BuiltInClass) Initform(arg ilos.Instance) (ilos.Instance, bool) { - return arg, true + return nil, true } func (p BuiltInClass) Initarg(arg ilos.Instance) (ilos.Instance, bool) { - return nil, false + return arg, true } func (BuiltInClass) Class() ilos.Class { return BuiltInClassClass } -func (p BuiltInClass) GetSlotValue(key ilos.Instance, _ ilos.Class) (ilos.Instance, bool) { - return nil, false -} - -func (p BuiltInClass) SetSlotValue(key ilos.Instance, value ilos.Instance, _ ilos.Class) bool { - return false -} - func (p BuiltInClass) String() string { return fmt.Sprint(p.name) } diff --git a/runtime/ilos/instance/character.go b/runtime/ilos/instance/character.go index 5d79399..5be552b 100644 --- a/runtime/ilos/instance/character.go +++ b/runtime/ilos/instance/character.go @@ -22,14 +22,6 @@ func (Character) Class() ilos.Class { return CharacterClass } -func (i Character) GetSlotValue(key ilos.Instance, _ ilos.Class) (ilos.Instance, bool) { - return nil, false -} - -func (i Character) SetSlotValue(key ilos.Instance, value ilos.Instance, _ ilos.Class) bool { - return false -} - func (i Character) String() string { return string(i) } diff --git a/runtime/ilos/instance/function.go b/runtime/ilos/instance/function.go index ffa3f5c..fc2e4ae 100644 --- a/runtime/ilos/instance/function.go +++ b/runtime/ilos/instance/function.go @@ -30,14 +30,6 @@ func (Function) Class() ilos.Class { return FunctionClass } -func (Function) GetSlotValue(_ ilos.Instance, _ ilos.Class) (ilos.Instance, bool) { - return nil, false -} - -func (Function) SetSlotValue(_, _ ilos.Instance, _ ilos.Class) bool { - return false -} - func (f Function) String() string { return fmt.Sprintf("#%v", f.Class()) } @@ -88,9 +80,9 @@ func (f *GenericFunction) AddMethod(qualifier, lambdaList ilos.Instance, classLi } } } - for _, method := range f.methods { - if method.qualifier == qualifier { - method.function = function.(Function) + for i := range f.methods { + if f.methods[i].qualifier == qualifier && reflect.DeepEqual(f.methods[i].classList, classList) { + f.methods[i].function = function.(Function) return true } } @@ -102,14 +94,6 @@ func (f *GenericFunction) Class() ilos.Class { return f.genericFunctionClass } -func (f *GenericFunction) GetSlotValue(_ ilos.Instance, _ ilos.Class) (ilos.Instance, bool) { - return nil, false -} - -func (f *GenericFunction) SetSlotValue(_, _ ilos.Instance, _ ilos.Class) bool { - return false -} - func (f *GenericFunction) String() string { return fmt.Sprintf("#%v", f.Class()) } diff --git a/runtime/ilos/instance/instance.go b/runtime/ilos/instance/instance.go index cb2ae5b..9b25528 100644 --- a/runtime/ilos/instance/instance.go +++ b/runtime/ilos/instance/instance.go @@ -50,14 +50,15 @@ func InitializeObject(local, global environment.Environment, object ilos.Instanc argName := inits[i] argValue := inits[i+1] if slotName, ok := object.Class().Initarg(argName); ok { - object.SetSlotValue(slotName, argValue, object.Class()) + object.(Instance).SetSlotValue(slotName, argValue, object.Class()) } } for _, slotName := range object.Class().Slots() { - if _, ok := object.GetSlotValue(slotName, object.Class()); !ok { - form, _ := object.Class().Initform(slotName) - value, _ := form.(Applicable).Apply(local, global) - object.SetSlotValue(slotName, value, object.Class()) + if _, ok := object.(Instance).GetSlotValue(slotName, object.Class()); !ok { + if form, ok := object.Class().Initform(slotName); ok { + value, _ := form.(Applicable).Apply(local, global) + object.(Instance).SetSlotValue(slotName, value, object.Class()) + } } } return object, nil @@ -78,7 +79,7 @@ func (i Instance) GetSlotValue(key ilos.Instance, class ilos.Class) (ilos.Instan return v, ok } for _, s := range i.supers { - if v, ok := s.GetSlotValue(key, class); ok { + if v, ok := s.(Instance).GetSlotValue(key, class); ok { return v, ok } } @@ -91,7 +92,7 @@ func (i Instance) SetSlotValue(key ilos.Instance, value ilos.Instance, class ilo return true } for _, s := range i.supers { - if ok := s.SetSlotValue(key, value, class); ok { + if ok := s.(Instance).SetSlotValue(key, value, class); ok { return ok } } diff --git a/runtime/ilos/instance/list.go b/runtime/ilos/instance/list.go index ef2c4a2..b1a8fa5 100644 --- a/runtime/ilos/instance/list.go +++ b/runtime/ilos/instance/list.go @@ -35,32 +35,6 @@ func (*Cons) Class() ilos.Class { return ConsClass } -func (i *Cons) GetSlotValue(key ilos.Instance, _ ilos.Class) (ilos.Instance, bool) { - if symbol, ok := key.(Symbol); ok { - switch symbol { - case "CAR": - return i.Car, true - case "CDR": - return i.Cdr, true - } - } - return nil, false -} - -func (i *Cons) SetSlotValue(key ilos.Instance, value ilos.Instance, _ ilos.Class) bool { - if symbol, ok := key.(Symbol); ok { - switch symbol { - case "CAR": - i.Car = value - return true - case "CDR": - i.Cdr = value - return true - } - } - return false -} - func (i *Cons) String() string { str := "(" + fmt.Sprint(i.Car) cdr := i.Cdr @@ -127,14 +101,6 @@ func (*Null) Class() ilos.Class { return NullClass } -func (i *Null) GetSlotValue(key ilos.Instance, _ ilos.Class) (ilos.Instance, bool) { - return nil, false -} - -func (i *Null) SetSlotValue(key ilos.Instance, value ilos.Instance, _ ilos.Class) bool { - return false -} - func (*Null) String() string { return "NIL" } diff --git a/runtime/ilos/instance/number.go b/runtime/ilos/instance/number.go index fe5d450..2c12429 100644 --- a/runtime/ilos/instance/number.go +++ b/runtime/ilos/instance/number.go @@ -23,14 +23,6 @@ func (Integer) Class() ilos.Class { return IntegerClass } -func (i Integer) GetSlotValue(key ilos.Instance, _ ilos.Class) (ilos.Instance, bool) { - return nil, false -} - -func (i Integer) SetSlotValue(key ilos.Instance, value ilos.Instance, _ ilos.Class) bool { - return false -} - func (i Integer) String() string { return fmt.Sprint(int(i)) } @@ -49,14 +41,6 @@ func (Float) Class() ilos.Class { return FloatClass } -func (i Float) GetSlotValue(key ilos.Instance, _ ilos.Class) (ilos.Instance, bool) { - return nil, false -} - -func (i Float) SetSlotValue(key ilos.Instance, value ilos.Instance, _ ilos.Class) bool { - return false -} - func (i Float) String() string { return fmt.Sprint(float64(i)) } diff --git a/runtime/ilos/instance/standard-class.go b/runtime/ilos/instance/standard-class.go index 425d4c8..28bc761 100644 --- a/runtime/ilos/instance/standard-class.go +++ b/runtime/ilos/instance/standard-class.go @@ -46,14 +46,6 @@ func (p StandardClass) Class() ilos.Class { return p.metaclass } -func (p StandardClass) GetSlotValue(key ilos.Instance, _ ilos.Class) (ilos.Instance, bool) { - return nil, false -} - -func (p StandardClass) SetSlotValue(key ilos.Instance, value ilos.Instance, _ ilos.Class) bool { - return false -} - func (p StandardClass) String() string { return fmt.Sprint(p.name) } diff --git a/runtime/ilos/instance/symbol.go b/runtime/ilos/instance/symbol.go index e006edf..242dac7 100644 --- a/runtime/ilos/instance/symbol.go +++ b/runtime/ilos/instance/symbol.go @@ -22,14 +22,6 @@ func (Symbol) Class() ilos.Class { return SymbolClass } -func (i Symbol) GetSlotValue(key ilos.Instance, _ ilos.Class) (ilos.Instance, bool) { - return nil, false -} - -func (i Symbol) SetSlotValue(key ilos.Instance, value ilos.Instance, _ ilos.Class) bool { - return false -} - func (i Symbol) String() string { return string(i) } diff --git a/runtime/non-local_exits.go b/runtime/non-local_exits.go index ce97962..2d429d4 100644 --- a/runtime/non-local_exits.go +++ b/runtime/non-local_exits.go @@ -56,9 +56,9 @@ func Block(local, global environment.Environment, tag ilos.Instance, body ...ilo sucess, fail = Eval(local, global, cadr) if fail != nil { if ilos.InstanceOf(class.BlockTag, fail) { - tag1, _ := fail.GetSlotValue(instance.NewSymbol("TAG"), class.Escape) // Checked at the head of// This condition + tag1, _ := fail.(instance.Instance).GetSlotValue(instance.NewSymbol("TAG"), class.Escape) // Checked at the head of// This condition if tag == tag1 { - obj, _ := fail.GetSlotValue(instance.NewSymbol("OBJECT"), class.BlockTag) // Checked at the head of// This condition + obj, _ := fail.(instance.Instance).GetSlotValue(instance.NewSymbol("OBJECT"), class.BlockTag) // Checked at the head of// This condition return obj, nil } } @@ -105,9 +105,9 @@ func Catch(local, global environment.Environment, tag ilos.Instance, body ...ilo sucess, fail = Eval(local, global, cadr) if fail != nil { if ilos.InstanceOf(class.CatchTag, fail) { - tag1, _ := fail.GetSlotValue(instance.NewSymbol("TAG"), class.Escape) // Checked at the head of// This condition + tag1, _ := fail.(instance.Instance).GetSlotValue(instance.NewSymbol("TAG"), class.Escape) // Checked at the head of// This condition if tag == tag1 { - obj, _ := fail.GetSlotValue(instance.NewSymbol("OBJECT"), class.CatchTag) // Checked at the head of// This condition + obj, _ := fail.(instance.Instance).GetSlotValue(instance.NewSymbol("OBJECT"), class.CatchTag) // Checked at the head of// This condition return obj, nil } } @@ -152,7 +152,7 @@ func Tagbody(local, global environment.Environment, body ...ilos.Instance) (ilos if fail != nil { TAG: if ilos.InstanceOf(class.TagbodyTag, fail) { - tag, _ := fail.GetSlotValue(instance.NewSymbol("TAG"), class.Escape) // Checked at the top of// This loop + tag, _ := fail.(instance.Instance).GetSlotValue(instance.NewSymbol("TAG"), class.Escape) // Checked at the top of// This loop found := false for _, tag1 := range body { if tag == tag1 { From 0f18c2e80ffbb34a1ae139045f687efd283d4fb0 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Mon, 21 Aug 2017 17:58:57 +0900 Subject: [PATCH 202/228] Delete newInstance function --- runtime/defining_classes.go | 4 +- runtime/ilos/instance/built-in-class.go | 2 +- runtime/ilos/instance/error.go | 80 ++++++++++++------------- runtime/ilos/instance/instance.go | 33 ++++------ runtime/ilos/instance/tag.go | 21 ++++--- 5 files changed, 61 insertions(+), 79 deletions(-) diff --git a/runtime/defining_classes.go b/runtime/defining_classes.go index abad011..41a843e 100644 --- a/runtime/defining_classes.go +++ b/runtime/defining_classes.go @@ -184,12 +184,12 @@ func Create(local, global environment.Environment, c ilos.Instance, i ...ilos.In if err := ensure(class.StandardClass, c); err != nil { return nil, err } - return instance.Create(local, global, c, i...) + return instance.Create(local, global, c, i...), nil } func InitializeObject(local, global environment.Environment, object ilos.Instance, inits ...ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.StandardObject, object); err != nil { return nil, err } - return instance.InitializeObject(local, global, object, inits...) + return instance.InitializeObject(local, global, object, inits...), nil } diff --git a/runtime/ilos/instance/built-in-class.go b/runtime/ilos/instance/built-in-class.go index d4e8882..6d45dd6 100644 --- a/runtime/ilos/instance/built-in-class.go +++ b/runtime/ilos/instance/built-in-class.go @@ -33,7 +33,7 @@ func (p BuiltInClass) Slots() []ilos.Instance { } func (p BuiltInClass) Initform(arg ilos.Instance) (ilos.Instance, bool) { - return nil, true + return nil, false } func (p BuiltInClass) Initarg(arg ilos.Instance) (ilos.Instance, bool) { diff --git a/runtime/ilos/instance/error.go b/runtime/ilos/instance/error.go index 321bd68..30bfb24 100644 --- a/runtime/ilos/instance/error.go +++ b/runtime/ilos/instance/error.go @@ -9,7 +9,7 @@ import ( "runtime" "strings" - "github.com/k0kubun/pp" + "github.com/ta2gch/iris/runtime/environment" "github.com/ta2gch/iris/runtime/ilos" ) @@ -35,78 +35,74 @@ func stackTrace() { } func NewArithmeticError(operation, operands ilos.Instance) ilos.Instance { - return newInstance(ArithmeticErrorClass, map[ilos.Instance]ilos.Instance{ - NewSymbol("OPERATION"): operation, - NewSymbol("OPERANDS"): operands, - }) + return Create(environment.New(), environment.New(), + ArithmeticErrorClass, + NewSymbol("OPERATION"), operation, + NewSymbol("OPERANDS"), operands) } func NewDivisionByZero(operation, operands ilos.Instance) ilos.Instance { - return newInstance(DivisionByZeroClass, map[ilos.Instance]ilos.Instance{ - NewSymbol("OPERATION"): operation, - NewSymbol("OPERANDS"): operands, - }) + return Create(environment.New(), environment.New(), + DivisionByZeroClass, + NewSymbol("OPERATION"), operation, + NewSymbol("OPERANDS"), operands) } func NewParseError(str, expectedClass ilos.Instance) ilos.Instance { - return newInstance(ParseErrorClass, map[ilos.Instance]ilos.Instance{ - NewSymbol("STRING"): str, - NewSymbol("EXPECTED-CLASS"): expectedClass, - }) + return Create(environment.New(), environment.New(), + ParseErrorClass, + NewSymbol("STRING"), str, + NewSymbol("EXPECTED-CLASS"), expectedClass) } func NewDomainError(object ilos.Instance, expectedClass ilos.Class) ilos.Instance { - pp.Println(object, expectedClass) - return newInstance(DomainErrorClass, map[ilos.Instance]ilos.Instance{ - NewSymbol("CAUSE"): NewSymbol("DOMAIN-ERROR"), - NewSymbol("OBJECT"): object, - NewSymbol("EXPECTED-CLASS"): expectedClass, - }) + return Create(environment.New(), environment.New(), + DomainErrorClass, + NewSymbol("CAUSE"), NewSymbol("DOMAIN-ERROR"), + NewSymbol("OBJECT"), object, + NewSymbol("EXPECTED-CLASS"), expectedClass) } func NewUndefinedFunction(name ilos.Instance) ilos.Instance { - return newInstance(UndefinedFunctionClass, map[ilos.Instance]ilos.Instance{ - NewSymbol("NAME"): name, - NewSymbol("NAMESPACE"): NewSymbol("FUNCTION"), - }) + return Create(environment.New(), environment.New(), + UndefinedFunctionClass, + NewSymbol("NAME"), name, + NewSymbol("NAMESPACE"), NewSymbol("FUNCTION")) } func NewUndefinedVariable(name ilos.Instance) ilos.Instance { - return newInstance(UndefinedVariableClass, map[ilos.Instance]ilos.Instance{ - NewSymbol("NAME"): name, - NewSymbol("NAMESPACE"): NewSymbol("VARIABLE"), - }) + return Create(environment.New(), environment.New(), + UndefinedVariableClass, + NewSymbol("NAME"), name, + NewSymbol("NAMESPACE"), NewSymbol("VARIABLE")) } func NewUndefinedClass(name ilos.Instance) ilos.Instance { - return newInstance(UndefinedVariableClass, map[ilos.Instance]ilos.Instance{ - NewSymbol("NAME"): name, - NewSymbol("NAMESPACE"): NewSymbol("CLASS"), - }) + return Create(environment.New(), environment.New(), + UndefinedEntityClass, + NewSymbol("NAME"), name, + NewSymbol("NAMESPACE"), NewSymbol("CLASS")) } func NewArityError() ilos.Instance { - //stackTrace() - return newInstance(ProgramErrorClass, map[ilos.Instance]ilos.Instance{}) + return Create(environment.New(), environment.New(), ProgramErrorClass) } func NewIndexOutOfRange() ilos.Instance { - //stackTrace() - return newInstance(ProgramErrorClass, map[ilos.Instance]ilos.Instance{}) + return Create(environment.New(), environment.New(), ProgramErrorClass) } func NewImmutableBinding() ilos.Instance { - //stackTrace() - return newInstance(ProgramErrorClass, map[ilos.Instance]ilos.Instance{}) + return Create(environment.New(), environment.New(), ProgramErrorClass) } func NewSimpleError(formatString, formatArguments ilos.Instance) ilos.Instance { - return newInstance(SimpleErrorClass, map[ilos.Instance]ilos.Instance{ - NewSymbol("FORMAT-STRING"): formatString, - NewSymbol("FORMAT-ARGUMENTS"): formatArguments, - }) + return Create(environment.New(), environment.New(), + SimpleErrorClass, + NewSymbol("FORMAT-STRING"), formatString, + NewSymbol("FORMAT-ARGUMENTS"), formatArguments) } func NewControlError() ilos.Instance { - return newInstance(ControlErrorClass) + return Create(environment.New(), environment.New(), ControlErrorClass) } diff --git a/runtime/ilos/instance/instance.go b/runtime/ilos/instance/instance.go index 9b25528..fab2132 100644 --- a/runtime/ilos/instance/instance.go +++ b/runtime/ilos/instance/instance.go @@ -16,33 +16,15 @@ import ( // instance // -func newInstance(c ilos.Class, s ...interface{}) ilos.Instance { - p := []ilos.Instance{} - for _, q := range c.Supers() { - p = append(p, newInstance(q, s...)) - } - t := map[ilos.Instance]ilos.Instance{} - for argName, argValue := range s[0].(map[ilos.Instance]ilos.Instance) { - if slotName, ok := c.Initarg(argName); ok { - t[slotName] = argValue - } - } - return Instance{c, p, t} -} - -func Create(local, global environment.Environment, c ilos.Instance, i ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Create(local, global environment.Environment, c ilos.Instance, i ...ilos.Instance) ilos.Instance { p := []ilos.Instance{} for _, q := range c.(ilos.Class).Supers() { - s, err := Create(local, global, q, i...) - if err != nil { - return nil, err - } - p = append(p, s) + p = append(p, Create(local, global, q, i...)) } return InitializeObject(local, global, Instance{c.(ilos.Class), p, map[ilos.Instance]ilos.Instance{}}, i...) } -func InitializeObject(local, global environment.Environment, object ilos.Instance, inits ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func InitializeObject(local, global environment.Environment, object ilos.Instance, inits ...ilos.Instance) ilos.Instance { for _, super := range object.(Instance).supers { InitializeObject(local, global, super, inits...) } @@ -50,7 +32,12 @@ func InitializeObject(local, global environment.Environment, object ilos.Instanc argName := inits[i] argValue := inits[i+1] if slotName, ok := object.Class().Initarg(argName); ok { - object.(Instance).SetSlotValue(slotName, argValue, object.Class()) + for _, s := range object.Class().Slots() { + if slotName == s { + object.(Instance).SetSlotValue(slotName, argValue, object.Class()) + break + } + } } } for _, slotName := range object.Class().Slots() { @@ -61,7 +48,7 @@ func InitializeObject(local, global environment.Environment, object ilos.Instanc } } } - return object, nil + return object } type Instance struct { diff --git a/runtime/ilos/instance/tag.go b/runtime/ilos/instance/tag.go index a3d7d67..36c5d64 100644 --- a/runtime/ilos/instance/tag.go +++ b/runtime/ilos/instance/tag.go @@ -5,23 +5,22 @@ package instance import ( + "github.com/ta2gch/iris/runtime/environment" "github.com/ta2gch/iris/runtime/ilos" ) func NewBlockTag(tag, object ilos.Instance) ilos.Instance { - return newInstance(BlockTagClass, map[ilos.Instance]ilos.Instance{ - NewSymbol("TAG"): tag, - NewSymbol("OBJECT"): object, - }) + return Create(environment.New(), environment.New(), + BlockTagClass, + NewSymbol("TAG"), tag, + NewSymbol("OBJECT"), object) } func NewCatchTag(tag, object ilos.Instance) ilos.Instance { - return newInstance(CatchTagClass, map[ilos.Instance]ilos.Instance{ - NewSymbol("TAG"): tag, - NewSymbol("OBJECT"): object, - }) + return Create(environment.New(), environment.New(), + CatchTagClass, + NewSymbol("TAG"), tag, + NewSymbol("OBJECT"), object) } func NewTagbodyTag(tag ilos.Instance) ilos.Instance { - return newInstance(TagbodyTagClass, map[ilos.Instance]ilos.Instance{ - NewSymbol("TAG"): tag, - }) + return Create(environment.New(), environment.New(), TagbodyTagClass, NewSymbol("TAG"), tag) } From 6469f9cdc883019c2447bbba7dc9828ce47cdb51 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Mon, 21 Aug 2017 20:47:51 +0900 Subject: [PATCH 203/228] Added Setf --- runtime/variable_test.go | 22 ++++++++++++++++++++++ runtime/variables.go | 22 +++++++++++++++++++++- 2 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 runtime/variable_test.go diff --git a/runtime/variable_test.go b/runtime/variable_test.go new file mode 100644 index 0000000..a1ad6eb --- /dev/null +++ b/runtime/variable_test.go @@ -0,0 +1,22 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package runtime + +import "testing" + +func TestSetf(t *testing.T) { + defun2("(SETF CAR)", SetCar) + defspecial(Setf) + defspecial(Let) + defspecial(Quote) + tests := []test{ + { + exp: `(let ((c '(1 2))) (setf (car c) 3) c)`, + want: `'(3 2)`, + wantErr: false, + }, + } + execTests(t, Setf, tests) +} diff --git a/runtime/variables.go b/runtime/variables.go index 51d2c57..a509dfa 100644 --- a/runtime/variables.go +++ b/runtime/variables.go @@ -5,6 +5,8 @@ package runtime import ( + "fmt" + "github.com/ta2gch/iris/runtime/environment" "github.com/ta2gch/iris/runtime/ilos" "github.com/ta2gch/iris/runtime/ilos/class" @@ -33,7 +35,25 @@ func Setq(local, global environment.Environment, var1, form ilos.Instance) (ilos return nil, instance.NewUndefinedVariable(var1) } -// TODO: Setf +func Setf(local, global environment.Environment, var1, form ilos.Instance) (ilos.Instance, ilos.Instance) { + if ilos.InstanceOf(class.Symbol, var1) { + val, err := Eval(local, global, form) + if err != nil { + return nil, err + } + return Setq(local, global, var1, val) + } + funcSpec := instance.NewSymbol(fmt.Sprintf("(SETF %v)", var1.(instance.List).Nth(0))) + fun, ok := global.Function.Get(funcSpec) + if !ok { + return nil, instance.NewUndefinedFunction(funcSpec) + } + arguments, err := evalArguments(local, global, instance.NewCons(form, var1.(*instance.Cons).Cdr)) + if err != nil { + return nil, err + } + return fun.(instance.Applicable).Apply(local, global, arguments.(instance.List).Slice()...) +} // Let is used to define a scope for a group of identifiers // for a sequence of forms body-form* (collectively referred to as the body). From c935cb515f8830b9cd89d54c18d1544399c3e221 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Tue, 22 Aug 2017 07:19:04 +0900 Subject: [PATCH 204/228] Delete TODOs --- reader/parser/array.go | 1 - runtime/array_operations.go | 2 +- runtime/cons.go | 4 ---- runtime/dynamic_variables.go | 2 -- runtime/symbol_class.go | 2 -- 5 files changed, 1 insertion(+), 10 deletions(-) diff --git a/reader/parser/array.go b/reader/parser/array.go index 013f777..d706392 100644 --- a/reader/parser/array.go +++ b/reader/parser/array.go @@ -10,7 +10,6 @@ import ( ) func list2array(dim int, list ilos.Instance) (ilos.Instance, ilos.Instance) { - // TODO: check array correctly ( #2((a) ()) ) if dim == 0 { return instance.NewGeneralArrayStar(nil, list), nil } diff --git a/runtime/array_operations.go b/runtime/array_operations.go index 88617ac..e3e6ee5 100644 --- a/runtime/array_operations.go +++ b/runtime/array_operations.go @@ -72,7 +72,7 @@ func CreateArray(local, global environment.Environment, dimensions ilos.Instance } array := make([]instance.GeneralArrayStar, int(dim[0].(instance.Integer))) for i := range array { - d, err := List(local, global, dim[1:]...) // TODO: replace UnsafeCdr + d, err := List(local, global, dim[1:]...) if err != nil { return nil, err } diff --git a/runtime/cons.go b/runtime/cons.go index 560fe3a..c067353 100644 --- a/runtime/cons.go +++ b/runtime/cons.go @@ -47,8 +47,6 @@ func Cdr(local, global environment.Environment, cons ilos.Instance) (ilos.Instan return cons.(*instance.Cons).Cdr, nil // Checked at the top of this function } -// TODO: setf car - // SetCar updates the left component of cons with obj. The returned value is obj . // An error shall be signaled if cons is not a cons (error-id. domain-error). // obj may be any ISLISP object. @@ -60,8 +58,6 @@ func SetCar(local, global environment.Environment, obj, cons ilos.Instance) (ilo return obj, nil } -// TODO: setf cdr - // SetCdr updates the right component of cons with obj. The returned value is obj . // An error shall be signaled if cons is not a cons (error-id. domain-error). // obj may be any ISLISP object. diff --git a/runtime/dynamic_variables.go b/runtime/dynamic_variables.go index 59e2ea5..c51aada 100644 --- a/runtime/dynamic_variables.go +++ b/runtime/dynamic_variables.go @@ -11,8 +11,6 @@ import ( "github.com/ta2gch/iris/runtime/ilos/instance" ) -// TODO: setf dynamic - // Dynamic denotes a reference to the identifier denoting a // dynamic variable. This special form is not allowed in the scope of a // definition of var which is not done by defdynamic or dynamic-let. diff --git a/runtime/symbol_class.go b/runtime/symbol_class.go index 27626df..e408812 100644 --- a/runtime/symbol_class.go +++ b/runtime/symbol_class.go @@ -13,8 +13,6 @@ import ( "github.com/ta2gch/iris/runtime/ilos/instance" ) -// TODO: setf property - // Symbolp returns t if obj is a symbol (instance of class symbol); // otherwise, returns nil. The obj may be any ISLISP object. func Symbolp(local, global environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { From f5e0a09db65c4fb2dce708500522750247534907 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Tue, 22 Aug 2017 23:37:21 +0900 Subject: [PATCH 205/228] Added stream --- runtime/class.go | 36 +++ runtime/condition_system.go | 85 ++++++ runtime/defining_classes.go | 7 - runtime/environment/environment.go | 62 +++-- runtime/environment/{mmap.go => map2.go} | 12 +- runtime/environment/stack.go | 2 +- runtime/eval.go | 14 +- runtime/functions.go | 2 +- runtime/ilos/instance/error.go | 26 +- runtime/ilos/instance/stream.go | 28 ++ runtime/ilos/instance/tag.go | 7 +- runtime/stream.go | 321 +++++++++++++++++++++++ runtime/test.go | 6 +- runtime/util.go | 40 ++- 14 files changed, 571 insertions(+), 77 deletions(-) create mode 100644 runtime/class.go create mode 100644 runtime/condition_system.go rename runtime/environment/{mmap.go => map2.go} (65%) create mode 100644 runtime/ilos/instance/stream.go create mode 100644 runtime/stream.go diff --git a/runtime/class.go b/runtime/class.go new file mode 100644 index 0000000..3221dbe --- /dev/null +++ b/runtime/class.go @@ -0,0 +1,36 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package runtime + +import ( + "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/ilos" + "github.com/ta2gch/iris/runtime/ilos/instance" +) + +func ClassOf(local, global environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { + return obj.Class(), nil +} + +func Instancep(local, global environment.Environment, obj ilos.Instance, class ilos.Class) (ilos.Instance, ilos.Instance) { + if ilos.InstanceOf(class, obj) { + return T, nil + } + return Nil, nil +} + +func Subclassp(local, global environment.Environment, class1, class2 ilos.Class) (ilos.Instance, ilos.Instance) { + if ilos.SubclassOf(class1, class2) { + return T, nil + } + return Nil, nil +} + +func Class(local, global environment.Environment, className ilos.Instance) (ilos.Class, ilos.Instance) { + if v, ok := global.Class.Get(className); ok { + return v.(ilos.Class), nil + } + return nil, instance.NewUndefinedClass(className) +} diff --git a/runtime/condition_system.go b/runtime/condition_system.go new file mode 100644 index 0000000..504b54f --- /dev/null +++ b/runtime/condition_system.go @@ -0,0 +1,85 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package runtime + +import ( + "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/ilos" + "github.com/ta2gch/iris/runtime/ilos/class" + "github.com/ta2gch/iris/runtime/ilos/instance" +) + +func SignalCondition(local, global environment.Environment, condition, continuable ilos.Instance) (ilos.Instance, ilos.Instance) { + if err := ensure(class.SeriousCondition, condition); err != nil { + return nil, err + } + condition.(instance.Instance).SetSlotValue(instance.NewSymbol("IRIS.CONTINUABLE"), continuable, class.SeriousCondition) + return nil, condition +} + +func Cerror(local, global environment.Environment, continueString, errorString ilos.Instance, objs ...ilos.Instance) (ilos.Instance, ilos.Instance) { + arguments, err := List(local, global, objs...) + if err != nil { + return nil, err + } + condition := instance.Create(local, global, class.SimpleError, instance.NewSymbol("FORMAT-STRING"), errorString, instance.NewSymbol("FORAMT-OBJECTS"), arguments) + ss, err := CreateStringOutputStream(local, global) + if err != nil { + return nil, err + } + if _, err := Format(local, global, ss, continueString, objs...); err != nil { + return nil, err + } + continuable, err := GetOutputStreamString(local, global, ss) + if err != nil { + return nil, err + } + return SignalCondition(local, global, condition, continuable) +} + +func Error(local, global environment.Environment, continueString, errorString ilos.Instance, objs ...ilos.Instance) (ilos.Instance, ilos.Instance) { + arguments, err := List(local, global, objs...) + if err != nil { + return nil, err + } + condition := instance.Create(local, global, class.SimpleError, instance.NewSymbol("FORMAT-STRING"), errorString, instance.NewSymbol("FORAMT-OBJECTS"), arguments) + return SignalCondition(local, global, condition, Nil) +} + +func IgnoreError(local, global environment.Environment, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { + ret, err := Progn(local, global, forms...) + if err != nil && ilos.InstanceOf(class.Error, err) { + return Nil, nil + } + return ret, err +} + +func ReportCondition(local, global environment.Environment, condition, stream ilos.Instance) (ilos.Instance, ilos.Instance) { + return nil, nil +} + +func ConditionContinuable(local, global environment.Environment, condition ilos.Instance) (ilos.Instance, ilos.Instance) { + if continuable, ok := condition.(instance.Instance).GetSlotValue(instance.NewSymbol("IRIS.CONTINUABLE"), class.SeriousCondition); ok { + return continuable, nil + } + return Nil, nil +} + +func ContinueCondition(local, global environment.Environment, condition, value ilos.Instance) (ilos.Instance, ilos.Instance) { + // TODO: + return nil, nil +} + +func WithHandler(local, global environment.Environment, handler ilos.Instance, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { + fun, err := Eval(local, global, handler) + if err != nil { + return nil, err + } + ret, err := Progn(local, global, forms...) + if err != nil { + return fun.(instance.Applicable).Apply(local, global, err) + } + return ret, err +} diff --git a/runtime/defining_classes.go b/runtime/defining_classes.go index 41a843e..18b3306 100644 --- a/runtime/defining_classes.go +++ b/runtime/defining_classes.go @@ -15,13 +15,6 @@ import ( "github.com/ta2gch/iris/runtime/ilos/instance" ) -func Class(local, global environment.Environment, className ilos.Instance) (ilos.Class, ilos.Instance) { - if v, ok := global.Class.Get(className); ok { - return v.(ilos.Class), nil - } - return nil, instance.NewUndefinedClass(className) -} - func checkSuperClass(a, b ilos.Class) bool { if reflect.DeepEqual(a, class.StandardObject) || reflect.DeepEqual(b, class.StandardObject) { return false diff --git a/runtime/environment/environment.go b/runtime/environment/environment.go index f902526..c2ee980 100644 --- a/runtime/environment/environment.go +++ b/runtime/environment/environment.go @@ -4,38 +4,32 @@ package environment +import ( + "github.com/ta2gch/iris/runtime/ilos" +) + // Environment struct is the struct for keeping functions and variables type Environment struct { - Class stack - BlockTag stack - TagbodyTag stack + // Lexical + BlockTag stack + TagbodyTag stack + Function stack + Variable stack + + // Global + Class stack + Macro stack + Special stack + Property map2 + GensymID int + Constant stack + + // Dynamic CatchTag stack - Macro stack - Function stack - Special stack - Variable stack DynamicVariable stack // deep biding - Constant stack - GensymID int - Property mmap -} - -// New creates new environment -func New() Environment { - env := new(Environment) - env.Class = newStack() - env.BlockTag = newStack() - env.TagbodyTag = newStack() - env.CatchTag = newStack() - env.Macro = newStack() - env.Function = newStack() - env.Special = newStack() - env.Variable = newStack() - env.DynamicVariable = newStack() - env.Constant = newStack() - env.GensymID = 0 // Will Not Worked - env.Property = mmap{} - return *env + StandardInput ilos.Instance + StandardOutput ilos.Instance + ErrorOutput ilos.Instance } func (env *Environment) Merge(before Environment) { @@ -51,12 +45,16 @@ func (env *Environment) Merge(before Environment) { env.Constant = append(before.Constant, env.Constant...) env.GensymID = before.GensymID env.Property = before.Property + env.StandardInput = before.StandardInput + env.StandardOutput = before.StandardOutput + env.ErrorOutput = before.ErrorOutput + } -func (env *Environment) PartialMerge(before Environment) { +func (env *Environment) MergeDynamic(before Environment) { env.CatchTag = append(before.CatchTag, env.CatchTag...) env.DynamicVariable = append(before.DynamicVariable, env.DynamicVariable...) + env.StandardInput = before.StandardInput + env.StandardOutput = before.StandardOutput + env.ErrorOutput = before.ErrorOutput } - -// TopLevel is a global environment -var TopLevel = New() diff --git a/runtime/environment/mmap.go b/runtime/environment/map2.go similarity index 65% rename from runtime/environment/mmap.go rename to runtime/environment/map2.go index de83b43..4d5fcb0 100644 --- a/runtime/environment/mmap.go +++ b/runtime/environment/map2.go @@ -8,19 +8,23 @@ import ( "github.com/ta2gch/iris/runtime/ilos" ) -type mmap map[[2]ilos.Instance]ilos.Instance +type map2 map[[2]ilos.Instance]ilos.Instance -func (s mmap) Get(key1, key2 ilos.Instance) (ilos.Instance, bool) { +func NewMap2() map2 { + return map[[2]ilos.Instance]ilos.Instance{} +} + +func (s map2) Get(key1, key2 ilos.Instance) (ilos.Instance, bool) { if v, ok := s[[2]ilos.Instance{key1, key2}]; ok { return v, true } return nil, false } -func (s mmap) Set(key1, key2, value ilos.Instance) { +func (s map2) Set(key1, key2, value ilos.Instance) { s[[2]ilos.Instance{key1, key2}] = value } -func (s mmap) Delete(key1, key2 ilos.Instance) (ilos.Instance, bool) { +func (s map2) Delete(key1, key2 ilos.Instance) (ilos.Instance, bool) { if v, ok := s[[2]ilos.Instance{key1, key2}]; ok { delete(s, [2]ilos.Instance{key1, key2}) return v, true diff --git a/runtime/environment/stack.go b/runtime/environment/stack.go index ff3c6b5..9b72e46 100644 --- a/runtime/environment/stack.go +++ b/runtime/environment/stack.go @@ -10,7 +10,7 @@ import ( type stack []map[ilos.Instance]ilos.Instance -func newStack() stack { +func NewStack() stack { return []map[ilos.Instance]ilos.Instance{map[ilos.Instance]ilos.Instance{}} } diff --git a/runtime/eval.go b/runtime/eval.go index c1fc640..36a6be8 100644 --- a/runtime/eval.go +++ b/runtime/eval.go @@ -48,8 +48,8 @@ func evalLambda(local, global environment.Environment, car, cdr ilos.Instance) ( if err != nil { return nil, err, true } - env := environment.New() - env.PartialMerge(local) + env := NewEnvironment() + env.MergeDynamic(local) ret, err := fun.(instance.Applicable).Apply(env, global, arguments.(instance.List).Slice()...) if err != nil { return nil, err, true @@ -67,7 +67,7 @@ func evalSpecial(local, global environment.Environment, car, cdr ilos.Instance) spl = s } if spl != nil { - env := environment.New() + env := NewEnvironment() env.Merge(local) ret, err := spl.(instance.Applicable).Apply(env, global, cdr.(instance.List).Slice()...) if err != nil { @@ -88,8 +88,8 @@ func evalMacro(local, global environment.Environment, car, cdr ilos.Instance) (i mac = m } if mac != nil { - env := environment.New() - env.PartialMerge(local) + env := NewEnvironment() + env.MergeDynamic(local) ret, err := mac.(instance.Applicable).Apply(env, global, cdr.(instance.List).Slice()...) if err != nil { return nil, err, true @@ -113,8 +113,8 @@ func evalFunction(local, global environment.Environment, car, cdr ilos.Instance) fun = f } if fun != nil { - env := environment.New() - env.PartialMerge(local) + env := NewEnvironment() + env.MergeDynamic(local) arguments, err := evalArguments(local, global, cdr) if err != nil { return nil, err, true diff --git a/runtime/functions.go b/runtime/functions.go index c16158c..ba995ca 100644 --- a/runtime/functions.go +++ b/runtime/functions.go @@ -131,7 +131,7 @@ func Flet(local, global environment.Environment, functions ilos.Instance, bodyFo if err := ensure(class.List, functions); err != nil { return nil, err } - env := environment.New() + env := NewEnvironment() env.Merge(local) for _, function := range functions.(instance.List).Slice() { if err := ensure(class.List, function); err != nil { diff --git a/runtime/ilos/instance/error.go b/runtime/ilos/instance/error.go index 30bfb24..8080ccd 100644 --- a/runtime/ilos/instance/error.go +++ b/runtime/ilos/instance/error.go @@ -13,6 +13,8 @@ import ( "github.com/ta2gch/iris/runtime/ilos" ) +var dummyEnv = *new(environment.Environment) // All class in ilos/instance has no initform, so it will not call apply + func stackTrace() { println("----") programCounter, sourceFileName, sourceFileLineNum, ok := runtime.Caller(2) @@ -35,28 +37,28 @@ func stackTrace() { } func NewArithmeticError(operation, operands ilos.Instance) ilos.Instance { - return Create(environment.New(), environment.New(), + return Create(dummyEnv, dummyEnv, ArithmeticErrorClass, NewSymbol("OPERATION"), operation, NewSymbol("OPERANDS"), operands) } func NewDivisionByZero(operation, operands ilos.Instance) ilos.Instance { - return Create(environment.New(), environment.New(), + return Create(dummyEnv, dummyEnv, DivisionByZeroClass, NewSymbol("OPERATION"), operation, NewSymbol("OPERANDS"), operands) } func NewParseError(str, expectedClass ilos.Instance) ilos.Instance { - return Create(environment.New(), environment.New(), + return Create(dummyEnv, dummyEnv, ParseErrorClass, NewSymbol("STRING"), str, NewSymbol("EXPECTED-CLASS"), expectedClass) } func NewDomainError(object ilos.Instance, expectedClass ilos.Class) ilos.Instance { - return Create(environment.New(), environment.New(), + return Create(dummyEnv, dummyEnv, DomainErrorClass, NewSymbol("CAUSE"), NewSymbol("DOMAIN-ERROR"), NewSymbol("OBJECT"), object, @@ -64,45 +66,45 @@ func NewDomainError(object ilos.Instance, expectedClass ilos.Class) ilos.Instanc } func NewUndefinedFunction(name ilos.Instance) ilos.Instance { - return Create(environment.New(), environment.New(), + return Create(dummyEnv, dummyEnv, UndefinedFunctionClass, NewSymbol("NAME"), name, NewSymbol("NAMESPACE"), NewSymbol("FUNCTION")) } func NewUndefinedVariable(name ilos.Instance) ilos.Instance { - return Create(environment.New(), environment.New(), + return Create(dummyEnv, dummyEnv, UndefinedVariableClass, NewSymbol("NAME"), name, NewSymbol("NAMESPACE"), NewSymbol("VARIABLE")) } func NewUndefinedClass(name ilos.Instance) ilos.Instance { - return Create(environment.New(), environment.New(), + return Create(dummyEnv, dummyEnv, UndefinedEntityClass, NewSymbol("NAME"), name, NewSymbol("NAMESPACE"), NewSymbol("CLASS")) } func NewArityError() ilos.Instance { - return Create(environment.New(), environment.New(), ProgramErrorClass) + return Create(dummyEnv, dummyEnv, ProgramErrorClass) } func NewIndexOutOfRange() ilos.Instance { - return Create(environment.New(), environment.New(), ProgramErrorClass) + return Create(dummyEnv, dummyEnv, ProgramErrorClass) } func NewImmutableBinding() ilos.Instance { - return Create(environment.New(), environment.New(), ProgramErrorClass) + return Create(dummyEnv, dummyEnv, ProgramErrorClass) } func NewSimpleError(formatString, formatArguments ilos.Instance) ilos.Instance { - return Create(environment.New(), environment.New(), + return Create(dummyEnv, dummyEnv, SimpleErrorClass, NewSymbol("FORMAT-STRING"), formatString, NewSymbol("FORMAT-ARGUMENTS"), formatArguments) } func NewControlError() ilos.Instance { - return Create(environment.New(), environment.New(), ControlErrorClass) + return Create(dummyEnv, dummyEnv, ControlErrorClass) } diff --git a/runtime/ilos/instance/stream.go b/runtime/ilos/instance/stream.go new file mode 100644 index 0000000..9717b8c --- /dev/null +++ b/runtime/ilos/instance/stream.go @@ -0,0 +1,28 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package instance + +import ( + "io" + + "github.com/ta2gch/iris/runtime/ilos" +) + +type Stream struct { + Reader io.Reader + Writer io.Writer +} + +func NewStream(r io.Reader, w io.Writer) ilos.Instance { + return Stream{r, w} +} + +func (Stream) Class() ilos.Class { + return StreamClass +} + +func (Stream) String() string { + return "#" +} diff --git a/runtime/ilos/instance/tag.go b/runtime/ilos/instance/tag.go index 36c5d64..6e08ffd 100644 --- a/runtime/ilos/instance/tag.go +++ b/runtime/ilos/instance/tag.go @@ -5,22 +5,21 @@ package instance import ( - "github.com/ta2gch/iris/runtime/environment" "github.com/ta2gch/iris/runtime/ilos" ) func NewBlockTag(tag, object ilos.Instance) ilos.Instance { - return Create(environment.New(), environment.New(), + return Create(dummyEnv, dummyEnv, BlockTagClass, NewSymbol("TAG"), tag, NewSymbol("OBJECT"), object) } func NewCatchTag(tag, object ilos.Instance) ilos.Instance { - return Create(environment.New(), environment.New(), + return Create(dummyEnv, dummyEnv, CatchTagClass, NewSymbol("TAG"), tag, NewSymbol("OBJECT"), object) } func NewTagbodyTag(tag ilos.Instance) ilos.Instance { - return Create(environment.New(), environment.New(), TagbodyTagClass, NewSymbol("TAG"), tag) + return Create(dummyEnv, dummyEnv, TagbodyTagClass, NewSymbol("TAG"), tag) } diff --git a/runtime/stream.go b/runtime/stream.go new file mode 100644 index 0000000..2a6af6d --- /dev/null +++ b/runtime/stream.go @@ -0,0 +1,321 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package runtime + +import ( + "bufio" + "bytes" + "fmt" + "os" + "regexp" + "strings" + + "github.com/ta2gch/iris/reader/parser" + "github.com/ta2gch/iris/reader/tokenizer" + "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/ilos" + "github.com/ta2gch/iris/runtime/ilos/class" + "github.com/ta2gch/iris/runtime/ilos/instance" +) + +func Streamp(local, global environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { + if ilos.InstanceOf(class.Stream, obj) { + return T, nil + } + return Nil, nil +} + +func OpenStreamP(local, global environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { + return T, nil +} + +func InputStreamp(local, global environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { + if s, ok := obj.(instance.Stream); ok && s.Reader != nil { + return T, nil + } + return Nil, nil +} + +func OutputStreamp(local, global environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { + if s, ok := obj.(instance.Stream); ok && s.Writer != nil { + return T, nil + } + return Nil, nil +} + +func StandardInput(local, global environment.Environment) (ilos.Instance, ilos.Instance) { + return local.StandardInput, nil +} + +func StandardOutput(local, global environment.Environment) (ilos.Instance, ilos.Instance) { + return local.StandardOutput, nil +} + +func ErrorOutput(local, global environment.Environment) (ilos.Instance, ilos.Instance) { + return local.ErrorOutput, nil +} + +func WithStandardInput(local, global environment.Environment, streamForm ilos.Instance, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { + var err ilos.Instance + local.StandardInput, err = Eval(local, global, streamForm) + if err != nil { + return nil, err + } + if err := ensure(class.Stream, local.ErrorOutput); err != nil { + return nil, err + } + return Progn(local, global, forms...) +} + +func WithStandardOutput(local, global environment.Environment, streamForm ilos.Instance, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { + var err ilos.Instance + local.StandardOutput, err = Eval(local, global, streamForm) + if err != nil { + return nil, err + } + if err := ensure(class.Stream, local.ErrorOutput); err != nil { + return nil, err + } + return Progn(local, global, forms...) +} + +func WithErrorOutput(local, global environment.Environment, streamForm ilos.Instance, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { + var err ilos.Instance + local.ErrorOutput, err = Eval(local, global, streamForm) + if err != nil { + return nil, err + } + if err := ensure(class.Stream, local.ErrorOutput); err != nil { + return nil, err + } + return Progn(local, global, forms...) +} + +func OpenInputFile(local, global environment.Environment, filename ilos.Instance, elementClass ...ilos.Instance) (ilos.Instance, ilos.Instance) { + // TODO: elementClass + if err := ensure(class.String, filename); err != nil { + return nil, err + } + file, err := os.Open(string(filename.(instance.String))) + if err != nil { + return nil, nil // Error File Not Found + } + return instance.NewStream(file, nil), nil +} + +func OpenOutputFile(local, global environment.Environment, filename ilos.Instance, elementClass ...ilos.Instance) (ilos.Instance, ilos.Instance) { + // TODO: elementClass + if err := ensure(class.String, filename); err != nil { + return nil, err + } + file, err := os.Open(string(filename.(instance.String))) + if err != nil { + return nil, nil // Error File Not Found + } + return instance.NewStream(nil, file), nil +} + +func OpenIoFile(local, global environment.Environment, filename ilos.Instance, elementClass ...ilos.Instance) (ilos.Instance, ilos.Instance) { + // TODO: elementClass + if err := ensure(class.String, filename); err != nil { + return nil, err + } + file, err := os.Open(string(filename.(instance.String))) + if err != nil { + return nil, nil // Error File Not Found + } + return instance.NewStream(file, file), nil +} + +func WithOpenInputFile(local, global environment.Environment, fileSpec ilos.Instance, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { + if err := ensure(class.Cons, fileSpec); err != nil { + return nil, err + } + n := fileSpec.(*instance.Cons).Car + s, err := Eval(local, global, instance.NewCons(instance.NewSymbol("OPEN-INPUT-FILE"), fileSpec.(*instance.Cons).Cdr)) + if err != nil { + return nil, err + } + local.Variable.Define(n, s) + return Progn(local, global, forms...) +} + +func WithOpenOutputFile(local, global environment.Environment, fileSpec ilos.Instance, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { + if err := ensure(class.Cons, fileSpec); err != nil { + return nil, err + } + n := fileSpec.(*instance.Cons).Car + s, err := Eval(local, global, instance.NewCons(instance.NewSymbol("OPEN-OUTPUT-FILE"), fileSpec.(*instance.Cons).Cdr)) + if err != nil { + return nil, err + } + local.Variable.Define(n, s) + return Progn(local, global, forms...) +} + +func WithOpenIoFile(local, global environment.Environment, fileSpec ilos.Instance, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { + if err := ensure(class.Cons, fileSpec); err != nil { + return nil, err + } + n := fileSpec.(*instance.Cons).Car + s, err := Eval(local, global, instance.NewCons(instance.NewSymbol("OPEN-IO-FILE"), fileSpec.(*instance.Cons).Cdr)) + if err != nil { + return nil, err + } + local.Variable.Define(n, s) + return Progn(local, global, forms...) +} + +func Close(local, global environment.Environment, stream ilos.Instance) (ilos.Instance, ilos.Instance) { + // It works on file or std stream. + if err := ensure(class.Stream, stream); err != nil { + return nil, err + } + if stream.(instance.Stream).Reader != nil { + stream.(instance.Stream).Reader.(*os.File).Close() + } + if stream.(instance.Stream).Writer != nil { + stream.(instance.Stream).Writer.(*os.File).Close() + } + return Nil, nil +} + +func FlushOutput(local, global environment.Environment, stream ilos.Instance) (ilos.Instance, ilos.Instance) { + // It works on file or std stream. + if err := ensure(class.Stream, stream); err != nil { + return nil, err + } + if stream.(instance.Stream).Writer != nil { + stream.(instance.Stream).Writer.(*os.File).Close() + } + return Nil, nil +} + +func CreateStringInputStream(local, global environment.Environment, str ilos.Instance) (ilos.Instance, ilos.Instance) { + return instance.NewStream(strings.NewReader(string(str.(instance.String))), nil), nil +} + +func CreateStringOutputStream(local, global environment.Environment) (ilos.Instance, ilos.Instance) { + return instance.NewStream(nil, new(bytes.Buffer)), nil +} + +func GetOutputStreamString(local, global environment.Environment, stream ilos.Instance) (ilos.Instance, ilos.Instance) { + if err := ensure(class.Stream, stream); err != nil { + return nil, err + } + return instance.NewString(stream.(instance.Stream).Writer.(*bytes.Buffer).String()), nil +} + +func Read(local, global environment.Environment, options ...ilos.Instance) (ilos.Instance, ilos.Instance) { + s := local.StandardInput + if len(options) > 0 { + s = options[0] + } + if b, _ := InputStreamp(local, global, s); b == Nil { + return nil, nil // throw Error + } + eosErrorP := true + if len(options) > 1 { + if options[1] == Nil { + eosErrorP = false + } + } + eosValue := Nil + if len(options) > 2 { + if options[2] == Nil { + eosValue = options[2] + } + } + v, err := parser.Parse(tokenizer.New(s.(instance.Stream).Reader)) + if ilos.InstanceOf(class.EndOfStream, err) { + if eosErrorP { + return nil, err + } + return eosValue, nil + } + return v, nil +} + +func ReadChar(local, global environment.Environment, options ...ilos.Instance) (ilos.Instance, ilos.Instance) { + s := local.StandardInput + if len(options) > 0 { + s = options[0] + } + if b, _ := InputStreamp(local, global, s); b == Nil { + return nil, nil // throw Error + } + eosErrorP := true + if len(options) > 1 { + if options[1] == Nil { + eosErrorP = false + } + } + eosValue := Nil + if len(options) > 2 { + if options[2] == Nil { + eosValue = options[2] + } + } + v, _, err := bufio.NewReader(s.(instance.Stream).Reader).ReadRune() + if err != nil { + if eosErrorP { + return nil, instance.Create(local, global, class.EndOfStream) + } + return eosValue, nil + } + return instance.NewCharacter(v), nil +} + +func ReadLine(local, global environment.Environment, options ...ilos.Instance) (ilos.Instance, ilos.Instance) { + s := local.StandardInput + if len(options) > 0 { + s = options[0] + } + if b, _ := InputStreamp(local, global, s); b == Nil { + return nil, nil // throw Error + } + eosErrorP := true + if len(options) > 1 { + if options[1] == Nil { + eosErrorP = false + } + } + eosValue := Nil + if len(options) > 2 { + if options[2] == Nil { + eosValue = options[2] + } + } + v, _, err := bufio.NewReader(s.(instance.Stream).Reader).ReadLine() + if err != nil { + if eosErrorP { + return nil, instance.Create(local, global, class.EndOfStream) + } + return eosValue, nil + } + return instance.NewString(string(v)), nil +} + +// TODO: preview-char (Hint: Bufio.Rreader) + +func StreamReadyP(local, global environment.Environment, inputStream ilos.Instance) (ilos.Instance, ilos.Instance) { + // TODO: stream-ready-p + return T, nil +} + +func Format(local, global environment.Environment, stream, formatString ilos.Instance, objs ...ilos.Instance) (ilos.Instance, ilos.Instance) { + f := regexp.MustCompile("([^~])~A").ReplaceAllString(string(formatString.(instance.String)), "%1%v") + f = regexp.MustCompile(`\`).ReplaceAllString(string(formatString.(instance.String)), `\\`) + f = regexp.MustCompile("([^~])~%").ReplaceAllString(string(formatString.(instance.String)), "%1\n") + if b, _ := OutputStreamp(local, global, stream); b == Nil { + return nil, nil // throw Error + } + args := []interface{}{} + for _, obj := range objs { + args = append(args, obj) + } + fmt.Fprintf(stream.(instance.Stream).Writer, f, args...) + return Nil, nil +} diff --git a/runtime/test.go b/runtime/test.go index 592960b..3b0a290 100644 --- a/runtime/test.go +++ b/runtime/test.go @@ -9,8 +9,6 @@ import ( "regexp" "runtime" "testing" - - "github.com/ta2gch/iris/runtime/environment" ) type test struct { @@ -22,8 +20,8 @@ type test struct { func execTests(t *testing.T, function interface{}, tests []test) { name := runtime.FuncForPC(reflect.ValueOf(function).Pointer()).Name() name = regexp.MustCompile(`.*\.`).ReplaceAllString(name, "") - local := environment.New() - global := environment.TopLevel + local := NewEnvironment() + global := TopLevel for _, tt := range tests { t.Run(tt.exp, func(t *testing.T) { got, err := Eval(local, global, readFromString(tt.exp)) diff --git a/runtime/util.go b/runtime/util.go index 79912e7..484b650 100644 --- a/runtime/util.go +++ b/runtime/util.go @@ -5,6 +5,7 @@ package runtime import ( + "os" "reflect" "regexp" "runtime" @@ -58,24 +59,24 @@ func func2symbol(function interface{}) ilos.Instance { } func defspecial(function interface{}) { - environment.TopLevel.Special.Define(func2symbol(function), instance.NewFunction(func2symbol(function), function)) + TopLevel.Special.Define(func2symbol(function), instance.NewFunction(func2symbol(function), function)) } func defmacro(function interface{}) { - environment.TopLevel.Macro.Define(func2symbol(function), instance.NewFunction(func2symbol(function), function)) + TopLevel.Macro.Define(func2symbol(function), instance.NewFunction(func2symbol(function), function)) } func defun(function interface{}) { - environment.TopLevel.Function.Define(func2symbol(function), instance.NewFunction(func2symbol(function), function)) + TopLevel.Function.Define(func2symbol(function), instance.NewFunction(func2symbol(function), function)) } func defun2(name string, function interface{}) { symbol := instance.NewSymbol(name) - environment.TopLevel.Function.Define(symbol, instance.NewFunction(symbol, function)) + TopLevel.Function.Define(symbol, instance.NewFunction(symbol, function)) } func defglobal(name string, value ilos.Instance) { symbol := instance.NewSymbol(name) - environment.TopLevel.Variable.Define(symbol, value) + TopLevel.Variable.Define(symbol, value) } func ensure(c ilos.Class, i ...ilos.Instance) ilos.Instance { for _, o := range i { @@ -85,3 +86,32 @@ func ensure(c ilos.Class, i ...ilos.Instance) ilos.Instance { } return nil } + +// New creates new environment +func NewEnvironment() environment.Environment { + env := new(environment.Environment) + + // Lexical + env.BlockTag = environment.NewStack() + env.TagbodyTag = environment.NewStack() + env.Function = environment.NewStack() + env.Variable = environment.NewStack() + + // Global + env.Macro = environment.NewStack() + env.Class = environment.NewStack() + env.Special = environment.NewStack() + env.Constant = environment.NewStack() + env.Property = environment.NewMap2() + env.GensymID = 0 + + // Dynamic + env.CatchTag = environment.NewStack() + env.DynamicVariable = environment.NewStack() + env.StandardInput = instance.NewStream(os.Stdin, nil) + env.StandardOutput = instance.NewStream(nil, os.Stdout) + env.ErrorOutput = instance.NewStream(nil, os.Stderr) + return *env +} + +var TopLevel = NewEnvironment() From a956d37509ffaf796bb65945c1676097a24cadb8 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Wed, 23 Aug 2017 08:22:24 +0900 Subject: [PATCH 206/228] Changed NewEnvironment --- runtime/environment/environment.go | 43 +++++++++++++++++++++++++++++- runtime/eval.go | 16 +++-------- runtime/functions.go | 3 +-- runtime/test.go | 6 ++++- runtime/util.go | 29 +------------------- 5 files changed, 53 insertions(+), 44 deletions(-) diff --git a/runtime/environment/environment.go b/runtime/environment/environment.go index c2ee980..5e7e2c8 100644 --- a/runtime/environment/environment.go +++ b/runtime/environment/environment.go @@ -30,6 +30,34 @@ type Environment struct { StandardInput ilos.Instance StandardOutput ilos.Instance ErrorOutput ilos.Instance + Handler stack +} + +// New creates new environment +func NewEnvironment(stdin, stdout, stderr ilos.Instance) Environment { + env := new(Environment) + + // Lexical + env.BlockTag = NewStack() + env.TagbodyTag = NewStack() + env.Function = NewStack() + env.Variable = NewStack() + + // Global + env.Macro = NewStack() + env.Class = NewStack() + env.Special = NewStack() + env.Constant = NewStack() + env.Property = NewMap2() + env.GensymID = 0 + + // Dynamic + env.CatchTag = NewStack() + env.DynamicVariable = NewStack() + env.StandardInput = stdin + env.StandardOutput = stdout + env.ErrorOutput = stderr + return *env } func (env *Environment) Merge(before Environment) { @@ -43,12 +71,12 @@ func (env *Environment) Merge(before Environment) { env.Macro = append(before.Macro, env.Macro...) env.DynamicVariable = append(before.DynamicVariable, env.DynamicVariable...) env.Constant = append(before.Constant, env.Constant...) + env.Handler = append(before.Handler, env.Handler...) env.GensymID = before.GensymID env.Property = before.Property env.StandardInput = before.StandardInput env.StandardOutput = before.StandardOutput env.ErrorOutput = before.ErrorOutput - } func (env *Environment) MergeDynamic(before Environment) { @@ -57,4 +85,17 @@ func (env *Environment) MergeDynamic(before Environment) { env.StandardInput = before.StandardInput env.StandardOutput = before.StandardOutput env.ErrorOutput = before.ErrorOutput + env.Handler = append(before.Handler, env.Handler...) +} + +func Push(before Environment) Environment { + env := NewEnvironment(before.StandardInput, before.StandardOutput, before.ErrorOutput) + env.Merge(before) + return env +} + +func PushDynamic(before Environment) Environment { + env := NewEnvironment(before.StandardInput, before.StandardOutput, before.ErrorOutput) + env.MergeDynamic(before) + return env } diff --git a/runtime/eval.go b/runtime/eval.go index 36a6be8..e3a39b7 100644 --- a/runtime/eval.go +++ b/runtime/eval.go @@ -48,9 +48,7 @@ func evalLambda(local, global environment.Environment, car, cdr ilos.Instance) ( if err != nil { return nil, err, true } - env := NewEnvironment() - env.MergeDynamic(local) - ret, err := fun.(instance.Applicable).Apply(env, global, arguments.(instance.List).Slice()...) + ret, err := fun.(instance.Applicable).Apply(environment.PushDynamic(local), global, arguments.(instance.List).Slice()...) if err != nil { return nil, err, true } @@ -67,9 +65,7 @@ func evalSpecial(local, global environment.Environment, car, cdr ilos.Instance) spl = s } if spl != nil { - env := NewEnvironment() - env.Merge(local) - ret, err := spl.(instance.Applicable).Apply(env, global, cdr.(instance.List).Slice()...) + ret, err := spl.(instance.Applicable).Apply(environment.Push(local), global, cdr.(instance.List).Slice()...) if err != nil { return nil, err, true } @@ -88,9 +84,7 @@ func evalMacro(local, global environment.Environment, car, cdr ilos.Instance) (i mac = m } if mac != nil { - env := NewEnvironment() - env.MergeDynamic(local) - ret, err := mac.(instance.Applicable).Apply(env, global, cdr.(instance.List).Slice()...) + ret, err := mac.(instance.Applicable).Apply(environment.PushDynamic(local), global, cdr.(instance.List).Slice()...) if err != nil { return nil, err, true } @@ -113,13 +107,11 @@ func evalFunction(local, global environment.Environment, car, cdr ilos.Instance) fun = f } if fun != nil { - env := NewEnvironment() - env.MergeDynamic(local) arguments, err := evalArguments(local, global, cdr) if err != nil { return nil, err, true } - ret, err := fun.(instance.Applicable).Apply(env, global, arguments.(instance.List).Slice()...) + ret, err := fun.(instance.Applicable).Apply(environment.PushDynamic(local), global, arguments.(instance.List).Slice()...) if err != nil { return nil, err, true } diff --git a/runtime/functions.go b/runtime/functions.go index ba995ca..d4ea5a1 100644 --- a/runtime/functions.go +++ b/runtime/functions.go @@ -131,8 +131,7 @@ func Flet(local, global environment.Environment, functions ilos.Instance, bodyFo if err := ensure(class.List, functions); err != nil { return nil, err } - env := NewEnvironment() - env.Merge(local) + env := environment.Push(local) for _, function := range functions.(instance.List).Slice() { if err := ensure(class.List, function); err != nil { return nil, err diff --git a/runtime/test.go b/runtime/test.go index 3b0a290..bc4da47 100644 --- a/runtime/test.go +++ b/runtime/test.go @@ -5,10 +5,14 @@ package runtime import ( + "os" "reflect" "regexp" "runtime" "testing" + + "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/ilos/instance" ) type test struct { @@ -20,7 +24,7 @@ type test struct { func execTests(t *testing.T, function interface{}, tests []test) { name := runtime.FuncForPC(reflect.ValueOf(function).Pointer()).Name() name = regexp.MustCompile(`.*\.`).ReplaceAllString(name, "") - local := NewEnvironment() + local := environment.NewEnvironment(instance.NewStream(os.Stdin, nil), instance.NewStream(nil, os.Stdout), instance.NewStream(nil, os.Stderr)) global := TopLevel for _, tt := range tests { t.Run(tt.exp, func(t *testing.T) { diff --git a/runtime/util.go b/runtime/util.go index 484b650..c92ede9 100644 --- a/runtime/util.go +++ b/runtime/util.go @@ -87,31 +87,4 @@ func ensure(c ilos.Class, i ...ilos.Instance) ilos.Instance { return nil } -// New creates new environment -func NewEnvironment() environment.Environment { - env := new(environment.Environment) - - // Lexical - env.BlockTag = environment.NewStack() - env.TagbodyTag = environment.NewStack() - env.Function = environment.NewStack() - env.Variable = environment.NewStack() - - // Global - env.Macro = environment.NewStack() - env.Class = environment.NewStack() - env.Special = environment.NewStack() - env.Constant = environment.NewStack() - env.Property = environment.NewMap2() - env.GensymID = 0 - - // Dynamic - env.CatchTag = environment.NewStack() - env.DynamicVariable = environment.NewStack() - env.StandardInput = instance.NewStream(os.Stdin, nil) - env.StandardOutput = instance.NewStream(nil, os.Stdout) - env.ErrorOutput = instance.NewStream(nil, os.Stderr) - return *env -} - -var TopLevel = NewEnvironment() +var TopLevel = environment.NewEnvironment(instance.NewStream(os.Stdin, nil), instance.NewStream(nil, os.Stdout), instance.NewStream(nil, os.Stderr)) From 6fc2fc39ac38a5801a95a5feb039a9381e0cf63a Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Wed, 23 Aug 2017 13:44:19 +0900 Subject: [PATCH 207/228] Remove global environment --- runtime/array_operations.go | 32 +++++----- runtime/character_class.go | 30 +++++----- runtime/class.go | 10 ++-- runtime/condition_system.go | 47 ++++++++------- runtime/conditional_expressions.go | 32 +++++----- runtime/cons.go | 12 ++-- runtime/constants.go | 2 +- runtime/defining_classes.go | 54 +++++++++-------- runtime/defining_operators.go | 33 ++++++----- runtime/dynamic_variables.go | 16 ++--- runtime/environment/environment.go | 87 ++++++++++++++++++++++------ runtime/equality.go | 6 +- runtime/eval.go | 63 +++++++++----------- runtime/float_class.go | 12 ++-- runtime/functions.go | 30 +++++----- runtime/functions_test.go | 7 +++ runtime/generic_functions.go | 18 +++--- runtime/ilos/instance/error.go | 29 +++++----- runtime/ilos/instance/function.go | 52 ++++++++--------- runtime/ilos/instance/instance.go | 12 ++-- runtime/ilos/instance/tag.go | 7 ++- runtime/integer_class.go | 16 ++--- runtime/iteration.go | 18 +++--- runtime/list_operations.go | 52 ++++++++--------- runtime/logical_connectives.go | 33 +++++++---- runtime/logical_connectives_test.go | 4 +- runtime/macros.go | 46 +++++++-------- runtime/namedfunc.go | 8 +-- runtime/non-local_exits.go | 38 ++++++------ runtime/null_class.go | 2 +- runtime/number_class.go | 90 ++++++++++++++--------------- runtime/sequence_functions.go | 18 +++--- runtime/sequencing_forms.go | 4 +- runtime/stream.go | 88 ++++++++++++++-------------- runtime/string_class.go | 38 ++++++------ runtime/symbol_class.go | 20 +++---- runtime/test.go | 12 +--- runtime/util.go | 4 +- runtime/variables.go | 30 +++++----- runtime/vectors.go | 8 +-- 40 files changed, 591 insertions(+), 529 deletions(-) diff --git a/runtime/array_operations.go b/runtime/array_operations.go index e3e6ee5..c57b239 100644 --- a/runtime/array_operations.go +++ b/runtime/array_operations.go @@ -13,7 +13,7 @@ import ( // BasicArrayP returns t if obj is a basic-array (instance of class basic-array); // otherwise, returns nil. obj may be any ISLISP object. -func BasicArrayP(local, global environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { +func BasicArrayP(local environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { if ilos.InstanceOf(class.BasicArray, obj) { return T, nil } @@ -22,7 +22,7 @@ func BasicArrayP(local, global environment.Environment, obj ilos.Instance) (ilos // BasicArrayStarP returns t if obj is a basic-array* (instance of class ); // otherwise, returns nil. obj may be any ISLISP object. -func BasicArrayStarP(local, global environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { +func BasicArrayStarP(local environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { if ilos.InstanceOf(class.BasicArrayStar, obj) { return T, nil } @@ -31,7 +31,7 @@ func BasicArrayStarP(local, global environment.Environment, obj ilos.Instance) ( // GeneralArrayStarP returns t if obj is a general-array* (instance of class ); // otherwise, returns nil. obj may be any ISLISP object. -func GeneralArrayStarP(local, global environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { +func GeneralArrayStarP(local environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { if ilos.InstanceOf(class.GeneralArrayStar, obj) { return T, nil } @@ -52,7 +52,7 @@ func GeneralArrayStarP(local, global environment.Environment, obj ilos.Instance) // // An error shall be signaled if dimensions is not a proper list of non-negative integers // (error-id. domain-error). initial-element may be any ISLISP object -func CreateArray(local, global environment.Environment, dimensions ilos.Instance, initialElement ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func CreateArray(local environment.Environment, dimensions ilos.Instance, initialElement ...ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.List, dimensions); err != nil { return nil, err } @@ -72,11 +72,11 @@ func CreateArray(local, global environment.Environment, dimensions ilos.Instance } array := make([]instance.GeneralArrayStar, int(dim[0].(instance.Integer))) for i := range array { - d, err := List(local, global, dim[1:]...) + d, err := List(local, dim[1:]...) if err != nil { return nil, err } - a, err := CreateArray(local, global, d, elt) + a, err := CreateArray(local, d, elt) if err != nil { return nil, err } @@ -93,7 +93,7 @@ func CreateArray(local, global environment.Environment, dimensions ilos.Instance // // An error shall be signaled if basic-array is not a basic-array (error-id. domain-error). // An error shall be signaled if any z is not a non-negative integer (error-id. domain-error). -func Aref(local, global environment.Environment, basicArray ilos.Instance, dimensions ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Aref(local environment.Environment, basicArray ilos.Instance, dimensions ...ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.BasicArray, basicArray); err != nil { return nil, err } @@ -120,13 +120,13 @@ func Aref(local, global environment.Environment, basicArray ilos.Instance, dimen } return basicArray.(instance.GeneralVector)[index], nil default: // General Array* - return Garef(local, global, basicArray, dimensions...) + return Garef(local, basicArray, dimensions...) } } // Garef is like aref but an error shall be signaled if its first argument, general-array, is // not an object of class general-vector or of class (error-id. domain-error). -func Garef(local, global environment.Environment, generalArray ilos.Instance, dimensions ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Garef(local environment.Environment, generalArray ilos.Instance, dimensions ...ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.GeneralArrayStar, generalArray); err != nil { return nil, err } @@ -150,7 +150,7 @@ func Garef(local, global environment.Environment, generalArray ilos.Instance, di // SetAref replaces the object obtainable by aref or garef with obj . The returned value is obj. // The constraints on the basic-array, the general-array, and the sequence of indices z is the // same as for aref and garef. -func SetAref(local, global environment.Environment, obj, basicArray ilos.Instance, dimensions ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func SetAref(local environment.Environment, obj, basicArray ilos.Instance, dimensions ...ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.BasicArray, basicArray); err != nil { return nil, err } @@ -182,14 +182,14 @@ func SetAref(local, global environment.Environment, obj, basicArray ilos.Instanc basicArray.(instance.GeneralVector)[index] = obj return obj, nil default: // General Array* - return SetGaref(local, global, obj, basicArray, dimensions...) + return SetGaref(local, obj, basicArray, dimensions...) } } // SetGaref replaces the object obtainable by aref or garef with obj . The returned value is obj. // The constraints on the basic-array, the general-array, and the sequence of indices z is the // same as for aref and garef. -func SetGaref(local, global environment.Environment, obj, generalArray ilos.Instance, dimensions ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func SetGaref(local environment.Environment, obj, generalArray ilos.Instance, dimensions ...ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.GeneralArrayStar, generalArray); err != nil { return nil, err } @@ -214,15 +214,15 @@ func SetGaref(local, global environment.Environment, obj, generalArray ilos.Inst // ArrayDimensions returns a list of the dimensions of a given basic-array. // An error shall be signaled if basic-array is not a basic-array (error-id. domain-error). // The consequences are undefined if the returned list is modified. -func ArrayDimensions(local, global environment.Environment, basicArray ilos.Instance) (ilos.Instance, ilos.Instance) { +func ArrayDimensions(local environment.Environment, basicArray ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.BasicArray, basicArray); err != nil { return nil, err } switch { case ilos.InstanceOf(class.String, basicArray): - return List(local, global, instance.NewInteger(len(basicArray.(instance.String)))) + return List(local, instance.NewInteger(len(basicArray.(instance.String)))) case ilos.InstanceOf(class.GeneralVector, basicArray): - return List(local, global, instance.NewInteger(len(basicArray.(instance.GeneralVector)))) + return List(local, instance.NewInteger(len(basicArray.(instance.GeneralVector)))) default: // General Array* var array instance.GeneralArrayStar dimensions := []ilos.Instance{} @@ -230,6 +230,6 @@ func ArrayDimensions(local, global environment.Environment, basicArray ilos.Inst dimensions = append(dimensions, instance.NewInteger(len(array.Vector))) array = array.Vector[0] } - return List(local, global, dimensions...) + return List(local, dimensions...) } } diff --git a/runtime/character_class.go b/runtime/character_class.go index 741a183..68c07cb 100644 --- a/runtime/character_class.go +++ b/runtime/character_class.go @@ -13,7 +13,7 @@ import ( // Characterp returns t if obj is a character (instance of class character); // otherwise, returns nil. obj may be any ISLISP object. -func Characterp(local, global environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { +func Characterp(local environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { if ilos.InstanceOf(class.Character, obj) { return T, nil } @@ -21,7 +21,7 @@ func Characterp(local, global environment.Environment, obj ilos.Instance) (ilos. } // CharEqual tests whether char1 is the same character as char2. -func CharEqual(local, global environment.Environment, char1, char2 ilos.Instance) (ilos.Instance, ilos.Instance) { +func CharEqual(local environment.Environment, char1, char2 ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Character, char1, char2); err != nil { return nil, err } @@ -32,17 +32,17 @@ func CharEqual(local, global environment.Environment, char1, char2 ilos.Instance } // CharNotEqual if and only if they are not char=. -func CharNotEqual(local, global environment.Environment, char1, char2 ilos.Instance) (ilos.Instance, ilos.Instance) { - ret, err := CharEqual(local, global, char1, char2) +func CharNotEqual(local environment.Environment, char1, char2 ilos.Instance) (ilos.Instance, ilos.Instance) { + ret, err := CharEqual(local, char1, char2) if err != nil { return nil, err } - return Not(local, global, ret) + return Not(local, ret) } // CharGreaterThan tests whether char1 is greater than char2. // An error shall be signaled if either char1 or char2 is not a character (error-id. domain-error). -func CharGreaterThan(local, global environment.Environment, char1, char2 ilos.Instance) (ilos.Instance, ilos.Instance) { +func CharGreaterThan(local environment.Environment, char1, char2 ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Character, char1, char2); err != nil { return nil, err } @@ -54,12 +54,12 @@ func CharGreaterThan(local, global environment.Environment, char1, char2 ilos.In // CharGreaterThanOrEqual tests whether char1 is greater than or equal to char2. // An error shall be signaled if either char1 or char2 is not a character (error-id. domain-error). -func CharGreaterThanOrEqual(local, global environment.Environment, char1, char2 ilos.Instance) (ilos.Instance, ilos.Instance) { - gt, err := CharGreaterThan(local, global, char1, char2) +func CharGreaterThanOrEqual(local environment.Environment, char1, char2 ilos.Instance) (ilos.Instance, ilos.Instance) { + gt, err := CharGreaterThan(local, char1, char2) if err != nil { return nil, err } - eq, err := CharEqual(local, global, char1, char2) + eq, err := CharEqual(local, char1, char2) if err != nil { return nil, err } @@ -71,20 +71,20 @@ func CharGreaterThanOrEqual(local, global environment.Environment, char1, char2 // CharLessThan tests whether char1 is less than char2. // An error shall be signaled if either char1 or char2 is not a character (error-id. domain-error). -func CharLessThan(local, global environment.Environment, char1, char2 ilos.Instance) (ilos.Instance, ilos.Instance) { - gt, err := CharGreaterThanOrEqual(local, global, char1, char2) +func CharLessThan(local environment.Environment, char1, char2 ilos.Instance) (ilos.Instance, ilos.Instance) { + gt, err := CharGreaterThanOrEqual(local, char1, char2) if err != nil { return nil, err } - return Not(local, global, gt) + return Not(local, gt) } // CharLessThanOrEqual tests whether char1 is less than or equal to char2. // An error shall be signaled if either char1 or char2 is not a character (error-id. domain-error). -func CharLessThanOrEqual(local, global environment.Environment, char1, char2 ilos.Instance) (ilos.Instance, ilos.Instance) { - gt, err := CharGreaterThan(local, global, char1, char2) +func CharLessThanOrEqual(local environment.Environment, char1, char2 ilos.Instance) (ilos.Instance, ilos.Instance) { + gt, err := CharGreaterThan(local, char1, char2) if err != nil { return nil, err } - return Not(local, global, gt) + return Not(local, gt) } diff --git a/runtime/class.go b/runtime/class.go index 3221dbe..e2fe43a 100644 --- a/runtime/class.go +++ b/runtime/class.go @@ -10,26 +10,26 @@ import ( "github.com/ta2gch/iris/runtime/ilos/instance" ) -func ClassOf(local, global environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { +func ClassOf(local environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { return obj.Class(), nil } -func Instancep(local, global environment.Environment, obj ilos.Instance, class ilos.Class) (ilos.Instance, ilos.Instance) { +func Instancep(local environment.Environment, obj ilos.Instance, class ilos.Class) (ilos.Instance, ilos.Instance) { if ilos.InstanceOf(class, obj) { return T, nil } return Nil, nil } -func Subclassp(local, global environment.Environment, class1, class2 ilos.Class) (ilos.Instance, ilos.Instance) { +func Subclassp(local environment.Environment, class1, class2 ilos.Class) (ilos.Instance, ilos.Instance) { if ilos.SubclassOf(class1, class2) { return T, nil } return Nil, nil } -func Class(local, global environment.Environment, className ilos.Instance) (ilos.Class, ilos.Instance) { - if v, ok := global.Class.Get(className); ok { +func Class(local environment.Environment, className ilos.Instance) (ilos.Class, ilos.Instance) { + if v, ok := TopLevel.Class.Get(className); ok { return v.(ilos.Class), nil } return nil, instance.NewUndefinedClass(className) diff --git a/runtime/condition_system.go b/runtime/condition_system.go index 504b54f..d051e4a 100644 --- a/runtime/condition_system.go +++ b/runtime/condition_system.go @@ -11,75 +11,80 @@ import ( "github.com/ta2gch/iris/runtime/ilos/instance" ) -func SignalCondition(local, global environment.Environment, condition, continuable ilos.Instance) (ilos.Instance, ilos.Instance) { +func SignalCondition(local environment.Environment, condition, continuable ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.SeriousCondition, condition); err != nil { return nil, err } + if handler, ok := local.Handler.Get(instance.NewSymbol("HANDLER")); ok { + if continuable != Nil { + handler.(instance.Applicable).Apply(local, condition) + } + } condition.(instance.Instance).SetSlotValue(instance.NewSymbol("IRIS.CONTINUABLE"), continuable, class.SeriousCondition) return nil, condition } -func Cerror(local, global environment.Environment, continueString, errorString ilos.Instance, objs ...ilos.Instance) (ilos.Instance, ilos.Instance) { - arguments, err := List(local, global, objs...) +func Cerror(local environment.Environment, continueString, errorString ilos.Instance, objs ...ilos.Instance) (ilos.Instance, ilos.Instance) { + arguments, err := List(local, objs...) if err != nil { return nil, err } - condition := instance.Create(local, global, class.SimpleError, instance.NewSymbol("FORMAT-STRING"), errorString, instance.NewSymbol("FORAMT-OBJECTS"), arguments) - ss, err := CreateStringOutputStream(local, global) + condition := instance.Create(local, class.SimpleError, instance.NewSymbol("FORMAT-STRING"), errorString, instance.NewSymbol("FORAMT-OBJECTS"), arguments) + ss, err := CreateStringOutputStream(local) if err != nil { return nil, err } - if _, err := Format(local, global, ss, continueString, objs...); err != nil { + if _, err := Format(local, ss, continueString, objs...); err != nil { return nil, err } - continuable, err := GetOutputStreamString(local, global, ss) + continuable, err := GetOutputStreamString(local, ss) if err != nil { return nil, err } - return SignalCondition(local, global, condition, continuable) + return SignalCondition(local, condition, continuable) } -func Error(local, global environment.Environment, continueString, errorString ilos.Instance, objs ...ilos.Instance) (ilos.Instance, ilos.Instance) { - arguments, err := List(local, global, objs...) +func Error(local environment.Environment, continueString, errorString ilos.Instance, objs ...ilos.Instance) (ilos.Instance, ilos.Instance) { + arguments, err := List(local, objs...) if err != nil { return nil, err } - condition := instance.Create(local, global, class.SimpleError, instance.NewSymbol("FORMAT-STRING"), errorString, instance.NewSymbol("FORAMT-OBJECTS"), arguments) - return SignalCondition(local, global, condition, Nil) + condition := instance.Create(local, class.SimpleError, instance.NewSymbol("FORMAT-STRING"), errorString, instance.NewSymbol("FORAMT-OBJECTS"), arguments) + return SignalCondition(local, condition, Nil) } -func IgnoreError(local, global environment.Environment, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { - ret, err := Progn(local, global, forms...) +func IgnoreError(local environment.Environment, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { + ret, err := Progn(local, forms...) if err != nil && ilos.InstanceOf(class.Error, err) { return Nil, nil } return ret, err } -func ReportCondition(local, global environment.Environment, condition, stream ilos.Instance) (ilos.Instance, ilos.Instance) { +func ReportCondition(local environment.Environment, condition, stream ilos.Instance) (ilos.Instance, ilos.Instance) { return nil, nil } -func ConditionContinuable(local, global environment.Environment, condition ilos.Instance) (ilos.Instance, ilos.Instance) { +func ConditionContinuable(local environment.Environment, condition ilos.Instance) (ilos.Instance, ilos.Instance) { if continuable, ok := condition.(instance.Instance).GetSlotValue(instance.NewSymbol("IRIS.CONTINUABLE"), class.SeriousCondition); ok { return continuable, nil } return Nil, nil } -func ContinueCondition(local, global environment.Environment, condition, value ilos.Instance) (ilos.Instance, ilos.Instance) { +func ContinueCondition(local environment.Environment, condition, value ilos.Instance) (ilos.Instance, ilos.Instance) { // TODO: return nil, nil } -func WithHandler(local, global environment.Environment, handler ilos.Instance, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { - fun, err := Eval(local, global, handler) +func WithHandler(local environment.Environment, handler ilos.Instance, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { + fun, err := Eval(local, handler) if err != nil { return nil, err } - ret, err := Progn(local, global, forms...) + ret, err := Progn(local, forms...) if err != nil { - return fun.(instance.Applicable).Apply(local, global, err) + return fun.(instance.Applicable).Apply(local, err) } return ret, err } diff --git a/runtime/conditional_expressions.go b/runtime/conditional_expressions.go index 5be4bdd..141582f 100644 --- a/runtime/conditional_expressions.go +++ b/runtime/conditional_expressions.go @@ -18,13 +18,13 @@ import ( // is evaluated and its value is returned. // // If no else-form is provided, it defaults to nil. -func If(local, global environment.Environment, testForm, thenForm ilos.Instance, elseForm ...ilos.Instance) (ilos.Instance, ilos.Instance) { - tf, err := Eval(local, global, testForm) +func If(local environment.Environment, testForm, thenForm ilos.Instance, elseForm ...ilos.Instance) (ilos.Instance, ilos.Instance) { + tf, err := Eval(local, testForm) if err != nil { return nil, err } if tf == T { - return Eval(local, global, thenForm) + return Eval(local, thenForm) } if len(elseForm) > 1 { return nil, instance.NewArityError() @@ -32,7 +32,7 @@ func If(local, global environment.Environment, testForm, thenForm ilos.Instance, if len(elseForm) == 0 { return Nil, nil } - return Eval(local, global, elseForm[0]) + return Eval(local, elseForm[0]) } // Cond the clauses (test form*) are scanned sequentially @@ -41,7 +41,7 @@ func If(local, global environment.Environment, testForm, thenForm ilos.Instance, //are sequentially evaluated and the value of the last one is returned. // If no test is true, then nil is returned. // If no form exists for the successful test then the value of this test is returned. -func Cond(local, global environment.Environment, testFrom ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Cond(local environment.Environment, testFrom ...ilos.Instance) (ilos.Instance, ilos.Instance) { for _, tf := range testFrom { if err := ensure(class.List, tf); err != nil { return nil, err @@ -50,12 +50,12 @@ func Cond(local, global environment.Environment, testFrom ...ilos.Instance) (ilo if len(s) == 0 { return nil, instance.NewArityError() } - ret, err := Eval(local, global, s[0]) + ret, err := Eval(local, s[0]) if err != nil { return nil, err } if ret == T { - return Progn(local, global, s[1:]...) + return Progn(local, s[1:]...) } } return Nil, nil @@ -74,8 +74,8 @@ func Cond(local, global environment.Environment, testFrom ...ilos.Instance) (ilo // the value returned by keyform and key. If no form exists for a matching key, the case form evaluates to nil. // If the value of keyform is different from every key, and there is a default clause, its forms, if any, // are evaluated sequentially, and the value of the last one is the result of the case form. -func Case(local, global environment.Environment, key ilos.Instance, pattern ...ilos.Instance) (ilos.Instance, ilos.Instance) { - key, err := Eval(local, global, key) +func Case(local environment.Environment, key ilos.Instance, pattern ...ilos.Instance) (ilos.Instance, ilos.Instance) { + key, err := Eval(local, key) if err != nil { return nil, err } @@ -88,14 +88,14 @@ func Case(local, global environment.Environment, key ilos.Instance, pattern ...i return nil, instance.NewArityError() } if idx == len(pattern)-1 && form[0] == T { - return Progn(local, global, form[1:]...) + return Progn(local, form[1:]...) } if err := ensure(class.List, form[0]); err != nil { return nil, err } for _, k := range form[0].(instance.List).Slice() { if k == key { - return Progn(local, global, form[1:]...) + return Progn(local, form[1:]...) } } } @@ -117,8 +117,8 @@ func Case(local, global environment.Environment, key ilos.Instance, pattern ...i // the value returned by keyform and key. If no form exists for a matching key, the case form evaluates to nil. // If the value of keyform is different from every key, and there is a default clause, its forms, if any, // are evaluated sequentially, and the value of the last one is the result of the case form. -func CaseUsing(local, global environment.Environment, key, pred ilos.Instance, pattern ...ilos.Instance) (ilos.Instance, ilos.Instance) { - key, err := Eval(local, global, key) +func CaseUsing(local environment.Environment, key, pred ilos.Instance, pattern ...ilos.Instance) (ilos.Instance, ilos.Instance) { + key, err := Eval(local, key) if err != nil { return nil, err } @@ -134,18 +134,18 @@ func CaseUsing(local, global environment.Environment, key, pred ilos.Instance, p return nil, instance.NewArityError() } if idx == len(pattern)-1 && form[0] == T { - return Progn(local, global, form[1:]...) + return Progn(local, form[1:]...) } if err := ensure(class.List, form[0]); err != nil { return nil, err } for _, k := range form[0].(instance.List).Slice() { - ret, err := pred.(instance.Applicable).Apply(local, global, k, key) + ret, err := pred.(instance.Applicable).Apply(local, k, key) if err != nil { return nil, err } if ret != Nil { - return Progn(local, global, form[1:]...) + return Progn(local, form[1:]...) } } } diff --git a/runtime/cons.go b/runtime/cons.go index c067353..dc8135e 100644 --- a/runtime/cons.go +++ b/runtime/cons.go @@ -13,7 +13,7 @@ import ( // Consp returns t if obj is a cons (instance of class cons); // otherwise, returns nil. obj may be any ISLISP object. -func Consp(local, global environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { +func Consp(local environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { if ilos.InstanceOf(class.Cons, obj) { return T, nil } @@ -25,13 +25,13 @@ func Consp(local, global environment.Environment, obj ilos.Instance) (ilos.Insta // An error shall be signaled if the requested cons cannot // be allocated (error-id. cannot-create-cons). Both obj1 // and obj2 may be any ISLISP object. -func Cons(local, global environment.Environment, obj1, obj2 ilos.Instance) (ilos.Instance, ilos.Instance) { +func Cons(local environment.Environment, obj1, obj2 ilos.Instance) (ilos.Instance, ilos.Instance) { return instance.NewCons(obj1, obj2), nil } // Car returns the left component of the cons. // An error shall be signaled if cons is not a cons (error-id. domain-error). -func Car(local, global environment.Environment, cons ilos.Instance) (ilos.Instance, ilos.Instance) { +func Car(local environment.Environment, cons ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Cons, cons); err != nil { return nil, err } @@ -40,7 +40,7 @@ func Car(local, global environment.Environment, cons ilos.Instance) (ilos.Instan // Cdr returns the right component of the cons. // An error shall be signaled if cons is not a cons (error-id. domain-error). -func Cdr(local, global environment.Environment, cons ilos.Instance) (ilos.Instance, ilos.Instance) { +func Cdr(local environment.Environment, cons ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Cons, cons); err != nil { return nil, err } @@ -50,7 +50,7 @@ func Cdr(local, global environment.Environment, cons ilos.Instance) (ilos.Instan // SetCar updates the left component of cons with obj. The returned value is obj . // An error shall be signaled if cons is not a cons (error-id. domain-error). // obj may be any ISLISP object. -func SetCar(local, global environment.Environment, obj, cons ilos.Instance) (ilos.Instance, ilos.Instance) { +func SetCar(local environment.Environment, obj, cons ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Cons, cons); err != nil { return nil, err } @@ -61,7 +61,7 @@ func SetCar(local, global environment.Environment, obj, cons ilos.Instance) (ilo // SetCdr updates the right component of cons with obj. The returned value is obj . // An error shall be signaled if cons is not a cons (error-id. domain-error). // obj may be any ISLISP object. -func SetCdr(local, global environment.Environment, obj, cons ilos.Instance) (ilos.Instance, ilos.Instance) { +func SetCdr(local environment.Environment, obj, cons ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Cons, cons); err != nil { return nil, err } diff --git a/runtime/constants.go b/runtime/constants.go index de564bf..6ced8f0 100644 --- a/runtime/constants.go +++ b/runtime/constants.go @@ -11,6 +11,6 @@ import ( // Quote is used to include any object in an ISLisp text. // A quoted expression denotes a reference to an object. -func Quote(local, global environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { +func Quote(local environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { return obj, nil } diff --git a/runtime/defining_classes.go b/runtime/defining_classes.go index 18b3306..add825b 100644 --- a/runtime/defining_classes.go +++ b/runtime/defining_classes.go @@ -8,7 +8,6 @@ import ( "fmt" "reflect" - "github.com/k0kubun/pp" "github.com/ta2gch/iris/runtime/environment" "github.com/ta2gch/iris/runtime/ilos" "github.com/ta2gch/iris/runtime/ilos/class" @@ -35,7 +34,7 @@ func checkSuperClass(a, b ilos.Class) bool { return false } -func Defclass(local, global environment.Environment, className, scNames, slotSpecs ilos.Instance, classOpts ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Defclass(local environment.Environment, className, scNames, slotSpecs ilos.Instance, classOpts ...ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Symbol, className); err != nil { return nil, err } @@ -44,7 +43,7 @@ func Defclass(local, global environment.Environment, className, scNames, slotSpe } supers := []ilos.Class{class.StandardObject} for _, scName := range scNames.(instance.List).Slice() { - super, err := Class(local, global, scName) + super, err := Class(local, scName) if err != nil { return nil, err } @@ -70,7 +69,7 @@ func Defclass(local, global environment.Environment, className, scNames, slotSpe for i := 0; i < len(slotOpts); i += 2 { switch slotOpts[i] { case instance.NewSymbol(":INITFORM"): - closure, err := newNamedFunction(local, global, instance.NewSymbol("CLOSURE"), Nil, slotOpts[i+1]) + closure, err := newNamedFunction(local, instance.NewSymbol("CLOSURE"), Nil, slotOpts[i+1]) if err != nil { return nil, err } @@ -86,17 +85,17 @@ func Defclass(local, global environment.Environment, className, scNames, slotSpe var err ilos.Instance switch classOpt.(*instance.Cons).Car { case instance.NewSymbol(":METACLASS"): - if metaclass, err = Class(local, global, classOpt.(instance.List).Nth(1)); err != nil { + if metaclass, err = Class(local, classOpt.(instance.List).Nth(1)); err != nil { return nil, err } case instance.NewSymbol(":ABSTRACTP"): - if abstractp, err = Eval(local, global, classOpt.(instance.List).Nth(1)); err != nil { + if abstractp, err = Eval(local, classOpt.(instance.List).Nth(1)); err != nil { return nil, err } } } classObject := instance.NewStandardClass(className, supers, slots, initforms, initargs, metaclass, abstractp) - global.Class.Define(className, classObject) + TopLevel.Class.Define(className, classObject) for _, slotSpec := range slotSpecs.(instance.List).Slice() { if ilos.InstanceOf(class.Symbol, slotSpec) { continue @@ -118,15 +117,15 @@ func Defclass(local, global environment.Environment, className, scNames, slotSpe } } if readerFunctionName != nil { - lambdaList, err := List(local, global, instance.NewSymbol("INSTANCE")) + lambdaList, err := List(local, instance.NewSymbol("INSTANCE")) if err != nil { return nil, err } - if _, ok := global.Function.Get(readerFunctionName); !ok { - Defgeneric(local, global, readerFunctionName, lambdaList) + if g, ok := local.Function.Get(readerFunctionName); !ok || !ilos.InstanceOf(class.GenericFunction, g) { + Defgeneric(local, readerFunctionName, lambdaList) } - fun, _ := global.Function.Get(readerFunctionName) - fun.(*instance.GenericFunction).AddMethod(nil, lambdaList, []ilos.Class{classObject}, instance.NewFunction(readerFunctionName, func(local, global environment.Environment, object ilos.Instance) (ilos.Instance, ilos.Instance) { + fun, _ := local.Function.Get(readerFunctionName) + fun.(*instance.GenericFunction).AddMethod(nil, lambdaList, []ilos.Class{classObject}, instance.NewFunction(readerFunctionName, func(local environment.Environment, object ilos.Instance) (ilos.Instance, ilos.Instance) { slot, ok := object.(instance.Instance).GetSlotValue(slotName, classObject) if ok { return slot, nil @@ -135,16 +134,15 @@ func Defclass(local, global environment.Environment, className, scNames, slotSpe })) } if writerFunctionName != nil { - lambdaList, err := List(local, global, instance.NewSymbol("Y"), instance.NewSymbol("X")) + lambdaList, err := List(local, instance.NewSymbol("Y"), instance.NewSymbol("X")) if err != nil { return nil, err } - if _, ok := global.Function.Get(writerFunctionName); !ok { - Defgeneric(local, global, writerFunctionName, lambdaList) - + if g, ok := local.Function.Get(writerFunctionName); !ok || !ilos.InstanceOf(class.GenericFunction, g) { + Defgeneric(local, writerFunctionName, lambdaList) } - fun, _ := global.Function.Get(writerFunctionName) - fun.(*instance.GenericFunction).AddMethod(nil, lambdaList, []ilos.Class{class.Object, classObject}, instance.NewFunction(writerFunctionName, func(local, global environment.Environment, obj, object ilos.Instance) (ilos.Instance, ilos.Instance) { + fun, _ := local.Function.Get(writerFunctionName) + fun.(*instance.GenericFunction).AddMethod(nil, lambdaList, []ilos.Class{class.Object, classObject}, instance.NewFunction(writerFunctionName, func(local environment.Environment, obj, object ilos.Instance) (ilos.Instance, ilos.Instance) { ok := object.(instance.Instance).SetSlotValue(obj, slotName, classObject) if ok { return obj, nil @@ -153,36 +151,36 @@ func Defclass(local, global environment.Environment, className, scNames, slotSpe })) } if boundpFunctionName != nil { - lambdaList, err := List(local, global, instance.NewSymbol("INSTANCE")) + lambdaList, err := List(local, instance.NewSymbol("INSTANCE")) if err != nil { return nil, err } - if _, ok := global.Function.Get(boundpFunctionName); !ok { - Defgeneric(local, global, boundpFunctionName, lambdaList) + if g, ok := local.Function.Get(boundpFunctionName); !ok || !ilos.InstanceOf(class.GenericFunction, g) { + Defgeneric(local, boundpFunctionName, lambdaList) } - fun, _ := global.Function.Get(boundpFunctionName) - pp.Print(fun.(*instance.GenericFunction).AddMethod(nil, lambdaList, []ilos.Class{classObject}, instance.NewFunction(boundpFunctionName, func(local, global environment.Environment, object ilos.Instance) (ilos.Instance, ilos.Instance) { + fun, _ := local.Function.Get(boundpFunctionName) + fun.(*instance.GenericFunction).AddMethod(nil, lambdaList, []ilos.Class{classObject}, instance.NewFunction(boundpFunctionName, func(local environment.Environment, object ilos.Instance) (ilos.Instance, ilos.Instance) { _, ok := object.(instance.Instance).GetSlotValue(slotName, classObject) if ok { return T, nil } return Nil, nil - }))) + })) } } return className, nil } -func Create(local, global environment.Environment, c ilos.Instance, i ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Create(local environment.Environment, c ilos.Instance, i ...ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.StandardClass, c); err != nil { return nil, err } - return instance.Create(local, global, c, i...), nil + return instance.Create(local, c, i...), nil } -func InitializeObject(local, global environment.Environment, object ilos.Instance, inits ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func InitializeObject(local environment.Environment, object ilos.Instance, inits ...ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.StandardObject, object); err != nil { return nil, err } - return instance.InitializeObject(local, global, object, inits...), nil + return instance.InitializeObject(local, object, inits...), nil } diff --git a/runtime/defining_operators.go b/runtime/defining_operators.go index 8a71fdf..909f037 100644 --- a/runtime/defining_operators.go +++ b/runtime/defining_operators.go @@ -20,15 +20,18 @@ import ( // The result of the evaluation of form is bound to the variable named by name. The binding and // the object created as the result of evaluating the second argument are immutable. The symbol named // name is returned. -func Defconstant(local, global environment.Environment, name, form ilos.Instance) (ilos.Instance, ilos.Instance) { +func Defconstant(local environment.Environment, name, form ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Symbol, name); err != nil { return nil, err } - ret, err := Eval(local, global, form) + if _, ok := TopLevel.Constant.Get(name); ok { + return nil, instance.NewImmutableBinding() + } + ret, err := Eval(local, form) if err != nil { return nil, err } - global.Constant.Define(name, ret) + TopLevel.Constant.Define(name, ret) return name, nil } @@ -40,19 +43,19 @@ func Defconstant(local, global environment.Environment, name, form ilos.Instance // returned. // // A lexical variable binding for name can still be locally established by a binding form; in that -// case, the local binding lexically shadows the outer binding of name defined by defglobal. -func Defglobal(local, global environment.Environment, name, form ilos.Instance) (ilos.Instance, ilos.Instance) { +// case, the local binding lexically shadows the outer binding of name defined by deflocal. +func Defglobal(local environment.Environment, name, form ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Symbol, name); err != nil { return nil, err } - if _, ok := global.Constant.Get(name); ok { + if _, ok := TopLevel.Constant.Get(name); ok { return nil, instance.NewImmutableBinding() } - ret, err := Eval(local, global, form) + ret, err := Eval(local, form) if err != nil { return nil, err } - global.Variable.Define(name, ret) + TopLevel.Variable.Define(name, ret) return name, nil } @@ -60,18 +63,18 @@ func Defglobal(local, global environment.Environment, name, form ilos.Instance) // The scope of name is the entire current toplevel scope except the body form. // //The symbol named name is returned. -func Defdynamic(local, global environment.Environment, name, form ilos.Instance) (ilos.Instance, ilos.Instance) { +func Defdynamic(local environment.Environment, name, form ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Symbol, name); err != nil { return nil, err } - if _, ok := global.Constant.Get(name); ok { + if _, ok := TopLevel.Constant.Get(name); ok { return nil, instance.NewImmutableBinding() } - ret, err := Eval(local, global, form) + ret, err := Eval(local, form) if err != nil { return nil, err } - global.DynamicVariable.Define(name, ret) + TopLevel.DynamicVariable.Define(name, ret) return name, nil } @@ -85,14 +88,14 @@ func Defdynamic(local, global environment.Environment, name, form ilos.Instance) // defun returns the function name which is the symbol named function-name. The free identifiers in // the body form* (i.e., those which are not contained in the lambda list) follow the rules of lexical // scoping. -func Defun(local, global environment.Environment, functionName, lambdaList ilos.Instance, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Defun(local environment.Environment, functionName, lambdaList ilos.Instance, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Symbol, functionName); err != nil { return nil, err } - ret, err := newNamedFunction(local, global, functionName, lambdaList, forms...) + ret, err := newNamedFunction(local, functionName, lambdaList, forms...) if err != nil { return nil, err } - global.Function.Define(functionName, ret) + TopLevel.Function.Define(functionName, ret) return functionName, nil } diff --git a/runtime/dynamic_variables.go b/runtime/dynamic_variables.go index c51aada..df10178 100644 --- a/runtime/dynamic_variables.go +++ b/runtime/dynamic_variables.go @@ -19,14 +19,14 @@ import ( // returned that was established most recently and is still in effect. An // error shall be signaled if such a binding does not exist // (error-id. unbound-variable). -func Dynamic(local, global environment.Environment, var1 ilos.Instance) (ilos.Instance, ilos.Instance) { +func Dynamic(local environment.Environment, var1 ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Symbol, var1); err != nil { return nil, err } if v, ok := local.DynamicVariable.Get(var1); ok { return v, nil } - if v, ok := global.DynamicVariable.Get(var1); ok { + if v, ok := local.DynamicVariable.Get(var1); ok { return v, nil } return nil, instance.NewUndefinedVariable(var1) @@ -41,18 +41,18 @@ func Dynamic(local, global environment.Environment, var1 ilos.Instance) (ilos.In // An error shall be signaled if var has no dynamic value // (error-id. unbound-variable). setf of dynamic can be used only for // modifying bindings, and not for establishing them. -func SetDynamic(local, global environment.Environment, form, var1 ilos.Instance) (ilos.Instance, ilos.Instance) { +func SetDynamic(local environment.Environment, form, var1 ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Symbol, var1); err != nil { return nil, err } - form, err := Eval(local, global, form) + form, err := Eval(local, form) if err != nil { return nil, form } if local.DynamicVariable.Set(var1, form) { return form, nil } - if global.DynamicVariable.Set(var1, form) { + if local.DynamicVariable.Set(var1, form) { return form, nil } return nil, instance.NewUndefinedVariable(var1) @@ -75,7 +75,7 @@ func SetDynamic(local, global environment.Environment, form, var1 ilos.Instance) // returned value of dynamic-let is that of the last body-form of the body (or // nil if there is none). The bindings are undone when control leaves the // prepared dynamic-let special form. -func DynamicLet(local, global environment.Environment, varForm ilos.Instance, bodyForm ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func DynamicLet(local environment.Environment, varForm ilos.Instance, bodyForm ...ilos.Instance) (ilos.Instance, ilos.Instance) { vfs := map[ilos.Instance]ilos.Instance{} if err := ensure(class.List, varForm); err != nil { return nil, err @@ -87,7 +87,7 @@ func DynamicLet(local, global environment.Environment, varForm ilos.Instance, bo if cadr.(instance.List).Length() != 2 { return nil, instance.NewArityError() } - f, err := Eval(local, global, cadr.(instance.List).Nth(1)) + f, err := Eval(local, cadr.(instance.List).Nth(1)) if err != nil { return nil, err } @@ -98,5 +98,5 @@ func DynamicLet(local, global environment.Environment, varForm ilos.Instance, bo return nil, instance.NewImmutableBinding() } } - return Progn(local, global, bodyForm...) + return Progn(local, bodyForm...) } diff --git a/runtime/environment/environment.go b/runtime/environment/environment.go index 5e7e2c8..41f6485 100644 --- a/runtime/environment/environment.go +++ b/runtime/environment/environment.go @@ -57,45 +57,98 @@ func NewEnvironment(stdin, stdout, stderr ilos.Instance) Environment { env.StandardInput = stdin env.StandardOutput = stdout env.ErrorOutput = stderr + env.Handler = NewStack() return *env } func (env *Environment) Merge(before Environment) { - env.Class = append(before.Class, env.Class...) - env.BlockTag = append(before.BlockTag, env.BlockTag...) - env.TagbodyTag = append(before.TagbodyTag, env.TagbodyTag...) - env.CatchTag = append(before.CatchTag, env.CatchTag...) - env.Variable = append(before.Variable, env.Variable...) - env.Function = append(before.Function, env.Function...) - env.Special = append(before.Special, env.Special...) - env.Macro = append(before.Macro, env.Macro...) - env.DynamicVariable = append(before.DynamicVariable, env.DynamicVariable...) - env.Constant = append(before.Constant, env.Constant...) - env.Handler = append(before.Handler, env.Handler...) - env.GensymID = before.GensymID + env.BlockTag = append(before.BlockTag, env.BlockTag[1:]...) + env.TagbodyTag = append(before.TagbodyTag, env.TagbodyTag[1:]...) + env.Variable = append(before.Variable, env.Variable[1:]...) + env.Function = append(before.Function, env.Function[1:]...) + + env.Macro = append(before.Macro, env.Macro[1:]...) + env.Class = append(before.Class, env.Class[1:]...) + env.Special = append(before.Special, env.Special[1:]...) + env.Constant = append(before.Constant, env.Constant[1:]...) env.Property = before.Property + env.GensymID = before.GensymID + + env.CatchTag = append(before.CatchTag, env.CatchTag[1:]...) + env.DynamicVariable = append(before.DynamicVariable, env.DynamicVariable[1:]...) env.StandardInput = before.StandardInput env.StandardOutput = before.StandardOutput env.ErrorOutput = before.ErrorOutput + env.Handler = append(before.Handler, env.Handler[1:]...) } func (env *Environment) MergeDynamic(before Environment) { - env.CatchTag = append(before.CatchTag, env.CatchTag...) - env.DynamicVariable = append(before.DynamicVariable, env.DynamicVariable...) + env.BlockTag = append(stack{before.BlockTag[0]}, env.BlockTag[1:]...) + env.TagbodyTag = append(stack{before.TagbodyTag[0]}, env.TagbodyTag[1:]...) + env.Variable = append(stack{before.Variable[0]}, env.Variable[1:]...) + env.Function = append(stack{before.Function[0]}, env.Function[1:]...) + + env.Macro = append(stack{before.Macro[0]}, env.Macro[1:]...) + env.Class = append(stack{before.Class[0]}, env.Class[1:]...) + env.Special = append(stack{before.Special[0]}, env.Special[1:]...) + env.Constant = append(stack{before.Constant[0]}, env.Constant[1:]...) + env.Property = before.Property + env.GensymID = before.GensymID + + env.CatchTag = append(before.CatchTag, env.CatchTag[1:]...) + env.DynamicVariable = append(before.DynamicVariable, env.DynamicVariable[1:]...) env.StandardInput = before.StandardInput env.StandardOutput = before.StandardOutput env.ErrorOutput = before.ErrorOutput - env.Handler = append(before.Handler, env.Handler...) + env.Handler = append(before.Handler, env.Handler[1:]...) } func Push(before Environment) Environment { env := NewEnvironment(before.StandardInput, before.StandardOutput, before.ErrorOutput) - env.Merge(before) + + env.BlockTag = append(before.BlockTag, env.BlockTag[0]) + env.TagbodyTag = append(before.TagbodyTag, env.TagbodyTag[0]) + env.Variable = append(before.Variable, env.Variable[0]) + env.Function = append(before.Function, env.Function[0]) + + env.Macro = append(before.Macro, env.Macro[0]) + env.Class = append(before.Class, env.Class[0]) + env.Special = append(before.Special, env.Special[0]) + env.Constant = append(before.Constant, env.Constant[0]) + env.Property = before.Property + env.GensymID = before.GensymID + + env.CatchTag = append(before.CatchTag, env.CatchTag[0]) + env.DynamicVariable = append(before.DynamicVariable, env.DynamicVariable[0]) + env.StandardInput = before.StandardInput + env.StandardOutput = before.StandardOutput + env.ErrorOutput = before.ErrorOutput + env.Handler = append(before.Handler, env.Handler[0]) + return env } func PushDynamic(before Environment) Environment { env := NewEnvironment(before.StandardInput, before.StandardOutput, before.ErrorOutput) - env.MergeDynamic(before) + + env.BlockTag = append(stack{before.BlockTag[0]}, env.BlockTag[0]) + env.TagbodyTag = append(stack{before.TagbodyTag[0]}, env.TagbodyTag[0]) + env.Variable = append(stack{before.Variable[0]}, env.Variable[0]) + env.Function = append(stack{before.Function[0]}, env.Function[0]) + + env.Macro = append(stack{before.Macro[0]}, env.Macro[0]) + env.Class = append(stack{before.Class[0]}, env.Class[0]) + env.Special = append(stack{before.Special[0]}, env.Special[0]) + env.Constant = append(stack{before.Constant[0]}, env.Constant[0]) + env.Property = before.Property + env.GensymID = before.GensymID + + env.CatchTag = append(before.CatchTag, env.CatchTag[0]) + env.DynamicVariable = append(before.DynamicVariable, env.DynamicVariable[0]) + env.StandardInput = before.StandardInput + env.StandardOutput = before.StandardOutput + env.ErrorOutput = before.ErrorOutput + env.Handler = append(before.Handler, env.Handler[0]) + return env } diff --git a/runtime/equality.go b/runtime/equality.go index 0b73835..3798118 100644 --- a/runtime/equality.go +++ b/runtime/equality.go @@ -33,7 +33,7 @@ func isComparable(t reflect.Type) bool { // They return t if the objects are the same; otherwise, they return nil. // Two objects are the same if there is no operation that could distinguish // them (without modifying them), and if modifying one would modify the other the same way. -func Eq(local, global environment.Environment, obj1, obj2 ilos.Instance) (ilos.Instance, ilos.Instance) { +func Eq(local environment.Environment, obj1, obj2 ilos.Instance) (ilos.Instance, ilos.Instance) { v1, v2 := reflect.ValueOf(obj1), reflect.ValueOf(obj2) if v1 == v2 || ilos.InstanceOf(class.Symbol, obj1) && ilos.InstanceOf(class.Symbol, obj2) && obj1 == obj2 { return T, nil @@ -45,7 +45,7 @@ func Eq(local, global environment.Environment, obj1, obj2 ilos.Instance) (ilos.I // They return t if the objects are the same; otherwise, they return nil. // Two objects are the same if there is no operation that could distinguish // them (without modifying them), and if modifying one would modify the other the same way. -func Eql(local, global environment.Environment, obj1, obj2 ilos.Instance) (ilos.Instance, ilos.Instance) { +func Eql(local environment.Environment, obj1, obj2 ilos.Instance) (ilos.Instance, ilos.Instance) { t1, t2 := reflect.TypeOf(obj1), reflect.TypeOf(obj2) if isComparable(t1) || isComparable(t2) { if obj1 == obj2 { @@ -65,7 +65,7 @@ func Eql(local, global environment.Environment, obj1, obj2 ilos.Instance) (ilos. // Specifically: // // If obj1 and obj2 are direct instances of the same class, equal returns t if they are eql. -func Equal(local, global environment.Environment, obj1, obj2 ilos.Instance) (ilos.Instance, ilos.Instance) { +func Equal(local environment.Environment, obj1, obj2 ilos.Instance) (ilos.Instance, ilos.Instance) { if reflect.DeepEqual(obj1, obj2) { return T, nil } diff --git a/runtime/eval.go b/runtime/eval.go index e3a39b7..8db2e59 100644 --- a/runtime/eval.go +++ b/runtime/eval.go @@ -5,14 +5,13 @@ package runtime import ( - "github.com/k0kubun/pp" "github.com/ta2gch/iris/runtime/environment" "github.com/ta2gch/iris/runtime/ilos" "github.com/ta2gch/iris/runtime/ilos/class" "github.com/ta2gch/iris/runtime/ilos/instance" ) -func evalArguments(local, global environment.Environment, arguments ilos.Instance) (ilos.Instance, ilos.Instance) { +func evalArguments(local environment.Environment, arguments ilos.Instance) (ilos.Instance, ilos.Instance) { // if arguments ends here if arguments == Nil { return Nil, nil @@ -22,11 +21,11 @@ func evalArguments(local, global environment.Environment, arguments ilos.Instanc } car := arguments.(*instance.Cons).Car // Checked there cdr := arguments.(*instance.Cons).Cdr // Checked there - a, err := Eval(local, global, car) + a, err := Eval(local, car) if err != nil { return nil, err } - b, err := evalArguments(local, global, cdr) + b, err := evalArguments(local, cdr) if err != nil { return nil, err } @@ -34,21 +33,21 @@ func evalArguments(local, global environment.Environment, arguments ilos.Instanc } -func evalLambda(local, global environment.Environment, car, cdr ilos.Instance) (ilos.Instance, ilos.Instance, bool) { +func evalLambda(local environment.Environment, car, cdr ilos.Instance) (ilos.Instance, ilos.Instance, bool) { // eval if lambda form if ilos.InstanceOf(class.Cons, car) { caar := car.(*instance.Cons).Car // Checked at the top of// This sentence if caar == instance.NewSymbol("LAMBDA") { - fun, err := Eval(local, global, car) + fun, err := Eval(local, car) if err != nil { return nil, err, true } - arguments, err := evalArguments(local, global, cdr) + arguments, err := evalArguments(local, cdr) if err != nil { return nil, err, true } - ret, err := fun.(instance.Applicable).Apply(environment.PushDynamic(local), global, arguments.(instance.List).Slice()...) + ret, err := fun.(instance.Applicable).Apply(environment.PushDynamic(local), arguments.(instance.List).Slice()...) if err != nil { return nil, err, true } @@ -58,14 +57,14 @@ func evalLambda(local, global environment.Environment, car, cdr ilos.Instance) ( return nil, nil, false } -func evalSpecial(local, global environment.Environment, car, cdr ilos.Instance) (ilos.Instance, ilos.Instance, bool) { +func evalSpecial(local environment.Environment, car, cdr ilos.Instance) (ilos.Instance, ilos.Instance, bool) { // get special instance has value of Function interface var spl ilos.Instance - if s, ok := global.Special.Get(car); ok { + if s, ok := local.Special.Get(car); ok { spl = s } if spl != nil { - ret, err := spl.(instance.Applicable).Apply(environment.Push(local), global, cdr.(instance.List).Slice()...) + ret, err := spl.(instance.Applicable).Apply(environment.Push(local), cdr.(instance.List).Slice()...) if err != nil { return nil, err, true } @@ -74,21 +73,18 @@ func evalSpecial(local, global environment.Environment, car, cdr ilos.Instance) return nil, nil, false } -func evalMacro(local, global environment.Environment, car, cdr ilos.Instance) (ilos.Instance, ilos.Instance, bool) { +func evalMacro(local environment.Environment, car, cdr ilos.Instance) (ilos.Instance, ilos.Instance, bool) { // get special instance has value of Function interface var mac ilos.Instance if m, ok := local.Macro.Get(car); ok { mac = m } - if m, ok := global.Macro.Get(car); ok { - mac = m - } if mac != nil { - ret, err := mac.(instance.Applicable).Apply(environment.PushDynamic(local), global, cdr.(instance.List).Slice()...) + ret, err := mac.(instance.Applicable).Apply(environment.PushDynamic(local), cdr.(instance.List).Slice()...) if err != nil { return nil, err, true } - ret, err = Eval(local, global, ret) + ret, err = Eval(local, ret) if err != nil { return nil, err, true } @@ -97,21 +93,18 @@ func evalMacro(local, global environment.Environment, car, cdr ilos.Instance) (i return nil, nil, false } -func evalFunction(local, global environment.Environment, car, cdr ilos.Instance) (ilos.Instance, ilos.Instance, bool) { +func evalFunction(local environment.Environment, car, cdr ilos.Instance) (ilos.Instance, ilos.Instance, bool) { // get special instance has value of Function interface var fun ilos.Instance - if f, ok := global.Function.Get(car); ok { - fun = f - } if f, ok := local.Function.Get(car); ok { fun = f } if fun != nil { - arguments, err := evalArguments(local, global, cdr) + arguments, err := evalArguments(local, cdr) if err != nil { return nil, err, true } - ret, err := fun.(instance.Applicable).Apply(environment.PushDynamic(local), global, arguments.(instance.List).Slice()...) + ret, err := fun.(instance.Applicable).Apply(environment.PushDynamic(local), arguments.(instance.List).Slice()...) if err != nil { return nil, err, true } @@ -120,7 +113,7 @@ func evalFunction(local, global environment.Environment, car, cdr ilos.Instance) return nil, nil, false } -func evalCons(local, global environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { +func evalCons(local environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Cons, obj); err != nil { return nil, err } @@ -128,52 +121,48 @@ func evalCons(local, global environment.Environment, obj ilos.Instance) (ilos.In cdr := obj.(*instance.Cons).Cdr // Checked at the top of// This function // eval if lambda form - if a, b, c := evalLambda(local, global, car, cdr); c { + if a, b, c := evalLambda(local, car, cdr); c { return a, b } // get special instance has value of Function interface - if a, b, c := evalSpecial(local, global, car, cdr); c { + if a, b, c := evalSpecial(local, car, cdr); c { return a, b } // get macro instance has value of Function interface - if a, b, c := evalMacro(local, global, car, cdr); c { + if a, b, c := evalMacro(local, car, cdr); c { return a, b } // get function instance has value of Function interface - if a, b, c := evalFunction(local, global, car, cdr); c { + if a, b, c := evalFunction(local, car, cdr); c { return a, b } - pp.Println(global, local) return nil, instance.NewUndefinedFunction(car) } -func evalVariable(local, global environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { +func evalVariable(local environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { if val, ok := local.Variable.Get(obj); ok { return val, nil } - if val, ok := global.Variable.Get(obj); ok { - return val, nil - } - if val, ok := global.Constant.Get(obj); ok { + if val, ok := local.Constant.Get(obj); ok { return val, nil } return nil, instance.NewUndefinedVariable(obj) } // Eval evaluates any classs -func Eval(local, global environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { +func Eval(local environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { if obj == Nil { return Nil, nil } if ilos.InstanceOf(class.Symbol, obj) { - ret, err := evalVariable(local, global, obj) + ret, err := evalVariable(local, obj) if err != nil { return nil, err } return ret, nil } if ilos.InstanceOf(class.Cons, obj) { - ret, err := evalCons(local, global, obj) + ret, err := evalCons(local, obj) if err != nil { return nil, err } diff --git a/runtime/float_class.go b/runtime/float_class.go index e711194..6d4029b 100644 --- a/runtime/float_class.go +++ b/runtime/float_class.go @@ -25,7 +25,7 @@ var ( // Floatp returns t if obj is a float (instance of class float); // otherwise, returns nil. The obj may be any ISLISP object. -func Floatp(local, global environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { +func Floatp(local environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { if ilos.InstanceOf(class.Float, obj) { return T, nil } @@ -35,7 +35,7 @@ func Floatp(local, global environment.Environment, obj ilos.Instance) (ilos.Inst // Float returns x itself if it is an instance of the class float // and returns a floating-point approximation of x otherwise. // An error shall be signaled if x is not a number (error-id. domain-error). -func Float(local, global environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { +func Float(local environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { f, _, err := convFloat64(x) if err != nil { return nil, err @@ -46,7 +46,7 @@ func Float(local, global environment.Environment, x ilos.Instance) (ilos.Instanc // Floor returns the greatest integer less than or equal to x . // That is, x is truncated towards negative infinity. An error // shall be signaled if x is not a number (error-id. domain-error). -func Floor(local, global environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { +func Floor(local environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { f, _, err := convFloat64(x) if err != nil { return nil, err @@ -57,7 +57,7 @@ func Floor(local, global environment.Environment, x ilos.Instance) (ilos.Instanc // Ceiling Returns the smallest integer that is not smaller than x. // That is, x is truncated towards positive infinity. An error // shall be signaled if x is not a number (error-id. domain-error). -func Ceiling(local, global environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { +func Ceiling(local environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { f, _, err := convFloat64(x) if err != nil { return nil, err @@ -68,7 +68,7 @@ func Ceiling(local, global environment.Environment, x ilos.Instance) (ilos.Insta // Truncate returns the integer between 0 and x (inclusive) that is nearest to x. // That is, x is truncated towards zero. An error shall be signaled // if x is not a number (error-id. domain-error). -func Truncate(local, global environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { +func Truncate(local environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { f, _, err := convFloat64(x) if err != nil { return nil, err @@ -79,7 +79,7 @@ func Truncate(local, global environment.Environment, x ilos.Instance) (ilos.Inst // Round returns the integer nearest to x. // If x is exactly halfway between two integers, the even one is chosen. // An error shall be signaled if x is not a number (error-id. domain-error). -func Round(local, global environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { +func Round(local environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { f, _, err := convFloat64(x) if err != nil { return nil, err diff --git a/runtime/functions.go b/runtime/functions.go index d4ea5a1..150225d 100644 --- a/runtime/functions.go +++ b/runtime/functions.go @@ -19,7 +19,7 @@ import ( // A function binding is an association between an identifier, function-name, // and a function object that is denoted by function-name—if in operator // position—or by (function function-name) elsewhere. -func Functionp(local, global environment.Environment, fun ilos.Instance) (ilos.Instance, ilos.Instance) { +func Functionp(local environment.Environment, fun ilos.Instance) (ilos.Instance, ilos.Instance) { if ilos.InstanceOf(class.Function, fun) { return T, nil } @@ -31,12 +31,12 @@ func Functionp(local, global environment.Environment, fun ilos.Instance) (ilos.I // An error shall be signaled if no binding has been established for the identifier // in the function namespace of current lexical environment (error-id. undefined-function). // The consequences are undefined if the function-name names a macro or special form -func Function(local, global environment.Environment, fun ilos.Instance) (ilos.Instance, ilos.Instance) { +func Function(local environment.Environment, fun ilos.Instance) (ilos.Instance, ilos.Instance) { // car must be a symbol if err := ensure(class.Symbol, fun); err != nil { return nil, err } - if f, ok := global.Function.Get(fun); ok { + if f, ok := local.Function.Get(fun); ok { return f, nil } if f, ok := local.Function.Get(fun); ok { @@ -69,11 +69,11 @@ func Function(local, global environment.Environment, fun ilos.Instance) (ilos.In // was called with apply and R corresponds to the final argument, L2 , to that call // to apply (or some subtail of L2), in which case it is implementation defined whether // L1 shares structure with L2 . -func Lambda(local, global environment.Environment, lambdaList ilos.Instance, form ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Lambda(local environment.Environment, lambdaList ilos.Instance, form ...ilos.Instance) (ilos.Instance, ilos.Instance) { if err := checkLambdaList(lambdaList); err != nil { return nil, err } - return newNamedFunction(local, global, instance.NewSymbol("ANONYMOUS-FUNCTION"), lambdaList, form...) + return newNamedFunction(local, instance.NewSymbol("ANONYMOUS-FUNCTION"), lambdaList, form...) } // Labels special form allow the definition of new identifiers in the function @@ -99,7 +99,7 @@ func Lambda(local, global environment.Environment, lambdaList ilos.Instance, for // (or nil if there is none) is the value returned by the special form activation. // // No function-name may appear more than once in the function bindings. -func Labels(local, global environment.Environment, functions ilos.Instance, bodyForm ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Labels(local environment.Environment, functions ilos.Instance, bodyForm ...ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.List, functions); err != nil { return nil, err } @@ -114,7 +114,7 @@ func Labels(local, global environment.Environment, functions ilos.Instance, body functionName := definition[0] lambdaList := definition[1] forms := definition[2:] - fun, err := newNamedFunction(local, global, functionName, lambdaList, forms...) + fun, err := newNamedFunction(local, functionName, lambdaList, forms...) if err != nil { return nil, err } @@ -122,12 +122,12 @@ func Labels(local, global environment.Environment, functions ilos.Instance, body return nil, instance.NewImmutableBinding() } } - return Progn(local, global, bodyForm...) + return Progn(local, bodyForm...) } // Flet special form allow the definition of new identifiers in the function // namespace for function objects (see Labels). -func Flet(local, global environment.Environment, functions ilos.Instance, bodyForm ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Flet(local environment.Environment, functions ilos.Instance, bodyForm ...ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.List, functions); err != nil { return nil, err } @@ -143,7 +143,7 @@ func Flet(local, global environment.Environment, functions ilos.Instance, bodyFo functionName := definition[0] lambdaList := definition[1] forms := definition[2:] - fun, err := newNamedFunction(local, global, functionName, lambdaList, forms...) + fun, err := newNamedFunction(local, functionName, lambdaList, forms...) if err != nil { return nil, err } @@ -151,7 +151,7 @@ func Flet(local, global environment.Environment, functions ilos.Instance, bodyFo return nil, instance.NewImmutableBinding() } } - return Progn(env, global, bodyForm...) + return Progn(env, bodyForm...) } // Apply applies function to the arguments, obj*, followed by the elements of list, @@ -160,7 +160,7 @@ func Flet(local, global environment.Environment, functions ilos.Instance, bodyFo // An error shall be signaled if function is not a function (error-id. domain-error). // Each obj may be any ISLISP object. An error shall be signaled // if list is not a proper list (error-id. improper-argument-list). -func Apply(local, global environment.Environment, function ilos.Instance, obj ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Apply(local environment.Environment, function ilos.Instance, obj ...ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Function, function); err != nil { return nil, err } @@ -168,7 +168,7 @@ func Apply(local, global environment.Environment, function ilos.Instance, obj .. return nil, err } obj = append(obj[:len(obj)-1], obj[len(obj)-1].(instance.List).Slice()...) - return function.(instance.Applicable).Apply(local, global, obj...) + return function.(instance.Applicable).Apply(local, obj...) } // Funcall activates the specified function function and returns the value that the function returns. @@ -176,7 +176,7 @@ func Apply(local, global environment.Environment, function ilos.Instance, obj .. // // An error shall be signaled if function is not a function (error-id. domain-error). // Each obj may be any ISLISP object. -func Funcall(local, global environment.Environment, function ilos.Instance, obj ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Funcall(local environment.Environment, function ilos.Instance, obj ...ilos.Instance) (ilos.Instance, ilos.Instance) { obj = append(obj, Nil) - return Apply(local, global, function, obj...) + return Apply(local, function, obj...) } diff --git a/runtime/functions_test.go b/runtime/functions_test.go index 2349b51..a38d4f4 100644 --- a/runtime/functions_test.go +++ b/runtime/functions_test.go @@ -104,7 +104,14 @@ func TestLabels(t *testing.T) { func TestFlet(t *testing.T) { defun2("+", Add) defspecial(Flet) + defspecial(Defun) + defspecial(Quote) tests := []test{ + { + exp: `(defun f (x) 0)`, + want: `'f`, + wantErr: false, + }, { exp: ` (flet ((f (x) (+ x 3))) diff --git a/runtime/generic_functions.go b/runtime/generic_functions.go index bcaf042..4a28d0a 100644 --- a/runtime/generic_functions.go +++ b/runtime/generic_functions.go @@ -11,7 +11,7 @@ import ( "github.com/ta2gch/iris/runtime/ilos/instance" ) -func Defmethod(local, global environment.Environment, arguments ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Defmethod(local environment.Environment, arguments ...ilos.Instance) (ilos.Instance, ilos.Instance) { if len(arguments) < 2 { return nil, instance.NewArityError() } @@ -30,7 +30,7 @@ func Defmethod(local, global environment.Environment, arguments ...ilos.Instance parameterList = append(parameterList, pp.(instance.List).Nth(0)) } } - lambdaList, err := List(local, global, parameterList...) + lambdaList, err := List(local, parameterList...) if err != nil { return nil, err } @@ -42,18 +42,18 @@ func Defmethod(local, global environment.Environment, arguments ...ilos.Instance if ilos.InstanceOf(class.Symbol, pp) { classList = append(classList, class.Object) } else { - class, ok := global.Class.Get(pp.(instance.List).Nth(1)) + class, ok := TopLevel.Class.Get(pp.(instance.List).Nth(1)) if !ok { return nil, instance.NewUndefinedClass(pp.(instance.List).Nth(1)) } classList = append(classList, class.(ilos.Class)) } } - fun, err := newNamedFunction(local, global, name, lambdaList, arguments[i+2:]...) + fun, err := newNamedFunction(local, name, lambdaList, arguments[i+2:]...) if err != nil { return nil, err } - gen, ok := global.Function.Get(name) + gen, ok := TopLevel.Function.Get(name) if !ok { return nil, instance.NewUndefinedFunction(name) } @@ -63,7 +63,7 @@ func Defmethod(local, global environment.Environment, arguments ...ilos.Instance return name, nil } -func Defgeneric(local, global environment.Environment, funcSpec, lambdaList ilos.Instance, optionsOrMethodDescs ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Defgeneric(local environment.Environment, funcSpec, lambdaList ilos.Instance, optionsOrMethodDescs ...ilos.Instance) (ilos.Instance, ilos.Instance) { var methodCombination ilos.Instance genericFunctionClass := class.StandardGenericFunction forms := []ilos.Instance{} @@ -72,7 +72,7 @@ func Defgeneric(local, global environment.Environment, funcSpec, lambdaList ilos case instance.NewSymbol(":METHOD-COMBINATION"): methodCombination = optionOrMethodDesc.(instance.List).Nth(1) case instance.NewSymbol(":GENERIC-FUNCTION-CLASS"): - class, ok := global.Class.Get(optionOrMethodDesc.(instance.List).Nth(1)) + class, ok := TopLevel.Class.Get(optionOrMethodDesc.(instance.List).Nth(1)) if !ok { return nil, instance.NewUndefinedClass(optionOrMethodDesc.(instance.List).Nth(1)) } @@ -81,7 +81,7 @@ func Defgeneric(local, global environment.Environment, funcSpec, lambdaList ilos forms = append(forms, instance.NewCons(instance.NewSymbol("DEFMETHOD"), optionOrMethodDesc.(instance.List).NthCdr(1))) } } - global.Function.Define(funcSpec, instance.NewGenericFunction(funcSpec, lambdaList, methodCombination, genericFunctionClass)) - Progn(local, global, forms...) + TopLevel.Function.Define(funcSpec, instance.NewGenericFunction(funcSpec, lambdaList, methodCombination, genericFunctionClass)) + Progn(local, forms...) return funcSpec, nil } diff --git a/runtime/ilos/instance/error.go b/runtime/ilos/instance/error.go index 8080ccd..24044fc 100644 --- a/runtime/ilos/instance/error.go +++ b/runtime/ilos/instance/error.go @@ -13,8 +13,6 @@ import ( "github.com/ta2gch/iris/runtime/ilos" ) -var dummyEnv = *new(environment.Environment) // All class in ilos/instance has no initform, so it will not call apply - func stackTrace() { println("----") programCounter, sourceFileName, sourceFileLineNum, ok := runtime.Caller(2) @@ -37,28 +35,28 @@ func stackTrace() { } func NewArithmeticError(operation, operands ilos.Instance) ilos.Instance { - return Create(dummyEnv, dummyEnv, + return Create(environment.NewEnvironment(nil, nil, nil), ArithmeticErrorClass, NewSymbol("OPERATION"), operation, NewSymbol("OPERANDS"), operands) } func NewDivisionByZero(operation, operands ilos.Instance) ilos.Instance { - return Create(dummyEnv, dummyEnv, + return Create(environment.NewEnvironment(nil, nil, nil), DivisionByZeroClass, NewSymbol("OPERATION"), operation, NewSymbol("OPERANDS"), operands) } func NewParseError(str, expectedClass ilos.Instance) ilos.Instance { - return Create(dummyEnv, dummyEnv, + return Create(environment.NewEnvironment(nil, nil, nil), ParseErrorClass, NewSymbol("STRING"), str, NewSymbol("EXPECTED-CLASS"), expectedClass) } func NewDomainError(object ilos.Instance, expectedClass ilos.Class) ilos.Instance { - return Create(dummyEnv, dummyEnv, + return Create(environment.NewEnvironment(nil, nil, nil), DomainErrorClass, NewSymbol("CAUSE"), NewSymbol("DOMAIN-ERROR"), NewSymbol("OBJECT"), object, @@ -66,45 +64,48 @@ func NewDomainError(object ilos.Instance, expectedClass ilos.Class) ilos.Instanc } func NewUndefinedFunction(name ilos.Instance) ilos.Instance { - return Create(dummyEnv, dummyEnv, + return Create(environment.NewEnvironment(nil, nil, nil), UndefinedFunctionClass, NewSymbol("NAME"), name, NewSymbol("NAMESPACE"), NewSymbol("FUNCTION")) } func NewUndefinedVariable(name ilos.Instance) ilos.Instance { - return Create(dummyEnv, dummyEnv, + return Create(environment.NewEnvironment(nil, nil, nil), UndefinedVariableClass, NewSymbol("NAME"), name, NewSymbol("NAMESPACE"), NewSymbol("VARIABLE")) } func NewUndefinedClass(name ilos.Instance) ilos.Instance { - return Create(dummyEnv, dummyEnv, + return Create(environment.NewEnvironment(nil, nil, nil), UndefinedEntityClass, NewSymbol("NAME"), name, NewSymbol("NAMESPACE"), NewSymbol("CLASS")) } func NewArityError() ilos.Instance { - return Create(dummyEnv, dummyEnv, ProgramErrorClass) + stackTrace() + return Create(environment.NewEnvironment(nil, nil, nil), ProgramErrorClass) } func NewIndexOutOfRange() ilos.Instance { - return Create(dummyEnv, dummyEnv, ProgramErrorClass) + stackTrace() + return Create(environment.NewEnvironment(nil, nil, nil), ProgramErrorClass) } func NewImmutableBinding() ilos.Instance { - return Create(dummyEnv, dummyEnv, ProgramErrorClass) + stackTrace() + return Create(environment.NewEnvironment(nil, nil, nil), ProgramErrorClass) } func NewSimpleError(formatString, formatArguments ilos.Instance) ilos.Instance { - return Create(dummyEnv, dummyEnv, + return Create(environment.NewEnvironment(nil, nil, nil), SimpleErrorClass, NewSymbol("FORMAT-STRING"), formatString, NewSymbol("FORMAT-ARGUMENTS"), formatArguments) } func NewControlError() ilos.Instance { - return Create(dummyEnv, dummyEnv, ControlErrorClass) + return Create(environment.NewEnvironment(nil, nil, nil), ControlErrorClass) } diff --git a/runtime/ilos/instance/function.go b/runtime/ilos/instance/function.go index fc2e4ae..570b86d 100644 --- a/runtime/ilos/instance/function.go +++ b/runtime/ilos/instance/function.go @@ -14,7 +14,7 @@ import ( ) type Applicable interface { - Apply(environment.Environment, environment.Environment, ...ilos.Instance) (ilos.Instance, ilos.Instance) + Apply(environment.Environment, ...ilos.Instance) (ilos.Instance, ilos.Instance) } type Function struct { @@ -34,10 +34,10 @@ func (f Function) String() string { return fmt.Sprintf("#%v", f.Class()) } -func (f Function) Apply(local, global environment.Environment, arguments ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func (f Function) Apply(local environment.Environment, arguments ...ilos.Instance) (ilos.Instance, ilos.Instance) { fv := reflect.ValueOf(f.function) ft := reflect.TypeOf(f.function) - argv := []reflect.Value{reflect.ValueOf(local), reflect.ValueOf(global)} + argv := []reflect.Value{reflect.ValueOf(local)} for _, cadr := range arguments { argv = append(argv, reflect.ValueOf(cadr)) } @@ -98,7 +98,7 @@ func (f *GenericFunction) String() string { return fmt.Sprintf("#%v", f.Class()) } -func (f *GenericFunction) Apply(local, global environment.Environment, arguments ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func (f *GenericFunction) Apply(local environment.Environment, arguments ...ilos.Instance) (ilos.Instance, ilos.Instance) { parameters := f.lambdaList.(List).Slice() variadic := false { @@ -139,15 +139,15 @@ func (f *GenericFunction) Apply(local, global environment.Environment, arguments return t[methods[a].qualifier] > t[methods[b].qualifier] }) - nextMethodPisNil := NewFunction(NewSymbol("NEXT-METHOD-P"), func(local, global environment.Environment) (ilos.Instance, ilos.Instance) { + nextMethodPisNil := NewFunction(NewSymbol("NEXT-METHOD-P"), func(local environment.Environment) (ilos.Instance, ilos.Instance) { return Nil, nil }) - nextMethodPisT := NewFunction(NewSymbol("NEXT-METHOD-P"), func(local, global environment.Environment) (ilos.Instance, ilos.Instance) { + nextMethodPisT := NewFunction(NewSymbol("NEXT-METHOD-P"), func(local environment.Environment) (ilos.Instance, ilos.Instance) { return T, nil }) if f.methodCombination == NewSymbol("NIL") { - var callNextMethod func(local, global environment.Environment) (ilos.Instance, ilos.Instance) // To Recursive - callNextMethod = func(local, global environment.Environment) (ilos.Instance, ilos.Instance) { // CALL-NEXT-METHOD + var callNextMethod func(local environment.Environment) (ilos.Instance, ilos.Instance) // To Recursive + callNextMethod = func(local environment.Environment) (ilos.Instance, ilos.Instance) { // CALL-NEXT-METHOD depth, _ := local.DynamicVariable.Get(NewSymbol("IRIS/DEPTH")) // Get previous depth index := int(depth.(Integer)) + 1 // Get index of next method local.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) // Set current depth @@ -157,7 +157,7 @@ func (f *GenericFunction) Apply(local, global environment.Environment, arguments local.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) local.Function.Define(NewSymbol("NEXT-METHOD-P"), NewFunction(NewSymbol("NEXT-METHOD-P"), nextMethodPisT)) } - return methods[index].function.Apply(local, global, arguments...) // Call next method + return methods[index].function.Apply(local, arguments...) // Call next method } local.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(0)) // Set current depth // If Generic Function has no next-mehtods, NEXT-METHOD-P local function returns nil @@ -166,7 +166,7 @@ func (f *GenericFunction) Apply(local, global environment.Environment, arguments local.Function.Define(NewSymbol("NEXT-METHOD-P"), NewFunction(NewSymbol("NEXT-METHOD-P"), nextMethodPisT)) local.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } - return methods[0].function.Apply(local, global, arguments...) //Call first of method + return methods[0].function.Apply(local, arguments...) //Call first of method } // if f.methodCombination == NewSymbol("STANDARD") { @@ -174,8 +174,8 @@ func (f *GenericFunction) Apply(local, global environment.Environment, arguments width := len(methods) if index := sort.Search(width, test); index < width { // if has :around methods // This callNextMethod is called in :around methods - var callNextMethod func(local, global environment.Environment) (ilos.Instance, ilos.Instance) - callNextMethod = func(local, global environment.Environment) (ilos.Instance, ilos.Instance) { + var callNextMethod func(local environment.Environment) (ilos.Instance, ilos.Instance) + callNextMethod = func(local environment.Environment) (ilos.Instance, ilos.Instance) { depth, _ := local.DynamicVariable.Get(NewSymbol("IRIS/DEPTH")) // Get previous depth for index, method := range methods[:int(depth.(Integer))+1] { if method.qualifier == around { // If have :around method @@ -190,22 +190,22 @@ func (f *GenericFunction) Apply(local, global environment.Environment, arguments local.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } } - return methods[int(depth.(Integer))].function.Apply(local, global, arguments...) // Call next method + return methods[int(depth.(Integer))].function.Apply(local, arguments...) // Call next method } } // If has no :around method then, // Do All :before mehtods for _, method := range methods { if method.qualifier == before { - if _, err := method.function.Apply(local, global, arguments...); err != nil { + if _, err := method.function.Apply(local, arguments...); err != nil { return nil, err } } } // Do the first of primary methods // this callNextMethod is called in primary methods - var callNextMethod func(local, global environment.Environment) (ilos.Instance, ilos.Instance) - callNextMethod = func(local, global environment.Environment) (ilos.Instance, ilos.Instance) { + var callNextMethod func(local environment.Environment) (ilos.Instance, ilos.Instance) + callNextMethod = func(local environment.Environment) (ilos.Instance, ilos.Instance) { depth, _ := local.DynamicVariable.Get(NewSymbol("IRIS/DEPTH")) // Get previous depth index := int(depth.(Integer)) // Convert depth to integer { @@ -224,7 +224,7 @@ func (f *GenericFunction) Apply(local, global environment.Environment, arguments local.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } } - return methods[index].function.Apply(local, global, arguments...) // Call next method + return methods[index].function.Apply(local, arguments...) // Call next method } // callNextMethod ends here index := 0 // index of the first primary method { // index != 0 is always true because this function has :around methods @@ -244,14 +244,14 @@ func (f *GenericFunction) Apply(local, global environment.Environment, arguments } } // Do primary methods - ret, err := methods[index].function.Apply(local, global, arguments...) + ret, err := methods[index].function.Apply(local, arguments...) if err != nil { return nil, err } // Do all :after methods for i := len(methods) - 1; i >= 0; i-- { if methods[i].qualifier == after { - if _, err := methods[i].function.Apply(local, global, arguments...); err != nil { + if _, err := methods[i].function.Apply(local, arguments...); err != nil { return nil, err } } @@ -269,13 +269,13 @@ func (f *GenericFunction) Apply(local, global environment.Environment, arguments local.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } } - return methods[index].function.Apply(local, global, arguments...) + return methods[index].function.Apply(local, arguments...) } } { // Function has no :around methods // This callNextMethod is called in primary methods - var callNextMethod func(local, global environment.Environment) (ilos.Instance, ilos.Instance) - callNextMethod = func(local, global environment.Environment) (ilos.Instance, ilos.Instance) { + var callNextMethod func(local environment.Environment) (ilos.Instance, ilos.Instance) + callNextMethod = func(local environment.Environment) (ilos.Instance, ilos.Instance) { depth, _ := local.DynamicVariable.Get(NewSymbol("IRIS/DEPTH")) // Get previous depth index := int(depth.(Integer)) // Convert depth to integer { @@ -294,12 +294,12 @@ func (f *GenericFunction) Apply(local, global environment.Environment, arguments local.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } } - return methods[int(depth.(Integer))].function.Apply(local, global, arguments...) + return methods[int(depth.(Integer))].function.Apply(local, arguments...) } // callNextMethod ends here // Do All :before mehtods for _, method := range methods { if method.qualifier == before { - if _, err := method.function.Apply(local, global, arguments...); err != nil { + if _, err := method.function.Apply(local, arguments...); err != nil { return nil, err } } @@ -323,11 +323,11 @@ func (f *GenericFunction) Apply(local, global environment.Environment, arguments local.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } } - ret, err := methods[index].function.Apply(local, global, arguments...) + ret, err := methods[index].function.Apply(local, arguments...) // Do all :after methods for i := len(methods) - 1; i >= 0; i-- { if methods[i].qualifier == after { - if _, err := methods[i].function.Apply(local, global, arguments...); err != nil { + if _, err := methods[i].function.Apply(local, arguments...); err != nil { return nil, err } } diff --git a/runtime/ilos/instance/instance.go b/runtime/ilos/instance/instance.go index fab2132..d602676 100644 --- a/runtime/ilos/instance/instance.go +++ b/runtime/ilos/instance/instance.go @@ -16,17 +16,17 @@ import ( // instance // -func Create(local, global environment.Environment, c ilos.Instance, i ...ilos.Instance) ilos.Instance { +func Create(local environment.Environment, c ilos.Instance, i ...ilos.Instance) ilos.Instance { p := []ilos.Instance{} for _, q := range c.(ilos.Class).Supers() { - p = append(p, Create(local, global, q, i...)) + p = append(p, Create(local, q, i...)) } - return InitializeObject(local, global, Instance{c.(ilos.Class), p, map[ilos.Instance]ilos.Instance{}}, i...) + return InitializeObject(local, Instance{c.(ilos.Class), p, map[ilos.Instance]ilos.Instance{}}, i...) } -func InitializeObject(local, global environment.Environment, object ilos.Instance, inits ...ilos.Instance) ilos.Instance { +func InitializeObject(local environment.Environment, object ilos.Instance, inits ...ilos.Instance) ilos.Instance { for _, super := range object.(Instance).supers { - InitializeObject(local, global, super, inits...) + InitializeObject(local, super, inits...) } for i := 0; i < len(inits); i += 2 { argName := inits[i] @@ -43,7 +43,7 @@ func InitializeObject(local, global environment.Environment, object ilos.Instanc for _, slotName := range object.Class().Slots() { if _, ok := object.(Instance).GetSlotValue(slotName, object.Class()); !ok { if form, ok := object.Class().Initform(slotName); ok { - value, _ := form.(Applicable).Apply(local, global) + value, _ := form.(Applicable).Apply(local) object.(Instance).SetSlotValue(slotName, value, object.Class()) } } diff --git a/runtime/ilos/instance/tag.go b/runtime/ilos/instance/tag.go index 6e08ffd..a27ac22 100644 --- a/runtime/ilos/instance/tag.go +++ b/runtime/ilos/instance/tag.go @@ -5,21 +5,22 @@ package instance import ( + "github.com/ta2gch/iris/runtime/environment" "github.com/ta2gch/iris/runtime/ilos" ) func NewBlockTag(tag, object ilos.Instance) ilos.Instance { - return Create(dummyEnv, dummyEnv, + return Create(environment.NewEnvironment(nil, nil, nil), BlockTagClass, NewSymbol("TAG"), tag, NewSymbol("OBJECT"), object) } func NewCatchTag(tag, object ilos.Instance) ilos.Instance { - return Create(dummyEnv, dummyEnv, + return Create(environment.NewEnvironment(nil, nil, nil), CatchTagClass, NewSymbol("TAG"), tag, NewSymbol("OBJECT"), object) } func NewTagbodyTag(tag ilos.Instance) ilos.Instance { - return Create(dummyEnv, dummyEnv, TagbodyTagClass, NewSymbol("TAG"), tag) + return Create(environment.NewEnvironment(nil, nil, nil), TagbodyTagClass, NewSymbol("TAG"), tag) } diff --git a/runtime/integer_class.go b/runtime/integer_class.go index 929c9de..2a97d8a 100644 --- a/runtime/integer_class.go +++ b/runtime/integer_class.go @@ -22,7 +22,7 @@ func convInt(z ilos.Instance) (int, ilos.Instance) { // Integerp returns t if obj is an integer (instance of class integer); // otherwise, returns nil. obj may be any ISLISP object. -func Integerp(local, global environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { +func Integerp(local environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { if ilos.InstanceOf(class.Integer, obj) { return T, nil } @@ -31,7 +31,7 @@ func Integerp(local, global environment.Environment, obj ilos.Instance) (ilos.In // Div returns the greatest integer less than or equal to the quotient of z1 and z2. // An error shall be signaled if z2 is zero (error-id. division-by-zero). -func Div(local, global environment.Environment, z1, z2 ilos.Instance) (ilos.Instance, ilos.Instance) { +func Div(local environment.Environment, z1, z2 ilos.Instance) (ilos.Instance, ilos.Instance) { a, err := convInt(z1) if err != nil { return nil, err @@ -42,7 +42,7 @@ func Div(local, global environment.Environment, z1, z2 ilos.Instance) (ilos.Inst } if b == 0 { operation := instance.NewSymbol("DIV") - operands, err := List(local, global, z1, z2) + operands, err := List(local, z1, z2) if err != nil { return nil, err } @@ -57,7 +57,7 @@ func Div(local, global environment.Environment, z1, z2 ilos.Instance) (ilos.Inst // and this result is divisible by z2 without remainder. // // An error shall be signaled if either z1 or z2 is not an integer (error-id. domain-error). -func Mod(local, global environment.Environment, z1, z2 ilos.Instance) (ilos.Instance, ilos.Instance) { +func Mod(local environment.Environment, z1, z2 ilos.Instance) (ilos.Instance, ilos.Instance) { a, err := convInt(z1) if err != nil { return nil, err @@ -68,7 +68,7 @@ func Mod(local, global environment.Environment, z1, z2 ilos.Instance) (ilos.Inst } if b == 0 { operation := instance.NewSymbol("MOD") - operands, err := List(local, global, z1, z2) + operands, err := List(local, z1, z2) if err != nil { return nil, err } @@ -84,7 +84,7 @@ func Mod(local, global environment.Environment, z1, z2 ilos.Instance) (ilos.Inst // // An error shall be signaled if either z1 or z2 is not an integer // (error-id. domain-error). -func Gcd(local, global environment.Environment, z1, z2 ilos.Instance) (ilos.Instance, ilos.Instance) { +func Gcd(local environment.Environment, z1, z2 ilos.Instance) (ilos.Instance, ilos.Instance) { gcd := func(x, y int) int { for y != 0 { x, y = y, x%y @@ -106,7 +106,7 @@ func Gcd(local, global environment.Environment, z1, z2 ilos.Instance) (ilos.Inst // // An error shall be signaled if either z1 or z2 is not an integer // (error-id. domain-error). -func Lcm(local, global environment.Environment, z1, z2 ilos.Instance) (ilos.Instance, ilos.Instance) { +func Lcm(local environment.Environment, z1, z2 ilos.Instance) (ilos.Instance, ilos.Instance) { gcd := func(x, y int) int { for y != 0 { x, y = y, x%y @@ -127,7 +127,7 @@ func Lcm(local, global environment.Environment, z1, z2 ilos.Instance) (ilos.Inst // Isqrt Returns the greatest integer less than or equal to // the exact positive square root of z . An error shall be signaled // if z is not a non-negative integer (error-id. domain-error). -func Isqrt(local, global environment.Environment, z ilos.Instance) (ilos.Instance, ilos.Instance) { +func Isqrt(local environment.Environment, z ilos.Instance) (ilos.Instance, ilos.Instance) { a, err := convInt(z) if err != nil { return nil, err diff --git a/runtime/iteration.go b/runtime/iteration.go index 5f491ca..a51ced4 100644 --- a/runtime/iteration.go +++ b/runtime/iteration.go @@ -20,17 +20,17 @@ import ( // 3. Otherwise, if Vt is non-nil, the forms body-form* are evaluated sequentially (from left to right). // // 4. Upon successful completion of the body-forms*, the while form begins again with step 1. -func While(local, global environment.Environment, testForm ilos.Instance, bodyForm ...ilos.Instance) (ilos.Instance, ilos.Instance) { - test, err := Eval(local, global, testForm) +func While(local environment.Environment, testForm ilos.Instance, bodyForm ...ilos.Instance) (ilos.Instance, ilos.Instance) { + test, err := Eval(local, testForm) if err != nil { return nil, err } for test == T { - _, err := Progn(local, global, bodyForm...) + _, err := Progn(local, bodyForm...) if err != nil { return nil, err } - test, err = Eval(local, global, testForm) + test, err = Eval(local, testForm) if err != nil { return nil, err } @@ -55,7 +55,7 @@ func While(local, global environment.Environment, testForm ilos.Instance, bodyFo // order from left to right. Then their values are assigned to the corresponding variables and the next iteration begins. // If end-test returns a non-nil value, then the result * are evaluated sequentially and the value of the // last one is returned as value of the whole for macro. If no result is present, then the value of the for macro is nil. -func For(local, global environment.Environment, iterationSpecs, endTestAndResults ilos.Instance, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func For(local environment.Environment, iterationSpecs, endTestAndResults ilos.Instance, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.List, iterationSpecs); err != nil { return nil, err } @@ -84,12 +84,12 @@ func For(local, global environment.Environment, iterationSpecs, endTestAndResult } endTest := ends[0] results := ends[1:] - test, err := Eval(local, global, endTest) + test, err := Eval(local, endTest) if err != nil { return nil, err } for test == Nil { - _, err := Progn(local, global, forms...) + _, err := Progn(local, forms...) if err != nil { return nil, err } @@ -109,10 +109,10 @@ func For(local, global environment.Environment, iterationSpecs, endTestAndResult return nil, instance.NewArityError() } } - test, err = Eval(local, global, endTest) + test, err = Eval(local, endTest) if err != nil { return nil, err } } - return Progn(local, global, results...) + return Progn(local, results...) } diff --git a/runtime/list_operations.go b/runtime/list_operations.go index fa95079..59808c0 100644 --- a/runtime/list_operations.go +++ b/runtime/list_operations.go @@ -15,7 +15,7 @@ import ( // Listp returns t if obj is a list (instance of class list); otherwise, returns nil. // obj may be any ISLISP object. -func Listp(local, global environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { +func Listp(local environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { if ilos.InstanceOf(class.Cons, obj) { return T, nil } @@ -27,7 +27,7 @@ func Listp(local, global environment.Environment, obj ilos.Instance) (ilos.Insta // error shall be signaled if the requested list cannot be allocated (error-id. cannot-create-list). // An error shall be signaled if i is not a non-negative integer (error-id. domain-error). //initial-element may be any ISLISP object. -func CreateList(local, global environment.Environment, i ilos.Instance, initialElement ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func CreateList(local environment.Environment, i ilos.Instance, initialElement ...ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Integer, i); err != nil { return nil, err } @@ -48,7 +48,7 @@ func CreateList(local, global environment.Environment, i ilos.Instance, initialE // List returns a new list whose length is the number of arguments and whose elements are the // arguments in the same order as in the list-form. An error shall be signaled if the requested list // cannot be allocated (error-id. cannot-create-list). Each obj may be any ISLISP object. -func List(local, global environment.Environment, objs ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func List(local environment.Environment, objs ...ilos.Instance) (ilos.Instance, ilos.Instance) { cons := Nil for i := len(objs) - 1; i >= 0; i-- { cons = instance.NewCons(objs[i], cons) @@ -61,7 +61,7 @@ func List(local, global environment.Environment, objs ...ilos.Instance) (ilos.In // // For reverse, no side-effect to the given list occurs. The resulting list is permitted but not // required to share structure with the input list. -func Reverse(local, global environment.Environment, list ilos.Instance) (ilos.Instance, ilos.Instance) { +func Reverse(local environment.Environment, list ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.List, list); err != nil { return nil, err } @@ -78,7 +78,7 @@ func Reverse(local, global environment.Environment, list ilos.Instance) (ilos.In // For nreverse, the conses which make up the top level of the given list are permitted, but not // required, to be side-effected in order to produce this new list. nreverse should never be called // on a literal object. -func Nreverse(local, global environment.Environment, list ilos.Instance) (ilos.Instance, ilos.Instance) { +func Nreverse(local environment.Environment, list ilos.Instance) (ilos.Instance, ilos.Instance) { // TODO: tests literal object if err := ensure(class.List, list); err != nil { return nil, err @@ -97,10 +97,10 @@ func Nreverse(local, global environment.Environment, list ilos.Instance) (ilos.I // result shares structure with its list arguments. // // An error shall be signaled if the list cannot be allocated (error-id. cannot-create-list). -func Append(local, global environment.Environment, lists ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Append(local environment.Environment, lists ...ilos.Instance) (ilos.Instance, ilos.Instance) { // Ref: https://github.com/sbcl/sbcl/blob/fe4faef65315c6ad52b3b89b62b6c6497cb78d09/src/code/list.lisp#L364 - result, err := List(local, global, Nil) + result, err := List(local, Nil) if err != nil { return nil, err } @@ -110,7 +110,7 @@ func Append(local, global environment.Environment, lists ...ilos.Instance) (ilos } for _, list := range lists { for _, elt := range list.(instance.List).Slice() { - it, err := List(local, global, elt) + it, err := List(local, elt) if err != nil { return nil, err } @@ -124,7 +124,7 @@ func Append(local, global environment.Environment, lists ...ilos.Instance) (ilos // Member returnes the first sublist of list whose car is obj if list contains at least one // occurrence of obj (as determined by eql). Otherwise, nil is returned. An error shall be signaled // if list is not a list (error-id. domain-error). -func Member(local, global environment.Environment, obj, list ilos.Instance) (ilos.Instance, ilos.Instance) { +func Member(local environment.Environment, obj, list ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.List, list); err != nil { return nil, err } @@ -140,7 +140,7 @@ func Member(local, global environment.Environment, obj, list ilos.Instance) (ilo // each list, then to the second element of each list, and so on. The iteration terminates when the // shortest list runs out, and excess elements in other lists are ignored. The value returned by // mapcar is a list of the results of successive calls to function. -func Mapcar(local, global environment.Environment, function, list1 ilos.Instance, lists ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Mapcar(local environment.Environment, function, list1 ilos.Instance, lists ...ilos.Instance) (ilos.Instance, ilos.Instance) { lists = append([]ilos.Instance{list1}, lists...) if err := ensure(class.Function, function); err != nil { return nil, err @@ -158,18 +158,18 @@ func Mapcar(local, global environment.Environment, function, list1 ilos.Instance for j, list := range lists { arguments[j] = list.(instance.List).Nth(i) } - ret, err := function.(instance.Applicable).Apply(local, global, arguments...) + ret, err := function.(instance.Applicable).Apply(local, arguments...) if err != nil { return nil, err } result = append(result, ret) } - return List(local, global, result...) + return List(local, result...) } // Mapc is like mapcar except that the results of applying function are not accumulated; // list1 is returned. -func Mapc(local, global environment.Environment, function, list1 ilos.Instance, lists ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Mapc(local environment.Environment, function, list1 ilos.Instance, lists ...ilos.Instance) (ilos.Instance, ilos.Instance) { lists = append([]ilos.Instance{list1}, lists...) if err := ensure(class.Function, function); err != nil { return nil, err @@ -186,7 +186,7 @@ func Mapc(local, global environment.Environment, function, list1 ilos.Instance, for j, list := range lists { arguments[j] = list.(instance.List).Nth(i) } - if _, err := function.(instance.Applicable).Apply(local, global, arguments...); err != nil { + if _, err := function.(instance.Applicable).Apply(local, arguments...); err != nil { return nil, err } } @@ -196,7 +196,7 @@ func Mapc(local, global environment.Environment, function, list1 ilos.Instance, // Mapcan is like mapcar respectively, except that the results of applying // function are combined into a list by the use of an operation that performs a destructive form of // append rather than list. -func Mapcan(local, global environment.Environment, function, list1 ilos.Instance, lists ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Mapcan(local environment.Environment, function, list1 ilos.Instance, lists ...ilos.Instance) (ilos.Instance, ilos.Instance) { lists = append([]ilos.Instance{list1}, lists...) if err := ensure(class.Function, function); err != nil { return nil, err @@ -214,19 +214,19 @@ func Mapcan(local, global environment.Environment, function, list1 ilos.Instance for j, list := range lists { arguments[j] = list.(instance.List).Nth(i) } - ret, err := function.(instance.Applicable).Apply(local, global, arguments...) + ret, err := function.(instance.Applicable).Apply(local, arguments...) if err != nil { return nil, err } result = append(result, ret) } - return Append(local, global, result...) + return Append(local, result...) } // Maplist is like mapcar except that function is applied to successive sublists of the lists. // function is first applied to the lists themselves, and then to the cdr of each list, and then to // the cdr of the cdr of each list, and so on. -func Maplist(local, global environment.Environment, function, list1 ilos.Instance, lists ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Maplist(local environment.Environment, function, list1 ilos.Instance, lists ...ilos.Instance) (ilos.Instance, ilos.Instance) { lists = append([]ilos.Instance{list1}, lists...) if err := ensure(class.Function, function); err != nil { return nil, err @@ -244,18 +244,18 @@ func Maplist(local, global environment.Environment, function, list1 ilos.Instanc for j, list := range lists { arguments[j] = list.(instance.List).NthCdr(i) } - ret, err := function.(instance.Applicable).Apply(local, global, arguments...) + ret, err := function.(instance.Applicable).Apply(local, arguments...) if err != nil { return nil, err } result = append(result, ret) } - return List(local, global, result...) + return List(local, result...) } // Mapl is like maplist except that the results of applying function are not accumulated; // list1 is returned. -func Mapl(local, global environment.Environment, function, list1 ilos.Instance, lists ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Mapl(local environment.Environment, function, list1 ilos.Instance, lists ...ilos.Instance) (ilos.Instance, ilos.Instance) { lists = append([]ilos.Instance{list1}, lists...) if err := ensure(class.Function, function); err != nil { return nil, err @@ -272,7 +272,7 @@ func Mapl(local, global environment.Environment, function, list1 ilos.Instance, for j, list := range lists { arguments[j] = list.(instance.List).NthCdr(i) } - if _, err := function.(instance.Applicable).Apply(local, global, arguments...); err != nil { + if _, err := function.(instance.Applicable).Apply(local, arguments...); err != nil { return nil, err } } @@ -282,7 +282,7 @@ func Mapl(local, global environment.Environment, function, list1 ilos.Instance, // Mapcon is like maplist respectively, except that the results of applying // function are combined into a list by the use of an operation that performs a destructive form of // append rather than list. -func Mapcon(local, global environment.Environment, function, list1 ilos.Instance, lists ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Mapcon(local environment.Environment, function, list1 ilos.Instance, lists ...ilos.Instance) (ilos.Instance, ilos.Instance) { lists = append([]ilos.Instance{list1}, lists...) if err := ensure(class.Function, function); err != nil { return nil, err @@ -300,19 +300,19 @@ func Mapcon(local, global environment.Environment, function, list1 ilos.Instance for j, list := range lists { arguments[j] = list.(instance.List).NthCdr(i) } - ret, err := function.(instance.Applicable).Apply(local, global, arguments...) + ret, err := function.(instance.Applicable).Apply(local, arguments...) if err != nil { return nil, err } result = append(result, ret) } - return Append(local, global, result...) + return Append(local, result...) } // Assoc returns the first cons if assocation-list contains at least one cons whose car is // obj (as determined by eql). Otherwise, nil is returned. An error shall be signaled // if association-list is not a list of conses (error-id. domain-error). -func Assoc(local, global environment.Environment, obj, associationList ilos.Instance) (ilos.Instance, ilos.Instance) { +func Assoc(local environment.Environment, obj, associationList ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.List, associationList); err != nil { return nil, err } diff --git a/runtime/logical_connectives.go b/runtime/logical_connectives.go index 6512096..ba80181 100644 --- a/runtime/logical_connectives.go +++ b/runtime/logical_connectives.go @@ -11,7 +11,7 @@ import ( // Not is the logical “not” (or “¬”). It returns t if obj is nil // and nil otherwise. obj may be any ISLISP object. -func Not(local, global environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { +func Not(local environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { if obj == Nil { return T, nil } @@ -22,26 +22,39 @@ func Not(local, global environment.Environment, obj ilos.Instance) (ilos.Instanc // from left to right until either one of them evaluates to nil or else // none are left. If one of them evaluates to nil, then nil is returned // from the and; otherwise, the value of the last evaluated form is returned. -func And(local, global environment.Environment, form ...ilos.Instance) (ilos.Instance, ilos.Instance) { - for _, f := range form { - if f == Nil { +func And(local environment.Environment, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { + var ret ilos.Instance + for _, form := range forms { + //fmt.Printf("%v\n%#v\n", form, local.Variable) + var err ilos.Instance + ret, err = Eval(local, form) + if err != nil { + return nil, err + } + if ret == Nil { return Nil, nil } } - if len(form) == 0 { + if len(forms) == 0 { return T, nil } - return form[len(form)-1], nil + return ret, nil } // Or is the sequential logical "or" (or "∨"). forms are evaluated // from left to right until either one of them evaluates to a non-nil value // or else none are left. If one of them evaluates to a non-nil value, // then this non-nil value is returned, otherwise nil is returned. -func Or(local, global environment.Environment, form ...ilos.Instance) (ilos.Instance, ilos.Instance) { - for _, f := range form { - if f != Nil { - return f, nil +func Or(local environment.Environment, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { + var ret ilos.Instance + for _, form := range forms { + var err ilos.Instance + ret, err = Eval(local, form) + if err != nil { + return nil, err + } + if ret != Nil { + return ret, nil } } return Nil, nil diff --git a/runtime/logical_connectives_test.go b/runtime/logical_connectives_test.go index e55b860..4045ca7 100644 --- a/runtime/logical_connectives_test.go +++ b/runtime/logical_connectives_test.go @@ -48,7 +48,7 @@ func TestNot(t *testing.T) { } func TestAnd(t *testing.T) { - defun(And) + defspecial(And) defun2("=", NumberEqual) defun2(">", NumberGreaterThan) defun2("<", NumberLessThan) @@ -119,7 +119,7 @@ func TestAnd(t *testing.T) { } func TestOr(t *testing.T) { - defun(Or) + defspecial(Or) defun2("=", NumberEqual) defun2(">", NumberGreaterThan) defun2("<", NumberLessThan) diff --git a/runtime/macros.go b/runtime/macros.go index c7b6337..7990a57 100644 --- a/runtime/macros.go +++ b/runtime/macros.go @@ -16,15 +16,15 @@ import ( // must be an identifier whose scope is the current toplevel scope in which the // defmacro form appears. lambda-list is as defined in page 23. The definition // point of macro-name is the closing parenthesis of the lambda-list. -func Defmacro(local, global environment.Environment, macroName, lambdaList ilos.Instance, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Defmacro(local environment.Environment, macroName, lambdaList ilos.Instance, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Symbol, macroName); err != nil { return nil, err } - ret, err := newNamedFunction(local, global, macroName, lambdaList, forms...) + ret, err := newNamedFunction(local, macroName, lambdaList, forms...) if err != nil { return nil, err } - global.Macro.Define(macroName, ret) + local.Macro.Define(macroName, ret) return macroName, nil } @@ -45,11 +45,11 @@ func Defmacro(local, global environment.Environment, macroName, lambdaList ilos. // expressions appearing at the same nesting level, which increases by one // inside each successive quasiquotation and decreases by one inside each // unquotation. -func Quasiquote(local, global environment.Environment, form ilos.Instance) (ilos.Instance, ilos.Instance) { - return expand(local, global, form, 0) +func Quasiquote(local environment.Environment, form ilos.Instance) (ilos.Instance, ilos.Instance) { + return expand(local, form, 0) } -func expand(local, global environment.Environment, form ilos.Instance, level int) (ilos.Instance, ilos.Instance) { +func expand(local environment.Environment, form ilos.Instance, level int) (ilos.Instance, ilos.Instance) { if !ilos.InstanceOf(class.Cons, form) { return form, nil } // If form is a instance of then, @@ -61,7 +61,7 @@ func expand(local, global environment.Environment, form ilos.Instance, level int // To expand `((foo ,(- 10 3)) ,@(cdr '(c)) . ,(car '(cons))) if cadr == instance.NewSymbol("UNQUOTE") && level == 0 { caddr := cddr.(*instance.Cons).Car - elt, err := Eval(local, global, caddr) + elt, err := Eval(local, caddr) if err != nil { return nil, err } @@ -69,7 +69,7 @@ func expand(local, global environment.Environment, form ilos.Instance, level int break } if !ilos.InstanceOf(class.Cons, cadr) { - lst, err := List(local, global, cadr) + lst, err := List(local, cadr) if err != nil { return nil, err } @@ -83,11 +83,11 @@ func expand(local, global environment.Environment, form ilos.Instance, level int cadadr := cdadr.(*instance.Cons).Car var elt, err ilos.Instance if level == 0 { - elt, err = Eval(local, global, cadadr) + elt, err = Eval(local, cadadr) if err != nil { return nil, err } - lst, err := List(local, global, elt) + lst, err := List(local, elt) if err != nil { return nil, err } @@ -95,15 +95,15 @@ func expand(local, global environment.Environment, form ilos.Instance, level int cdr = cdr.(*instance.Cons).Cdr continue } else { - elt, err = expand(local, global, cadadr, level-1) + elt, err = expand(local, cadadr, level-1) if err != nil { return nil, err } - lst, err := List(local, global, caadr, elt) + lst, err := List(local, caadr, elt) if err != nil { return nil, err } - lstlst, err := List(local, global, lst) + lstlst, err := List(local, lst) if err != nil { return nil, err } @@ -115,7 +115,7 @@ func expand(local, global environment.Environment, form ilos.Instance, level int if caadr == instance.NewSymbol("UNQUOTE-SPLICING") { cadadr := cdadr.(*instance.Cons).Car if level == 0 { - elt, err := Eval(local, global, cadadr) + elt, err := Eval(local, cadadr) if err != nil { return nil, err } @@ -123,15 +123,15 @@ func expand(local, global environment.Environment, form ilos.Instance, level int cdr = cdr.(*instance.Cons).Cdr continue } else { - elt, err := expand(local, global, cadadr, level-1) + elt, err := expand(local, cadadr, level-1) if err != nil { return nil, err } - lst, err := List(local, global, caadr, elt) + lst, err := List(local, caadr, elt) if err != nil { return nil, err } - lstlst, err := List(local, global, lst) + lstlst, err := List(local, lst) if err != nil { return nil, err } @@ -142,15 +142,15 @@ func expand(local, global environment.Environment, form ilos.Instance, level int } if caadr == instance.NewSymbol("QUASIQUOTE") { cadadr := cdadr.(*instance.Cons).Car - elt, err := expand(local, global, cadadr, level+1) + elt, err := expand(local, cadadr, level+1) if err != nil { return nil, err } - lst, err := List(local, global, caadr, elt) + lst, err := List(local, caadr, elt) if err != nil { return nil, err } - lstlst, err := List(local, global, lst) + lstlst, err := List(local, lst) if err != nil { return nil, err } @@ -159,11 +159,11 @@ func expand(local, global environment.Environment, form ilos.Instance, level int continue } // If the cadr is not special forms then, - elt, err := expand(local, global, cadr, level) + elt, err := expand(local, cadr, level) if err != nil { return nil, err } - lst, err := List(local, global, elt) + lst, err := List(local, elt) if err != nil { return nil, err } @@ -178,7 +178,7 @@ func expand(local, global environment.Environment, form ilos.Instance, level int for i := len(exp) - 2; i >= 0; i-- { if ilos.InstanceOf(class.List, lst) { var err ilos.Instance - lst, err = Append(local, global, exp[i], lst) + lst, err = Append(local, exp[i], lst) if err != nil { return nil, err } diff --git a/runtime/namedfunc.go b/runtime/namedfunc.go index 15f6b7a..ee34849 100644 --- a/runtime/namedfunc.go +++ b/runtime/namedfunc.go @@ -28,7 +28,7 @@ func checkLambdaList(lambdaList ilos.Instance) ilos.Instance { return nil } -func newNamedFunction(local, global environment.Environment, functionName, lambdaList ilos.Instance, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func newNamedFunction(local environment.Environment, functionName, lambdaList ilos.Instance, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { lexical := local if err := ensure(class.Symbol, functionName); err != nil { return nil, err @@ -44,7 +44,7 @@ func newNamedFunction(local, global environment.Environment, functionName, lambd } parameters = append(parameters, cadr) } - return instance.NewFunction(functionName.(instance.Symbol), func(local, global environment.Environment, arguments ...ilos.Instance) (ilos.Instance, ilos.Instance) { + return instance.NewFunction(functionName.(instance.Symbol), func(local environment.Environment, arguments ...ilos.Instance) (ilos.Instance, ilos.Instance) { local.Merge(lexical) if (variadic && len(parameters)-2 > len(arguments)) || (!variadic && len(parameters) != len(arguments)) { return nil, instance.NewArityError() @@ -53,7 +53,7 @@ func newNamedFunction(local, global environment.Environment, functionName, lambd key := parameters[idx] if key == instance.NewSymbol(":REST") || key == instance.NewSymbol("&REST") { key := parameters[idx+1] - value, err := List(local, global, arguments[idx:]...) + value, err := List(local, arguments[idx:]...) if err != nil { return nil, err } @@ -67,6 +67,6 @@ func newNamedFunction(local, global environment.Environment, functionName, lambd return nil, instance.NewImmutableBinding() } } - return Progn(local, global, forms...) + return Progn(local, forms...) }), nil } diff --git a/runtime/non-local_exits.go b/runtime/non-local_exits.go index 2d429d4..a11eb69 100644 --- a/runtime/non-local_exits.go +++ b/runtime/non-local_exits.go @@ -38,9 +38,9 @@ more recently than the destination to which control is being transferred is immediately considered invalid. */ -func Block(local, global environment.Environment, tag ilos.Instance, body ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Block(local environment.Environment, tag ilos.Instance, body ...ilos.Instance) (ilos.Instance, ilos.Instance) { var err ilos.Instance - tag, err = Eval(local, global, tag) // Checked at the top of// This function + tag, err = Eval(local, tag) // Checked at the top of// This function if err != nil { return nil, err } @@ -53,7 +53,7 @@ func Block(local, global environment.Environment, tag ilos.Instance, body ...ilo var fail ilos.Instance sucess := Nil for _, cadr := range body { - sucess, fail = Eval(local, global, cadr) + sucess, fail = Eval(local, cadr) if fail != nil { if ilos.InstanceOf(class.BlockTag, fail) { tag1, _ := fail.(instance.Instance).GetSlotValue(instance.NewSymbol("TAG"), class.Escape) // Checked at the head of// This condition @@ -68,16 +68,16 @@ func Block(local, global environment.Environment, tag ilos.Instance, body ...ilo return sucess, nil } -func ReturnFrom(local, global environment.Environment, tag, object ilos.Instance) (ilos.Instance, ilos.Instance) { +func ReturnFrom(local environment.Environment, tag, object ilos.Instance) (ilos.Instance, ilos.Instance) { var err ilos.Instance - tag, err = Eval(local, global, tag) + tag, err = Eval(local, tag) if err != nil { return nil, err } if ilos.InstanceOf(class.Number, tag) || ilos.InstanceOf(class.Character, tag) { return nil, instance.NewDomainError(tag, class.Object) } - object, err = Eval(local, global, object) + object, err = Eval(local, object) if err != nil { return nil, err } @@ -87,9 +87,9 @@ func ReturnFrom(local, global environment.Environment, tag, object ilos.Instance return nil, instance.NewBlockTag(tag, object) } -func Catch(local, global environment.Environment, tag ilos.Instance, body ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Catch(local environment.Environment, tag ilos.Instance, body ...ilos.Instance) (ilos.Instance, ilos.Instance) { var err ilos.Instance - tag, err = Eval(local, global, tag) + tag, err = Eval(local, tag) if err != nil { return nil, err } @@ -102,7 +102,7 @@ func Catch(local, global environment.Environment, tag ilos.Instance, body ...ilo var fail ilos.Instance sucess := Nil for _, cadr := range body { - sucess, fail = Eval(local, global, cadr) + sucess, fail = Eval(local, cadr) if fail != nil { if ilos.InstanceOf(class.CatchTag, fail) { tag1, _ := fail.(instance.Instance).GetSlotValue(instance.NewSymbol("TAG"), class.Escape) // Checked at the head of// This condition @@ -117,16 +117,16 @@ func Catch(local, global environment.Environment, tag ilos.Instance, body ...ilo return sucess, nil } -func Throw(local, global environment.Environment, tag, object ilos.Instance) (ilos.Instance, ilos.Instance) { +func Throw(local environment.Environment, tag, object ilos.Instance) (ilos.Instance, ilos.Instance) { var err ilos.Instance - tag, err = Eval(local, global, tag) + tag, err = Eval(local, tag) if err != nil { return nil, err } if ilos.InstanceOf(class.Number, tag) || ilos.InstanceOf(class.Character, tag) { return nil, instance.NewDomainError(tag, class.Object) } - object, err = Eval(local, global, object) + object, err = Eval(local, object) if err != nil { return nil, err } @@ -137,7 +137,7 @@ func Throw(local, global environment.Environment, tag, object ilos.Instance) (il return nil, instance.NewCatchTag(tag, object) } -func Tagbody(local, global environment.Environment, body ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Tagbody(local environment.Environment, body ...ilos.Instance) (ilos.Instance, ilos.Instance) { for idx, cadr := range body { cddr := instance.GeneralVector(body[idx+1:]) if !ilos.InstanceOf(class.Cons, cadr) { @@ -148,7 +148,7 @@ func Tagbody(local, global environment.Environment, body ...ilos.Instance) (ilos } for _, cadr := range body { if ilos.InstanceOf(class.Cons, cadr) { - _, fail := Eval(local, global, cadr) + _, fail := Eval(local, cadr) if fail != nil { TAG: if ilos.InstanceOf(class.TagbodyTag, fail) { @@ -164,7 +164,7 @@ func Tagbody(local, global environment.Environment, body ...ilos.Instance) (ilos forms, _ := local.TagbodyTag.Get(tag) // Checked in the function, tagbodyGo for _, form := range forms.(instance.GeneralVector) { if ilos.InstanceOf(class.Cons, form) { - _, fail = Eval(local, global, form) + _, fail = Eval(local, form) if fail != nil { goto TAG } @@ -181,7 +181,7 @@ func Tagbody(local, global environment.Environment, body ...ilos.Instance) (ilos return Nil, nil } -func Go(local, global environment.Environment, tag ilos.Instance) (ilos.Instance, ilos.Instance) { +func Go(local environment.Environment, tag ilos.Instance) (ilos.Instance, ilos.Instance) { if _, ok := local.TagbodyTag.Get(tag); !ok { return nil, instance.NewSimpleError(instance.NewString("%v is not defined as the tag"), tag) @@ -217,9 +217,9 @@ func Go(local, global environment.Environment, tag ilos.Instance) (ilos.Instance // not terminate abnormally, normal mechanisms for non-local exit (return-from, // throw, or go) would be used as necessary and would respect these // cleanup-forms. -func UnwindProtect(local, global environment.Environment, form ilos.Instance, cleanupForms ...ilos.Instance) (ilos.Instance, ilos.Instance) { - ret1, err1 := Eval(local, global, form) - ret2, err2 := Progn(local, global, cleanupForms...) +func UnwindProtect(local environment.Environment, form ilos.Instance, cleanupForms ...ilos.Instance) (ilos.Instance, ilos.Instance) { + ret1, err1 := Eval(local, form) + ret2, err2 := Progn(local, cleanupForms...) if ilos.InstanceOf(class.Escape, err2) { return nil, instance.NewControlError() } diff --git a/runtime/null_class.go b/runtime/null_class.go index 5c33fb0..7f8d6c1 100644 --- a/runtime/null_class.go +++ b/runtime/null_class.go @@ -10,7 +10,7 @@ import ( ) // Null returns t if obj is nil; otherwise, returns nil obj may be any ISLISP object. -func Null(local, global environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { +func Null(local environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { if obj == Nil { return T, nil } diff --git a/runtime/number_class.go b/runtime/number_class.go index 8d66d43..c7d0cb7 100644 --- a/runtime/number_class.go +++ b/runtime/number_class.go @@ -16,7 +16,7 @@ import ( // Numberp returns t if obj is a number (instance of class number); otherwise, // returns nil. The obj may be any ISLISP object. -func Numberp(local, global environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { +func Numberp(local environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { if ilos.InstanceOf(class.Number, obj) { return T, nil } @@ -29,7 +29,7 @@ func Numberp(local, global environment.Environment, obj ilos.Instance) (ilos.Ins // An error shall be signaled if string is not a string (error-id. domain-error). // An error shall be signaled if string is not the textual representation // of a number (error-id. cannot-parse-number). -func ParseNumber(local, global environment.Environment, str ilos.Instance) (ilos.Instance, ilos.Instance) { +func ParseNumber(local environment.Environment, str ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.String, str); err != nil { return nil, err } @@ -46,7 +46,7 @@ func ParseNumber(local, global environment.Environment, str ilos.Instance) (ilos // // Note: = differs from eql because = compares only the mathematical values of its arguments, // whereas eql also compares the representations -func NumberEqual(local, global environment.Environment, x1, x2 ilos.Instance) (ilos.Instance, ilos.Instance) { +func NumberEqual(local environment.Environment, x1, x2 ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Number, x1, x2); err != nil { return nil, err } @@ -70,16 +70,16 @@ func NumberEqual(local, global environment.Environment, x1, x2 ilos.Instance) (i // NumberNotEqual returns t if x1 and x2 have mathematically distinct values; // otherwise, returns nil. An error shall be signaled if either x1 or x2 is not // a number (error-id. domain-error). -func NumberNotEqual(local, global environment.Environment, x1, x2 ilos.Instance) (ilos.Instance, ilos.Instance) { - ret, err := NumberEqual(local, global, x1, x2) +func NumberNotEqual(local environment.Environment, x1, x2 ilos.Instance) (ilos.Instance, ilos.Instance) { + ret, err := NumberEqual(local, x1, x2) if err != nil { return ret, err } - return Not(local, global, ret) + return Not(local, ret) } // NumberGreaterThan returns t if x1 is greater than x2 -func NumberGreaterThan(local, global environment.Environment, x1, x2 ilos.Instance) (ilos.Instance, ilos.Instance) { +func NumberGreaterThan(local environment.Environment, x1, x2 ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Number, x1, x2); err != nil { return nil, err } @@ -101,12 +101,12 @@ func NumberGreaterThan(local, global environment.Environment, x1, x2 ilos.Instan } // NumberGreaterThanOrEqual returns t if x1 is greater than or = x2 -func NumberGreaterThanOrEqual(local, global environment.Environment, x1, x2 ilos.Instance) (ilos.Instance, ilos.Instance) { - gt, err := NumberGreaterThan(local, global, x1, x2) +func NumberGreaterThanOrEqual(local environment.Environment, x1, x2 ilos.Instance) (ilos.Instance, ilos.Instance) { + gt, err := NumberGreaterThan(local, x1, x2) if err != nil { return nil, err } - eq, err := NumberEqual(local, global, x1, x2) + eq, err := NumberEqual(local, x1, x2) if err != nil { return nil, err } @@ -117,27 +117,27 @@ func NumberGreaterThanOrEqual(local, global environment.Environment, x1, x2 ilos } // NumberLessThan returns t if x1 is less than x2 -func NumberLessThan(local, global environment.Environment, x1, x2 ilos.Instance) (ilos.Instance, ilos.Instance) { - ge, err := NumberGreaterThanOrEqual(local, global, x1, x2) +func NumberLessThan(local environment.Environment, x1, x2 ilos.Instance) (ilos.Instance, ilos.Instance) { + ge, err := NumberGreaterThanOrEqual(local, x1, x2) if err != nil { return nil, err } - return Not(local, global, ge) + return Not(local, ge) } // NumberLessThanOrEqulal returns t if x1 is less than or = x2 -func NumberLessThanOrEqulal(local, global environment.Environment, x1, x2 ilos.Instance) (ilos.Instance, ilos.Instance) { - gt, err := NumberGreaterThan(local, global, x1, x2) +func NumberLessThanOrEqulal(local environment.Environment, x1, x2 ilos.Instance) (ilos.Instance, ilos.Instance) { + gt, err := NumberGreaterThan(local, x1, x2) if err != nil { return nil, err } - return Not(local, global, gt) + return Not(local, gt) } // Add returns the sum, respectively, of their arguments. If all arguments are integers, // the result is an integer. If any argument is a float, the result is a float. When given no arguments, // + returns 0. An error shall be signaled if any x is not a number (error-id. domain-error). -func Add(local, global environment.Environment, x ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Add(local environment.Environment, x ...ilos.Instance) (ilos.Instance, ilos.Instance) { flt := false sum := 0.0 for _, a := range x { @@ -157,7 +157,7 @@ func Add(local, global environment.Environment, x ...ilos.Instance) (ilos.Instan // Multiply returns the product, respectively, of their arguments. If all arguments are integers, // the result is an integer. If any argument is a float, the result is a float. When given no arguments, // Multiply returns 1. An error shall be signaled if any x is not a number (error-id. domain-error). -func Multiply(local, global environment.Environment, x ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Multiply(local environment.Environment, x ...ilos.Instance) (ilos.Instance, ilos.Instance) { flt := false pdt := 1.0 for _, a := range x { @@ -181,9 +181,9 @@ func Multiply(local, global environment.Environment, x ...ilos.Instance) (ilos.I // returns -0.0; in implementations where -0.0 and 0.0 are not distinct, (- 0.0) returns 0.0. // Given more than one argument, x1 … xn , - returns their successive differences, // x1 −x2 − … −xn. An error shall be signaled if any x is not a number (error-id. domain-error). -func Substruct(local, global environment.Environment, x ilos.Instance, xs ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Substruct(local environment.Environment, x ilos.Instance, xs ...ilos.Instance) (ilos.Instance, ilos.Instance) { if len(xs) == 0 { - ret, err := Substruct(local, global, instance.NewInteger(0), x) + ret, err := Substruct(local, instance.NewInteger(0), x) return ret, err } sub, flt, err := convFloat64(x) @@ -208,7 +208,7 @@ func Substruct(local, global environment.Environment, x ilos.Instance, xs ...ilo // // Given more than two arguments, quotient operates iteratively on each of the divisor1 … divisorn as in dividend /divisor1 / … /divisorn. The type of the result follows from the two-argument case because the three-or-more-argument quotient can be defined as follows: // An error shall be signaled if dividend is not a number (error-id. domain-error). An error shall be signaled if any divisor is not a number (error-id. domain-error). An error shall be signaled if any divisor is zero (error-id. division-by-zero). -func Quotient(local, global environment.Environment, dividend, divisor1 ilos.Instance, divisor ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Quotient(local environment.Environment, dividend, divisor1 ilos.Instance, divisor ...ilos.Instance) (ilos.Instance, ilos.Instance) { divisor = append([]ilos.Instance{divisor1}, divisor...) quotient, flt, err := convFloat64(dividend) if err != nil { @@ -239,16 +239,16 @@ func Quotient(local, global environment.Environment, dividend, divisor1 ilos.Ins // Reciprocal returns the reciprocal of its argument x ; that is, 1/x . // An error shall be signaled if x is zero (error-id. division-by-zero). -func Reciprocal(local, global environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { - return Quotient(local, global, instance.NewInteger(1), x) +func Reciprocal(local environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { + return Quotient(local, instance.NewInteger(1), x) } // Max returns the greatest (closest to positive infinity) of its arguments. The comparison is done by >. // An error shall be signaled if any x is not a number (error-id. domain-error). -func Max(local, global environment.Environment, x ilos.Instance, xs ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Max(local environment.Environment, x ilos.Instance, xs ...ilos.Instance) (ilos.Instance, ilos.Instance) { max := x for _, y := range xs { - ret, err := NumberGreaterThan(local, global, y, max) + ret, err := NumberGreaterThan(local, y, max) if err != nil { return nil, err } @@ -261,10 +261,10 @@ func Max(local, global environment.Environment, x ilos.Instance, xs ...ilos.Inst // Min returns the least (closest to negative infinity) of its arguments. The comparison is done by <. // An error shall be signaled if any x is not a number (error-id. domain-error). -func Min(local, global environment.Environment, x ilos.Instance, xs ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Min(local environment.Environment, x ilos.Instance, xs ...ilos.Instance) (ilos.Instance, ilos.Instance) { min := x for _, y := range xs { - ret, err := NumberLessThan(local, global, y, min) + ret, err := NumberLessThan(local, y, min) if err != nil { return nil, err } @@ -277,20 +277,20 @@ func Min(local, global environment.Environment, x ilos.Instance, xs ...ilos.Inst // Abs returns the absolute value of its argument. // An error shall be signaled if x is not a number (error-id. domain-error). -func Abs(local, global environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { - ret, err := NumberLessThan(local, global, x, instance.NewInteger(0)) +func Abs(local environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { + ret, err := NumberLessThan(local, x, instance.NewInteger(0)) if err != nil { return nil, err } if ret == T { - return Substruct(local, global, x) + return Substruct(local, x) } return x, nil } // Exp returns e raised to the power x , where e is the base of the natural logarithm. // An error shall be signaled if x is not a number (error-id. domain-error). -func Exp(local, global environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { +func Exp(local environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { f, _, err := convFloat64(x) if err != nil { return nil, err @@ -300,7 +300,7 @@ func Exp(local, global environment.Environment, x ilos.Instance) (ilos.Instance, // Log returns the natural logarithm of x. // An error shall be signaled if x is not a positive number (error-id. domain-error). -func Log(local, global environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { +func Log(local environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { f, _, err := convFloat64(x) if err != nil { return nil, err @@ -316,7 +316,7 @@ func Log(local, global environment.Environment, x ilos.Instance) (ilos.Instance, // An error shall be signaled if x1 is zero and x2 is negative, // or if x1 is zero and x2 is a zero float, or if x1 is negative // and x2 is not an integer. -func Expt(local, global environment.Environment, x1, x2 ilos.Instance) (ilos.Instance, ilos.Instance) { +func Expt(local environment.Environment, x1, x2 ilos.Instance) (ilos.Instance, ilos.Instance) { a, af, err := convFloat64(x1) if err != nil { return nil, err @@ -330,7 +330,7 @@ func Expt(local, global environment.Environment, x1, x2 ilos.Instance) (ilos.Ins } if (a == 0 && b < 0) || (a == 0 && bf && b == 0) || (a < 0 && bf) { operation := instance.NewSymbol("EXPT") - operands, err := List(local, global, x1, x2) + operands, err := List(local, x1, x2) if err != nil { return nil, err } @@ -341,7 +341,7 @@ func Expt(local, global environment.Environment, x1, x2 ilos.Instance) (ilos.Ins // Sqrt returns the non-negative square root of x. An error shall be signaled // if x is not a non-negative number (error-id. domain-error). -func Sqrt(local, global environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { +func Sqrt(local environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { a, _, err := convFloat64(x) if err != nil { return nil, err @@ -360,7 +360,7 @@ var Pi = instance.NewFloat(3.141592653589793) // Sin returns the sine of x . x must be given in radians. // An error shall be signaled if x is not a number (error-id. domain-error). -func Sin(local, global environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { +func Sin(local environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { a, _, err := convFloat64(x) if err != nil { return nil, err @@ -370,7 +370,7 @@ func Sin(local, global environment.Environment, x ilos.Instance) (ilos.Instance, // Cos returns the cosine of x . x must be given in radians. // An error shall be signaled if x is not a number (error-id. domain-error). -func Cos(local, global environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { +func Cos(local environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { a, _, err := convFloat64(x) if err != nil { return nil, err @@ -380,7 +380,7 @@ func Cos(local, global environment.Environment, x ilos.Instance) (ilos.Instance, // Tan returns the tangent of x . x must be given in radians. // An error shall be signaled if x is not a number (error-id. domain-error). -func Tan(local, global environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { +func Tan(local environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { a, _, err := convFloat64(x) if err != nil { return nil, err @@ -391,7 +391,7 @@ func Tan(local, global environment.Environment, x ilos.Instance) (ilos.Instance, // Atan returns the arc tangent of x. // The result is a (real) number that lies between −π/2 and π/2 (both exclusive). // An error shall be signaled if x is not a number (error-id. domain-error). -func Atan(local, global environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { +func Atan(local environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { a, _, err := convFloat64(x) if err != nil { return nil, err @@ -408,7 +408,7 @@ func Atan(local, global environment.Environment, x ilos.Instance) (ilos.Instance // is not supported; when minus zero is supported, the range includes −π. // // The signs of x1 (indicated as y) and x2 (indicated as x) are used to derive quadrant information. -func Atan2(local, global environment.Environment, x1, x2 ilos.Instance) (ilos.Instance, ilos.Instance) { +func Atan2(local environment.Environment, x1, x2 ilos.Instance) (ilos.Instance, ilos.Instance) { a, _, err := convFloat64(x1) if err != nil { return nil, err @@ -419,7 +419,7 @@ func Atan2(local, global environment.Environment, x1, x2 ilos.Instance) (ilos.In } if a == 0 && b == 0 { operation := instance.NewSymbol("ATAN2") - operands, err := List(local, global, x1, x2) + operands, err := List(local, x1, x2) if err != nil { return nil, err } @@ -430,7 +430,7 @@ func Atan2(local, global environment.Environment, x1, x2 ilos.Instance) (ilos.In // Sinh returns the hyperbolic sine of x . x must be given in radians. // An error shall be signaled if x is not a number (error-id. domain-error). -func Sinh(local, global environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { +func Sinh(local environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { a, _, err := convFloat64(x) if err != nil { return nil, err @@ -440,7 +440,7 @@ func Sinh(local, global environment.Environment, x ilos.Instance) (ilos.Instance // Cosh returns the hyperbolic cosine of x . x must be given in radians. // An error shall be signaled if x is not a number (error-id. domain-error). -func Cosh(local, global environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { +func Cosh(local environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { a, _, err := convFloat64(x) if err != nil { return nil, err @@ -450,7 +450,7 @@ func Cosh(local, global environment.Environment, x ilos.Instance) (ilos.Instance // Tanh returns the hyperbolic tangent of x . x must be given in radians. // An error shall be signaled if x is not a number (error-id. domain-error). -func Tanh(local, global environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { +func Tanh(local environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { a, _, err := convFloat64(x) if err != nil { return nil, err @@ -460,7 +460,7 @@ func Tanh(local, global environment.Environment, x ilos.Instance) (ilos.Instance // Atanh returns the hyperbolic arc tangent of x. // An error shall be signaled if x is not a number with absolute value less than 1 (error-id. domain-error). -func Atanh(local, global environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { +func Atanh(local environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { a, _, err := convFloat64(x) if err != nil { return nil, err diff --git a/runtime/sequence_functions.go b/runtime/sequence_functions.go index 6216942..8dcbd1e 100644 --- a/runtime/sequence_functions.go +++ b/runtime/sequence_functions.go @@ -24,7 +24,7 @@ import ( // // An error shall be signaled if sequence is not a basic-vector or a list // (error-id. domain-error). -func Length(local, global environment.Environment, sequence ilos.Instance) (ilos.Instance, ilos.Instance) { +func Length(local environment.Environment, sequence ilos.Instance) (ilos.Instance, ilos.Instance) { switch { case ilos.InstanceOf(class.String, sequence): return instance.NewInteger(len(sequence.(instance.String))), nil @@ -44,7 +44,7 @@ func Length(local, global environment.Environment, sequence ilos.Instance) (ilos // // An error shall be signaled if sequence is not a basic-vector or a list or if z is not an // integer (error-id. domain-error). -func Elt(local, global environment.Environment, sequence, z ilos.Instance) (ilos.Instance, ilos.Instance) { +func Elt(local environment.Environment, sequence, z ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Integer, z); err != nil { return nil, err } @@ -80,7 +80,7 @@ func Elt(local, global environment.Environment, sequence, z ilos.Instance) (ilos // An error shall be signaled if z is an integer outside of the valid range of indices // (error-id. index-out-of-range). An error shall be signaled if sequence is not a basic-vector // or a list or if z is not an integer (error-id. domain-error). obj may be any ISLISP object. -func SetElt(local, global environment.Environment, obj, sequence, z ilos.Instance) (ilos.Instance, ilos.Instance) { +func SetElt(local environment.Environment, obj, sequence, z ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Integer, z); err != nil { return nil, err } @@ -130,7 +130,7 @@ func SetElt(local, global environment.Environment, obj, sequence, z ilos.Instanc // mentioned (error-id. index-out-of-range). An error shall be signaled if sequence is not a // basic-vector or a list, or if z1 is not an integer, or if z2 is not an integer // (error-id. domain-error). -func Subseq(local, global environment.Environment, sequence, z1, z2 ilos.Instance) (ilos.Instance, ilos.Instance) { +func Subseq(local environment.Environment, sequence, z1, z2 ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Integer, z1, z2); err != nil { return nil, err } @@ -154,7 +154,7 @@ func Subseq(local, global environment.Environment, sequence, z1, z2 ilos.Instanc if !(0 < start && start < len(seq) && 0 < end && end < len(seq) && start <= end) { return nil, instance.NewIndexOutOfRange() } - return List(local, global, seq[start:end]...) + return List(local, seq[start:end]...) } return nil, instance.NewDomainError(sequence, class.Object) } @@ -175,7 +175,7 @@ func Subseq(local, global environment.Environment, sequence, z1, z2 ilos.Instanc // // An error shall be signaled if any sequence is not a basic-vector or a list // (error-id. domain-error). -func mapInto(local, global environment.Environment, destination, function ilos.Instance, sequences ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func mapInto(local environment.Environment, destination, function ilos.Instance, sequences ...ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.List, append(sequences, destination)...); err != nil { if err := ensure(class.BasicVector, append(sequences, destination)...); err != nil { return nil, err @@ -199,16 +199,16 @@ func mapInto(local, global environment.Environment, destination, function ilos.I arguments := make([]ilos.Instance, int(max)) for _, seq := range sequences { var err ilos.Instance - arguments[i], err = Elt(local, global, seq, instance.NewInteger(i)) + arguments[i], err = Elt(local, seq, instance.NewInteger(i)) if err != nil { return nil, err } } - ret, err := function.(instance.Applicable).Apply(local, global, arguments...) + ret, err := function.(instance.Applicable).Apply(local, arguments...) if err != nil { return nil, err } - _, err = SetElt(local, global, ret, destination, instance.NewInteger(i)) + _, err = SetElt(local, ret, destination, instance.NewInteger(i)) if err != nil { return nil, err } diff --git a/runtime/sequencing_forms.go b/runtime/sequencing_forms.go index 9d639cb..3b8ec56 100644 --- a/runtime/sequencing_forms.go +++ b/runtime/sequencing_forms.go @@ -14,11 +14,11 @@ import ( // The result of evaluation of the last form of form* is returned. All the forms are // evaluated from left to right. The values of all the forms but the last are discarded, // so they are executed only for their side-effects. progn without forms returns nil. -func Progn(local, global environment.Environment, form ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Progn(local environment.Environment, form ...ilos.Instance) (ilos.Instance, ilos.Instance) { var err ilos.Instance ret := Nil for _, e := range form { - ret, err = Eval(local, global, e) + ret, err = Eval(local, e) if err != nil { return nil, err } diff --git a/runtime/stream.go b/runtime/stream.go index 2a6af6d..ae24430 100644 --- a/runtime/stream.go +++ b/runtime/stream.go @@ -20,80 +20,80 @@ import ( "github.com/ta2gch/iris/runtime/ilos/instance" ) -func Streamp(local, global environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { +func Streamp(local environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { if ilos.InstanceOf(class.Stream, obj) { return T, nil } return Nil, nil } -func OpenStreamP(local, global environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { +func OpenStreamP(local environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { return T, nil } -func InputStreamp(local, global environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { +func InputStreamp(local environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { if s, ok := obj.(instance.Stream); ok && s.Reader != nil { return T, nil } return Nil, nil } -func OutputStreamp(local, global environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { +func OutputStreamp(local environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { if s, ok := obj.(instance.Stream); ok && s.Writer != nil { return T, nil } return Nil, nil } -func StandardInput(local, global environment.Environment) (ilos.Instance, ilos.Instance) { +func StandardInput(local environment.Environment) (ilos.Instance, ilos.Instance) { return local.StandardInput, nil } -func StandardOutput(local, global environment.Environment) (ilos.Instance, ilos.Instance) { +func StandardOutput(local environment.Environment) (ilos.Instance, ilos.Instance) { return local.StandardOutput, nil } -func ErrorOutput(local, global environment.Environment) (ilos.Instance, ilos.Instance) { +func ErrorOutput(local environment.Environment) (ilos.Instance, ilos.Instance) { return local.ErrorOutput, nil } -func WithStandardInput(local, global environment.Environment, streamForm ilos.Instance, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func WithStandardInput(local environment.Environment, streamForm ilos.Instance, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { var err ilos.Instance - local.StandardInput, err = Eval(local, global, streamForm) + local.StandardInput, err = Eval(local, streamForm) if err != nil { return nil, err } if err := ensure(class.Stream, local.ErrorOutput); err != nil { return nil, err } - return Progn(local, global, forms...) + return Progn(local, forms...) } -func WithStandardOutput(local, global environment.Environment, streamForm ilos.Instance, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func WithStandardOutput(local environment.Environment, streamForm ilos.Instance, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { var err ilos.Instance - local.StandardOutput, err = Eval(local, global, streamForm) + local.StandardOutput, err = Eval(local, streamForm) if err != nil { return nil, err } if err := ensure(class.Stream, local.ErrorOutput); err != nil { return nil, err } - return Progn(local, global, forms...) + return Progn(local, forms...) } -func WithErrorOutput(local, global environment.Environment, streamForm ilos.Instance, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func WithErrorOutput(local environment.Environment, streamForm ilos.Instance, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { var err ilos.Instance - local.ErrorOutput, err = Eval(local, global, streamForm) + local.ErrorOutput, err = Eval(local, streamForm) if err != nil { return nil, err } if err := ensure(class.Stream, local.ErrorOutput); err != nil { return nil, err } - return Progn(local, global, forms...) + return Progn(local, forms...) } -func OpenInputFile(local, global environment.Environment, filename ilos.Instance, elementClass ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func OpenInputFile(local environment.Environment, filename ilos.Instance, elementClass ...ilos.Instance) (ilos.Instance, ilos.Instance) { // TODO: elementClass if err := ensure(class.String, filename); err != nil { return nil, err @@ -105,7 +105,7 @@ func OpenInputFile(local, global environment.Environment, filename ilos.Instance return instance.NewStream(file, nil), nil } -func OpenOutputFile(local, global environment.Environment, filename ilos.Instance, elementClass ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func OpenOutputFile(local environment.Environment, filename ilos.Instance, elementClass ...ilos.Instance) (ilos.Instance, ilos.Instance) { // TODO: elementClass if err := ensure(class.String, filename); err != nil { return nil, err @@ -117,7 +117,7 @@ func OpenOutputFile(local, global environment.Environment, filename ilos.Instanc return instance.NewStream(nil, file), nil } -func OpenIoFile(local, global environment.Environment, filename ilos.Instance, elementClass ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func OpenIoFile(local environment.Environment, filename ilos.Instance, elementClass ...ilos.Instance) (ilos.Instance, ilos.Instance) { // TODO: elementClass if err := ensure(class.String, filename); err != nil { return nil, err @@ -129,46 +129,46 @@ func OpenIoFile(local, global environment.Environment, filename ilos.Instance, e return instance.NewStream(file, file), nil } -func WithOpenInputFile(local, global environment.Environment, fileSpec ilos.Instance, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func WithOpenInputFile(local environment.Environment, fileSpec ilos.Instance, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Cons, fileSpec); err != nil { return nil, err } n := fileSpec.(*instance.Cons).Car - s, err := Eval(local, global, instance.NewCons(instance.NewSymbol("OPEN-INPUT-FILE"), fileSpec.(*instance.Cons).Cdr)) + s, err := Eval(local, instance.NewCons(instance.NewSymbol("OPEN-INPUT-FILE"), fileSpec.(*instance.Cons).Cdr)) if err != nil { return nil, err } local.Variable.Define(n, s) - return Progn(local, global, forms...) + return Progn(local, forms...) } -func WithOpenOutputFile(local, global environment.Environment, fileSpec ilos.Instance, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func WithOpenOutputFile(local environment.Environment, fileSpec ilos.Instance, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Cons, fileSpec); err != nil { return nil, err } n := fileSpec.(*instance.Cons).Car - s, err := Eval(local, global, instance.NewCons(instance.NewSymbol("OPEN-OUTPUT-FILE"), fileSpec.(*instance.Cons).Cdr)) + s, err := Eval(local, instance.NewCons(instance.NewSymbol("OPEN-OUTPUT-FILE"), fileSpec.(*instance.Cons).Cdr)) if err != nil { return nil, err } local.Variable.Define(n, s) - return Progn(local, global, forms...) + return Progn(local, forms...) } -func WithOpenIoFile(local, global environment.Environment, fileSpec ilos.Instance, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func WithOpenIoFile(local environment.Environment, fileSpec ilos.Instance, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Cons, fileSpec); err != nil { return nil, err } n := fileSpec.(*instance.Cons).Car - s, err := Eval(local, global, instance.NewCons(instance.NewSymbol("OPEN-IO-FILE"), fileSpec.(*instance.Cons).Cdr)) + s, err := Eval(local, instance.NewCons(instance.NewSymbol("OPEN-IO-FILE"), fileSpec.(*instance.Cons).Cdr)) if err != nil { return nil, err } local.Variable.Define(n, s) - return Progn(local, global, forms...) + return Progn(local, forms...) } -func Close(local, global environment.Environment, stream ilos.Instance) (ilos.Instance, ilos.Instance) { +func Close(local environment.Environment, stream ilos.Instance) (ilos.Instance, ilos.Instance) { // It works on file or std stream. if err := ensure(class.Stream, stream); err != nil { return nil, err @@ -182,7 +182,7 @@ func Close(local, global environment.Environment, stream ilos.Instance) (ilos.In return Nil, nil } -func FlushOutput(local, global environment.Environment, stream ilos.Instance) (ilos.Instance, ilos.Instance) { +func FlushOutput(local environment.Environment, stream ilos.Instance) (ilos.Instance, ilos.Instance) { // It works on file or std stream. if err := ensure(class.Stream, stream); err != nil { return nil, err @@ -193,27 +193,27 @@ func FlushOutput(local, global environment.Environment, stream ilos.Instance) (i return Nil, nil } -func CreateStringInputStream(local, global environment.Environment, str ilos.Instance) (ilos.Instance, ilos.Instance) { +func CreateStringInputStream(local environment.Environment, str ilos.Instance) (ilos.Instance, ilos.Instance) { return instance.NewStream(strings.NewReader(string(str.(instance.String))), nil), nil } -func CreateStringOutputStream(local, global environment.Environment) (ilos.Instance, ilos.Instance) { +func CreateStringOutputStream(local environment.Environment) (ilos.Instance, ilos.Instance) { return instance.NewStream(nil, new(bytes.Buffer)), nil } -func GetOutputStreamString(local, global environment.Environment, stream ilos.Instance) (ilos.Instance, ilos.Instance) { +func GetOutputStreamString(local environment.Environment, stream ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Stream, stream); err != nil { return nil, err } return instance.NewString(stream.(instance.Stream).Writer.(*bytes.Buffer).String()), nil } -func Read(local, global environment.Environment, options ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Read(local environment.Environment, options ...ilos.Instance) (ilos.Instance, ilos.Instance) { s := local.StandardInput if len(options) > 0 { s = options[0] } - if b, _ := InputStreamp(local, global, s); b == Nil { + if b, _ := InputStreamp(local, s); b == Nil { return nil, nil // throw Error } eosErrorP := true @@ -238,12 +238,12 @@ func Read(local, global environment.Environment, options ...ilos.Instance) (ilos return v, nil } -func ReadChar(local, global environment.Environment, options ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func ReadChar(local environment.Environment, options ...ilos.Instance) (ilos.Instance, ilos.Instance) { s := local.StandardInput if len(options) > 0 { s = options[0] } - if b, _ := InputStreamp(local, global, s); b == Nil { + if b, _ := InputStreamp(local, s); b == Nil { return nil, nil // throw Error } eosErrorP := true @@ -261,19 +261,19 @@ func ReadChar(local, global environment.Environment, options ...ilos.Instance) ( v, _, err := bufio.NewReader(s.(instance.Stream).Reader).ReadRune() if err != nil { if eosErrorP { - return nil, instance.Create(local, global, class.EndOfStream) + return nil, instance.Create(local, class.EndOfStream) } return eosValue, nil } return instance.NewCharacter(v), nil } -func ReadLine(local, global environment.Environment, options ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func ReadLine(local environment.Environment, options ...ilos.Instance) (ilos.Instance, ilos.Instance) { s := local.StandardInput if len(options) > 0 { s = options[0] } - if b, _ := InputStreamp(local, global, s); b == Nil { + if b, _ := InputStreamp(local, s); b == Nil { return nil, nil // throw Error } eosErrorP := true @@ -291,7 +291,7 @@ func ReadLine(local, global environment.Environment, options ...ilos.Instance) ( v, _, err := bufio.NewReader(s.(instance.Stream).Reader).ReadLine() if err != nil { if eosErrorP { - return nil, instance.Create(local, global, class.EndOfStream) + return nil, instance.Create(local, class.EndOfStream) } return eosValue, nil } @@ -300,16 +300,16 @@ func ReadLine(local, global environment.Environment, options ...ilos.Instance) ( // TODO: preview-char (Hint: Bufio.Rreader) -func StreamReadyP(local, global environment.Environment, inputStream ilos.Instance) (ilos.Instance, ilos.Instance) { +func StreamReadyP(local environment.Environment, inputStream ilos.Instance) (ilos.Instance, ilos.Instance) { // TODO: stream-ready-p return T, nil } -func Format(local, global environment.Environment, stream, formatString ilos.Instance, objs ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Format(local environment.Environment, stream, formatString ilos.Instance, objs ...ilos.Instance) (ilos.Instance, ilos.Instance) { f := regexp.MustCompile("([^~])~A").ReplaceAllString(string(formatString.(instance.String)), "%1%v") f = regexp.MustCompile(`\`).ReplaceAllString(string(formatString.(instance.String)), `\\`) f = regexp.MustCompile("([^~])~%").ReplaceAllString(string(formatString.(instance.String)), "%1\n") - if b, _ := OutputStreamp(local, global, stream); b == Nil { + if b, _ := OutputStreamp(local, stream); b == Nil { return nil, nil // throw Error } args := []interface{}{} diff --git a/runtime/string_class.go b/runtime/string_class.go index e442f19..c75b54b 100644 --- a/runtime/string_class.go +++ b/runtime/string_class.go @@ -15,7 +15,7 @@ import ( // Stringp returns t if obj is a string (instance of class string); // otherwise, returns nil. obj may be any ISLISP object. -func Stringp(local, global environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { +func Stringp(local environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { if ilos.InstanceOf(class.String, obj) { return T, nil } @@ -26,7 +26,7 @@ func Stringp(local, global environment.Environment, obj ilos.Instance) (ilos.Ins // the new string are initialized with this character, otherwise the initialization is implementation defined. // An error shall be signaled if the requested string cannot be allocated (error-id. cannot-create-string). // An error shall be signaled if i is not a non-negative integer or if initial-character is not a character (error-id. domain-error). -func CreateString(local, global environment.Environment, i ilos.Instance, initialElement ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func CreateString(local environment.Environment, i ilos.Instance, initialElement ...ilos.Instance) (ilos.Instance, ilos.Instance) { if !ilos.InstanceOf(class.Integer, i) || int(i.(instance.Integer)) < 0 { return nil, instance.NewDomainError(i, class.Integer) } @@ -49,7 +49,7 @@ func CreateString(local, global environment.Environment, i ilos.Instance, initia } // StringEqual tests whether string1 is the same string as string2. -func StringEqual(local, global environment.Environment, string1, string2 ilos.Instance) (ilos.Instance, ilos.Instance) { +func StringEqual(local environment.Environment, string1, string2 ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.String, string1, string2); err != nil { return nil, err } @@ -60,16 +60,16 @@ func StringEqual(local, global environment.Environment, string1, string2 ilos.In } // StringNotEqual tests whether string1 not is the same string as string2. -func StringNotEqual(local, global environment.Environment, string1, string2 ilos.Instance) (ilos.Instance, ilos.Instance) { - ret, err := StringEqual(local, global, string1, string2) +func StringNotEqual(local environment.Environment, string1, string2 ilos.Instance) (ilos.Instance, ilos.Instance) { + ret, err := StringEqual(local, string1, string2) if err != nil { return nil, err } - return Not(local, global, ret) + return Not(local, ret) } // StringGreaterThan tests whether string1 is greater than string2. -func StringGreaterThan(local, global environment.Environment, string1, string2 ilos.Instance) (ilos.Instance, ilos.Instance) { +func StringGreaterThan(local environment.Environment, string1, string2 ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.String, string1, string2); err != nil { return nil, err } @@ -80,12 +80,12 @@ func StringGreaterThan(local, global environment.Environment, string1, string2 i } // StringGreaterThanOrEqual tests whether string1 is greater than or equal to string2. -func StringGreaterThanOrEqual(local, global environment.Environment, string1, string2 ilos.Instance) (ilos.Instance, ilos.Instance) { - gt, err := StringGreaterThan(local, global, string1, string2) +func StringGreaterThanOrEqual(local environment.Environment, string1, string2 ilos.Instance) (ilos.Instance, ilos.Instance) { + gt, err := StringGreaterThan(local, string1, string2) if err != nil { return nil, err } - eq, err := StringEqual(local, global, string1, string2) + eq, err := StringEqual(local, string1, string2) if err != nil { return nil, err } @@ -96,21 +96,21 @@ func StringGreaterThanOrEqual(local, global environment.Environment, string1, st } // StringLessThan tests whether string1 is less than string2. -func StringLessThan(local, global environment.Environment, string1, string2 ilos.Instance) (ilos.Instance, ilos.Instance) { - gt, err := StringGreaterThanOrEqual(local, global, string1, string2) +func StringLessThan(local environment.Environment, string1, string2 ilos.Instance) (ilos.Instance, ilos.Instance) { + gt, err := StringGreaterThanOrEqual(local, string1, string2) if err != nil { return nil, err } - return Not(local, global, gt) + return Not(local, gt) } // StringLessThanOrEqual tests whether string1 is less than or equal to string2. -func StringLessThanOrEqual(local, global environment.Environment, string1, string2 ilos.Instance) (ilos.Instance, ilos.Instance) { - gt, err := StringGreaterThan(local, global, string1, string2) +func StringLessThanOrEqual(local environment.Environment, string1, string2 ilos.Instance) (ilos.Instance, ilos.Instance) { + gt, err := StringGreaterThan(local, string1, string2) if err != nil { return nil, err } - return Not(local, global, gt) + return Not(local, gt) } // CharIndex returns the position of char in string, The search starts from the position indicated @@ -119,7 +119,7 @@ func StringLessThanOrEqual(local, global environment.Environment, string1, strin // If the char does not occur in the string, nil is returned. The function char= is used for the comparisons. // // An error shall be signaled if char is not a character or if string is not a string (error-id. domain-error). -func CharIndex(local, global environment.Environment, char, str ilos.Instance, startPosition ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func CharIndex(local environment.Environment, char, str ilos.Instance, startPosition ...ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Character, char); err != nil { return nil, err } @@ -152,7 +152,7 @@ func CharIndex(local, global environment.Environment, char, str ilos.Instance, s // Presence of the substring is done by sequential use of char= on corresponding elements of the two strings. // // An error shall be signaled if either substring or string is not a string (error-id. domain-error). -func StringIndex(local, global environment.Environment, sub, str ilos.Instance, startPosition ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func StringIndex(local environment.Environment, sub, str ilos.Instance, startPosition ...ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.String, sub); err != nil { return nil, err } @@ -186,7 +186,7 @@ func StringIndex(local, global environment.Environment, sub, str ilos.Instance, // when the result shares structure with its string arguments. // // An error shall be signaled if the string cannot be allocated (error-id. cannot-create-string). -func StringAppend(local, global environment.Environment, str ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func StringAppend(local environment.Environment, str ...ilos.Instance) (ilos.Instance, ilos.Instance) { ret := "" for _, s := range str { if err := ensure(class.String, s); err != nil { diff --git a/runtime/symbol_class.go b/runtime/symbol_class.go index e408812..2029cb5 100644 --- a/runtime/symbol_class.go +++ b/runtime/symbol_class.go @@ -15,7 +15,7 @@ import ( // Symbolp returns t if obj is a symbol (instance of class symbol); // otherwise, returns nil. The obj may be any ISLISP object. -func Symbolp(local, global environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { +func Symbolp(local environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { if ilos.InstanceOf(class.Symbol, obj) { return T, nil } @@ -28,14 +28,14 @@ func Symbolp(local, global environment.Environment, obj ilos.Instance) (ilos.Ins // // An error shall be signaled if either symbol or property-name is not a // symbol (error-id. domain-error). obj may be any ISLISP object -func Property(local, global environment.Environment, symbol, propertyName ilos.Instance, obj ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Property(local environment.Environment, symbol, propertyName ilos.Instance, obj ...ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Symbol, symbol); err != nil { return nil, err } if len(obj) > 1 { return nil, instance.NewArityError() } - ret, ok := global.Property.Get(symbol, propertyName) + ret, ok := local.Property.Get(symbol, propertyName) if ok { return ret, nil } @@ -49,11 +49,11 @@ func Property(local, global environment.Environment, symbol, propertyName ilos.I // // An error shall be signaled if either symbol or property-name is not a // symbol (error-id. domain-error). obj may be any ISLISP object -func SetProperty(local, global environment.Environment, obj, symbol, propertyName ilos.Instance) (ilos.Instance, ilos.Instance) { +func SetProperty(local environment.Environment, obj, symbol, propertyName ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Symbol, symbol); err != nil { return nil, err } - global.Property.Set(symbol, propertyName, obj) + local.Property.Set(symbol, propertyName, obj) return obj, nil } @@ -63,11 +63,11 @@ func SetProperty(local, global environment.Environment, obj, symbol, propertyNam // // An error shall be signaled if either symbol or property-name is not a // symbol (error-id. domain-error). -func RemoveProperty(local, global environment.Environment, symbol, propertyName ilos.Instance) (ilos.Instance, ilos.Instance) { +func RemoveProperty(local environment.Environment, symbol, propertyName ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Symbol, symbol); err != nil { return nil, err } - if v, ok := global.Property.Delete(symbol, propertyName); ok { + if v, ok := local.Property.Delete(symbol, propertyName); ok { return v, nil } return Nil, nil @@ -75,7 +75,7 @@ func RemoveProperty(local, global environment.Environment, symbol, propertyName // Gensym returns an unnamed symbol. gensym is useful for writing macros. // It is impossible for an identifier to name an unnamed symbol. -func Gensym(local, global environment.Environment) (ilos.Instance, ilos.Instance) { - global.GensymID++ - return instance.NewSymbol(fmt.Sprintf("IRIS/G#%v", global.GensymID)), nil +func Gensym(local environment.Environment) (ilos.Instance, ilos.Instance) { + local.GensymID++ + return instance.NewSymbol(fmt.Sprintf("IRIS/G#%v", local.GensymID)), nil } diff --git a/runtime/test.go b/runtime/test.go index bc4da47..4554092 100644 --- a/runtime/test.go +++ b/runtime/test.go @@ -5,14 +5,9 @@ package runtime import ( - "os" "reflect" - "regexp" "runtime" "testing" - - "github.com/ta2gch/iris/runtime/environment" - "github.com/ta2gch/iris/runtime/ilos/instance" ) type test struct { @@ -23,13 +18,10 @@ type test struct { func execTests(t *testing.T, function interface{}, tests []test) { name := runtime.FuncForPC(reflect.ValueOf(function).Pointer()).Name() - name = regexp.MustCompile(`.*\.`).ReplaceAllString(name, "") - local := environment.NewEnvironment(instance.NewStream(os.Stdin, nil), instance.NewStream(nil, os.Stdout), instance.NewStream(nil, os.Stderr)) - global := TopLevel for _, tt := range tests { t.Run(tt.exp, func(t *testing.T) { - got, err := Eval(local, global, readFromString(tt.exp)) - want, _ := Eval(local, global, readFromString(tt.want)) + got, err := Eval(TopLevel, readFromString(tt.exp)) + want, _ := Eval(TopLevel, readFromString(tt.want)) if !tt.wantErr && !reflect.DeepEqual(got, want) { t.Errorf("%v() got = %v, want %v", name, got, want) } diff --git a/runtime/util.go b/runtime/util.go index c92ede9..1ef6093 100644 --- a/runtime/util.go +++ b/runtime/util.go @@ -45,8 +45,8 @@ func readFromString(s string) ilos.Instance { e, _ := parser.Parse(tokenizer.New(strings.NewReader(s))) return e } -func evalString(local, global environment.Environment, s string) ilos.Instance { - e, _ := Eval(local, global, readFromString(s)) +func evalString(local environment.Environment, s string) ilos.Instance { + e, _ := Eval(local, readFromString(s)) return e } diff --git a/runtime/variables.go b/runtime/variables.go index a509dfa..536f17f 100644 --- a/runtime/variables.go +++ b/runtime/variables.go @@ -21,38 +21,38 @@ import ( // setq can be used only for modifying bindings, and not for establishing a variable. // The setq special form must be contained in the scope of var , established by defglobal, // let, let*, for, or a lambda expression. -func Setq(local, global environment.Environment, var1, form ilos.Instance) (ilos.Instance, ilos.Instance) { - ret, err := Eval(local, global, form) +func Setq(local environment.Environment, var1, form ilos.Instance) (ilos.Instance, ilos.Instance) { + ret, err := Eval(local, form) if err != nil { return nil, err } if local.Variable.Set(var1, ret) { return ret, nil } - if global.Variable.Set(var1, ret) { + if local.Variable.Set(var1, ret) { return ret, nil } return nil, instance.NewUndefinedVariable(var1) } -func Setf(local, global environment.Environment, var1, form ilos.Instance) (ilos.Instance, ilos.Instance) { +func Setf(local environment.Environment, var1, form ilos.Instance) (ilos.Instance, ilos.Instance) { if ilos.InstanceOf(class.Symbol, var1) { - val, err := Eval(local, global, form) + val, err := Eval(local, form) if err != nil { return nil, err } - return Setq(local, global, var1, val) + return Setq(local, var1, val) } funcSpec := instance.NewSymbol(fmt.Sprintf("(SETF %v)", var1.(instance.List).Nth(0))) - fun, ok := global.Function.Get(funcSpec) + fun, ok := local.Function.Get(funcSpec) if !ok { return nil, instance.NewUndefinedFunction(funcSpec) } - arguments, err := evalArguments(local, global, instance.NewCons(form, var1.(*instance.Cons).Cdr)) + arguments, err := evalArguments(local, instance.NewCons(form, var1.(*instance.Cons).Cdr)) if err != nil { return nil, err } - return fun.(instance.Applicable).Apply(local, global, arguments.(instance.List).Slice()...) + return fun.(instance.Applicable).Apply(local, arguments.(instance.List).Slice()...) } // Let is used to define a scope for a group of identifiers @@ -67,7 +67,7 @@ func Setf(local, global environment.Environment, var1, form ilos.Instance) (ilos // of the evaluation of the last body-form of its body (or nil if there is none). // // No var may appear more than once in let variable list. -func Let(local, global environment.Environment, varForm ilos.Instance, bodyForm ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Let(local environment.Environment, varForm ilos.Instance, bodyForm ...ilos.Instance) (ilos.Instance, ilos.Instance) { vfs := map[ilos.Instance]ilos.Instance{} if err := ensure(class.List, varForm); err != nil { return nil, err @@ -79,7 +79,7 @@ func Let(local, global environment.Environment, varForm ilos.Instance, bodyForm if cadr.(instance.List).Length() != 2 { return nil, instance.NewArityError() } - f, err := Eval(local, global, cadr.(instance.List).Nth(1)) + f, err := Eval(local, cadr.(instance.List).Nth(1)) if err != nil { return nil, err } @@ -90,7 +90,7 @@ func Let(local, global environment.Environment, varForm ilos.Instance, bodyForm return nil, instance.NewImmutableBinding() } } - return Progn(local, global, bodyForm...) + return Progn(local, bodyForm...) } // LetStar form is used to define a scope for a group of identifiers for a sequence @@ -107,7 +107,7 @@ func Let(local, global environment.Environment, varForm ilos.Instance, bodyForm // and in this enlarged or modified environment the body-forms are executed. // The returned value of let* is the result of the evaluation of the last form // of its body (or nil if there is none). -func LetStar(local, global environment.Environment, varForm ilos.Instance, bodyForm ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func LetStar(local environment.Environment, varForm ilos.Instance, bodyForm ...ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.List, varForm); err != nil { return nil, err } @@ -118,7 +118,7 @@ func LetStar(local, global environment.Environment, varForm ilos.Instance, bodyF if cadr.(instance.List).Length() != 2 { return nil, instance.NewArityError() } - f, err := Eval(local, global, cadr.(instance.List).Nth(1)) + f, err := Eval(local, cadr.(instance.List).Nth(1)) if err != nil { return nil, err } @@ -126,5 +126,5 @@ func LetStar(local, global environment.Environment, varForm ilos.Instance, bodyF return nil, instance.NewImmutableBinding() } } - return Progn(local, global, bodyForm...) + return Progn(local, bodyForm...) } diff --git a/runtime/vectors.go b/runtime/vectors.go index 9ee0a5c..3a7f82b 100644 --- a/runtime/vectors.go +++ b/runtime/vectors.go @@ -13,7 +13,7 @@ import ( // BasicVectorP returns t if obj is a basic-vector (instance of class basic-vector); // otherwise, returns nil. obj may be any ISLISP object. -func BasicVectorP(local, global environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { +func BasicVectorP(local environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { if ilos.InstanceOf(class.BasicVector, obj) { return T, nil } @@ -22,7 +22,7 @@ func BasicVectorP(local, global environment.Environment, obj ilos.Instance) (ilo // GeneralVectorP returns t if obj is a general-vector (instance of class general-vector); // otherwise, returns nil. obj may be any ISLISP object. -func GeneralVectorP(local, global environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { +func GeneralVectorP(local environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { if ilos.InstanceOf(class.GeneralVector, obj) { return T, nil } @@ -35,7 +35,7 @@ func GeneralVectorP(local, global environment.Environment, obj ilos.Instance) (i // if the requested vector cannot be allocated (error-id. cannot-create-vector). // An error shall be signaled if i is not a non-negative integer (error-id. domain-error). // initial-element may be any ISLISP object. -func CreateVector(local, global environment.Environment, i ilos.Instance, initialElement ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func CreateVector(local environment.Environment, i ilos.Instance, initialElement ...ilos.Instance) (ilos.Instance, ilos.Instance) { if !ilos.InstanceOf(class.Integer, i) || int(i.(instance.Integer)) < 0 { return nil, instance.NewDomainError(i, class.Integer) } @@ -59,6 +59,6 @@ func CreateVector(local, global environment.Environment, i ilos.Instance, initia // The vector is indexed by integers ranging from 0 to dimension−1. An error shall be signaled // if the requested vector cannot be allocated (error-id. cannot-create-vector). // Each obj may be any ISLISP object. -func Vector(local, global environment.Environment, obj ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Vector(local environment.Environment, obj ...ilos.Instance) (ilos.Instance, ilos.Instance) { return instance.GeneralVector(obj), nil } From 6828f426c9fcfdab053eb653b34d0ddb0fc117fe Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Wed, 23 Aug 2017 14:31:52 +0900 Subject: [PATCH 208/228] renamed package environment to env --- runtime/array_operations.go | 34 +++--- runtime/character_class.go | 32 +++--- runtime/class.go | 10 +- runtime/condition_system.go | 48 ++++---- runtime/conditional_expressions.go | 34 +++--- runtime/cons.go | 14 +-- runtime/constants.go | 4 +- runtime/defining_classes.go | 50 ++++----- runtime/defining_operators.go | 24 ++-- runtime/dynamic_variables.go | 24 ++-- runtime/env/environment.go | 154 ++++++++++++++++++++++++++ runtime/{environment => env}/map2.go | 2 +- runtime/{environment => env}/stack.go | 2 +- runtime/environment/environment.go | 154 -------------------------- runtime/equality.go | 8 +- runtime/eval.go | 60 +++++----- runtime/float_class.go | 14 +-- runtime/functions.go | 48 ++++---- runtime/generic_functions.go | 12 +- runtime/ilos/instance/error.go | 26 ++--- runtime/ilos/instance/function.go | 148 ++++++++++++------------- runtime/ilos/instance/instance.go | 14 +-- runtime/ilos/instance/tag.go | 8 +- runtime/integer_class.go | 18 +-- runtime/iteration.go | 26 ++--- runtime/list_operations.go | 54 ++++----- runtime/logical_connectives.go | 14 +-- runtime/macros.go | 48 ++++---- runtime/namedfunc.go | 18 +-- runtime/non-local_exits.go | 80 ++++++------- runtime/null_class.go | 4 +- runtime/number_class.go | 92 +++++++-------- runtime/sequence_functions.go | 20 ++-- runtime/sequencing_forms.go | 8 +- runtime/stream.go | 114 +++++++++---------- runtime/string_class.go | 40 +++---- runtime/symbol_class.go | 22 ++-- runtime/util.go | 14 +-- runtime/variables.go | 40 +++---- runtime/vectors.go | 10 +- 40 files changed, 773 insertions(+), 773 deletions(-) create mode 100644 runtime/env/environment.go rename runtime/{environment => env}/map2.go (97%) rename runtime/{environment => env}/stack.go (97%) delete mode 100644 runtime/environment/environment.go diff --git a/runtime/array_operations.go b/runtime/array_operations.go index c57b239..7ea26ba 100644 --- a/runtime/array_operations.go +++ b/runtime/array_operations.go @@ -5,7 +5,7 @@ package runtime import ( - "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/env" "github.com/ta2gch/iris/runtime/ilos" "github.com/ta2gch/iris/runtime/ilos/class" "github.com/ta2gch/iris/runtime/ilos/instance" @@ -13,7 +13,7 @@ import ( // BasicArrayP returns t if obj is a basic-array (instance of class basic-array); // otherwise, returns nil. obj may be any ISLISP object. -func BasicArrayP(local environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { +func BasicArrayP(e env.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { if ilos.InstanceOf(class.BasicArray, obj) { return T, nil } @@ -22,7 +22,7 @@ func BasicArrayP(local environment.Environment, obj ilos.Instance) (ilos.Instanc // BasicArrayStarP returns t if obj is a basic-array* (instance of class ); // otherwise, returns nil. obj may be any ISLISP object. -func BasicArrayStarP(local environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { +func BasicArrayStarP(e env.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { if ilos.InstanceOf(class.BasicArrayStar, obj) { return T, nil } @@ -31,7 +31,7 @@ func BasicArrayStarP(local environment.Environment, obj ilos.Instance) (ilos.Ins // GeneralArrayStarP returns t if obj is a general-array* (instance of class ); // otherwise, returns nil. obj may be any ISLISP object. -func GeneralArrayStarP(local environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { +func GeneralArrayStarP(e env.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { if ilos.InstanceOf(class.GeneralArrayStar, obj) { return T, nil } @@ -52,7 +52,7 @@ func GeneralArrayStarP(local environment.Environment, obj ilos.Instance) (ilos.I // // An error shall be signaled if dimensions is not a proper list of non-negative integers // (error-id. domain-error). initial-element may be any ISLISP object -func CreateArray(local environment.Environment, dimensions ilos.Instance, initialElement ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func CreateArray(e env.Environment, dimensions ilos.Instance, initialElement ...ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.List, dimensions); err != nil { return nil, err } @@ -72,11 +72,11 @@ func CreateArray(local environment.Environment, dimensions ilos.Instance, initia } array := make([]instance.GeneralArrayStar, int(dim[0].(instance.Integer))) for i := range array { - d, err := List(local, dim[1:]...) + d, err := List(e, dim[1:]...) if err != nil { return nil, err } - a, err := CreateArray(local, d, elt) + a, err := CreateArray(e, d, elt) if err != nil { return nil, err } @@ -93,7 +93,7 @@ func CreateArray(local environment.Environment, dimensions ilos.Instance, initia // // An error shall be signaled if basic-array is not a basic-array (error-id. domain-error). // An error shall be signaled if any z is not a non-negative integer (error-id. domain-error). -func Aref(local environment.Environment, basicArray ilos.Instance, dimensions ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Aref(e env.Environment, basicArray ilos.Instance, dimensions ...ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.BasicArray, basicArray); err != nil { return nil, err } @@ -120,13 +120,13 @@ func Aref(local environment.Environment, basicArray ilos.Instance, dimensions .. } return basicArray.(instance.GeneralVector)[index], nil default: // General Array* - return Garef(local, basicArray, dimensions...) + return Garef(e, basicArray, dimensions...) } } // Garef is like aref but an error shall be signaled if its first argument, general-array, is // not an object of class general-vector or of class (error-id. domain-error). -func Garef(local environment.Environment, generalArray ilos.Instance, dimensions ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Garef(e env.Environment, generalArray ilos.Instance, dimensions ...ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.GeneralArrayStar, generalArray); err != nil { return nil, err } @@ -150,7 +150,7 @@ func Garef(local environment.Environment, generalArray ilos.Instance, dimensions // SetAref replaces the object obtainable by aref or garef with obj . The returned value is obj. // The constraints on the basic-array, the general-array, and the sequence of indices z is the // same as for aref and garef. -func SetAref(local environment.Environment, obj, basicArray ilos.Instance, dimensions ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func SetAref(e env.Environment, obj, basicArray ilos.Instance, dimensions ...ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.BasicArray, basicArray); err != nil { return nil, err } @@ -182,14 +182,14 @@ func SetAref(local environment.Environment, obj, basicArray ilos.Instance, dimen basicArray.(instance.GeneralVector)[index] = obj return obj, nil default: // General Array* - return SetGaref(local, obj, basicArray, dimensions...) + return SetGaref(e, obj, basicArray, dimensions...) } } // SetGaref replaces the object obtainable by aref or garef with obj . The returned value is obj. // The constraints on the basic-array, the general-array, and the sequence of indices z is the // same as for aref and garef. -func SetGaref(local environment.Environment, obj, generalArray ilos.Instance, dimensions ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func SetGaref(e env.Environment, obj, generalArray ilos.Instance, dimensions ...ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.GeneralArrayStar, generalArray); err != nil { return nil, err } @@ -214,15 +214,15 @@ func SetGaref(local environment.Environment, obj, generalArray ilos.Instance, di // ArrayDimensions returns a list of the dimensions of a given basic-array. // An error shall be signaled if basic-array is not a basic-array (error-id. domain-error). // The consequences are undefined if the returned list is modified. -func ArrayDimensions(local environment.Environment, basicArray ilos.Instance) (ilos.Instance, ilos.Instance) { +func ArrayDimensions(e env.Environment, basicArray ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.BasicArray, basicArray); err != nil { return nil, err } switch { case ilos.InstanceOf(class.String, basicArray): - return List(local, instance.NewInteger(len(basicArray.(instance.String)))) + return List(e, instance.NewInteger(len(basicArray.(instance.String)))) case ilos.InstanceOf(class.GeneralVector, basicArray): - return List(local, instance.NewInteger(len(basicArray.(instance.GeneralVector)))) + return List(e, instance.NewInteger(len(basicArray.(instance.GeneralVector)))) default: // General Array* var array instance.GeneralArrayStar dimensions := []ilos.Instance{} @@ -230,6 +230,6 @@ func ArrayDimensions(local environment.Environment, basicArray ilos.Instance) (i dimensions = append(dimensions, instance.NewInteger(len(array.Vector))) array = array.Vector[0] } - return List(local, dimensions...) + return List(e, dimensions...) } } diff --git a/runtime/character_class.go b/runtime/character_class.go index 68c07cb..af40fe0 100644 --- a/runtime/character_class.go +++ b/runtime/character_class.go @@ -5,7 +5,7 @@ package runtime import ( - "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/env" "github.com/ta2gch/iris/runtime/ilos" "github.com/ta2gch/iris/runtime/ilos/class" "github.com/ta2gch/iris/runtime/ilos/instance" @@ -13,7 +13,7 @@ import ( // Characterp returns t if obj is a character (instance of class character); // otherwise, returns nil. obj may be any ISLISP object. -func Characterp(local environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { +func Characterp(e env.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { if ilos.InstanceOf(class.Character, obj) { return T, nil } @@ -21,7 +21,7 @@ func Characterp(local environment.Environment, obj ilos.Instance) (ilos.Instance } // CharEqual tests whether char1 is the same character as char2. -func CharEqual(local environment.Environment, char1, char2 ilos.Instance) (ilos.Instance, ilos.Instance) { +func CharEqual(e env.Environment, char1, char2 ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Character, char1, char2); err != nil { return nil, err } @@ -32,17 +32,17 @@ func CharEqual(local environment.Environment, char1, char2 ilos.Instance) (ilos. } // CharNotEqual if and only if they are not char=. -func CharNotEqual(local environment.Environment, char1, char2 ilos.Instance) (ilos.Instance, ilos.Instance) { - ret, err := CharEqual(local, char1, char2) +func CharNotEqual(e env.Environment, char1, char2 ilos.Instance) (ilos.Instance, ilos.Instance) { + ret, err := CharEqual(e, char1, char2) if err != nil { return nil, err } - return Not(local, ret) + return Not(e, ret) } // CharGreaterThan tests whether char1 is greater than char2. // An error shall be signaled if either char1 or char2 is not a character (error-id. domain-error). -func CharGreaterThan(local environment.Environment, char1, char2 ilos.Instance) (ilos.Instance, ilos.Instance) { +func CharGreaterThan(e env.Environment, char1, char2 ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Character, char1, char2); err != nil { return nil, err } @@ -54,12 +54,12 @@ func CharGreaterThan(local environment.Environment, char1, char2 ilos.Instance) // CharGreaterThanOrEqual tests whether char1 is greater than or equal to char2. // An error shall be signaled if either char1 or char2 is not a character (error-id. domain-error). -func CharGreaterThanOrEqual(local environment.Environment, char1, char2 ilos.Instance) (ilos.Instance, ilos.Instance) { - gt, err := CharGreaterThan(local, char1, char2) +func CharGreaterThanOrEqual(e env.Environment, char1, char2 ilos.Instance) (ilos.Instance, ilos.Instance) { + gt, err := CharGreaterThan(e, char1, char2) if err != nil { return nil, err } - eq, err := CharEqual(local, char1, char2) + eq, err := CharEqual(e, char1, char2) if err != nil { return nil, err } @@ -71,20 +71,20 @@ func CharGreaterThanOrEqual(local environment.Environment, char1, char2 ilos.Ins // CharLessThan tests whether char1 is less than char2. // An error shall be signaled if either char1 or char2 is not a character (error-id. domain-error). -func CharLessThan(local environment.Environment, char1, char2 ilos.Instance) (ilos.Instance, ilos.Instance) { - gt, err := CharGreaterThanOrEqual(local, char1, char2) +func CharLessThan(e env.Environment, char1, char2 ilos.Instance) (ilos.Instance, ilos.Instance) { + gt, err := CharGreaterThanOrEqual(e, char1, char2) if err != nil { return nil, err } - return Not(local, gt) + return Not(e, gt) } // CharLessThanOrEqual tests whether char1 is less than or equal to char2. // An error shall be signaled if either char1 or char2 is not a character (error-id. domain-error). -func CharLessThanOrEqual(local environment.Environment, char1, char2 ilos.Instance) (ilos.Instance, ilos.Instance) { - gt, err := CharGreaterThan(local, char1, char2) +func CharLessThanOrEqual(e env.Environment, char1, char2 ilos.Instance) (ilos.Instance, ilos.Instance) { + gt, err := CharGreaterThan(e, char1, char2) if err != nil { return nil, err } - return Not(local, gt) + return Not(e, gt) } diff --git a/runtime/class.go b/runtime/class.go index e2fe43a..7ab536b 100644 --- a/runtime/class.go +++ b/runtime/class.go @@ -5,30 +5,30 @@ package runtime import ( - "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/env" "github.com/ta2gch/iris/runtime/ilos" "github.com/ta2gch/iris/runtime/ilos/instance" ) -func ClassOf(local environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { +func ClassOf(e env.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { return obj.Class(), nil } -func Instancep(local environment.Environment, obj ilos.Instance, class ilos.Class) (ilos.Instance, ilos.Instance) { +func Instancep(e env.Environment, obj ilos.Instance, class ilos.Class) (ilos.Instance, ilos.Instance) { if ilos.InstanceOf(class, obj) { return T, nil } return Nil, nil } -func Subclassp(local environment.Environment, class1, class2 ilos.Class) (ilos.Instance, ilos.Instance) { +func Subclassp(e env.Environment, class1, class2 ilos.Class) (ilos.Instance, ilos.Instance) { if ilos.SubclassOf(class1, class2) { return T, nil } return Nil, nil } -func Class(local environment.Environment, className ilos.Instance) (ilos.Class, ilos.Instance) { +func Class(e env.Environment, className ilos.Instance) (ilos.Class, ilos.Instance) { if v, ok := TopLevel.Class.Get(className); ok { return v.(ilos.Class), nil } diff --git a/runtime/condition_system.go b/runtime/condition_system.go index d051e4a..ce6c4ca 100644 --- a/runtime/condition_system.go +++ b/runtime/condition_system.go @@ -5,86 +5,86 @@ package runtime import ( - "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/env" "github.com/ta2gch/iris/runtime/ilos" "github.com/ta2gch/iris/runtime/ilos/class" "github.com/ta2gch/iris/runtime/ilos/instance" ) -func SignalCondition(local environment.Environment, condition, continuable ilos.Instance) (ilos.Instance, ilos.Instance) { +func SignalCondition(e env.Environment, condition, continuable ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.SeriousCondition, condition); err != nil { return nil, err } - if handler, ok := local.Handler.Get(instance.NewSymbol("HANDLER")); ok { + if handler, ok := e.Handler.Get(instance.NewSymbol("HANDLER")); ok { if continuable != Nil { - handler.(instance.Applicable).Apply(local, condition) + handler.(instance.Applicable).Apply(e, condition) } } condition.(instance.Instance).SetSlotValue(instance.NewSymbol("IRIS.CONTINUABLE"), continuable, class.SeriousCondition) return nil, condition } -func Cerror(local environment.Environment, continueString, errorString ilos.Instance, objs ...ilos.Instance) (ilos.Instance, ilos.Instance) { - arguments, err := List(local, objs...) +func Cerror(e env.Environment, continueString, errorString ilos.Instance, objs ...ilos.Instance) (ilos.Instance, ilos.Instance) { + arguments, err := List(e, objs...) if err != nil { return nil, err } - condition := instance.Create(local, class.SimpleError, instance.NewSymbol("FORMAT-STRING"), errorString, instance.NewSymbol("FORAMT-OBJECTS"), arguments) - ss, err := CreateStringOutputStream(local) + condition := instance.Create(e, class.SimpleError, instance.NewSymbol("FORMAT-STRING"), errorString, instance.NewSymbol("FORAMT-OBJECTS"), arguments) + ss, err := CreateStringOutputStream(e) if err != nil { return nil, err } - if _, err := Format(local, ss, continueString, objs...); err != nil { + if _, err := Format(e, ss, continueString, objs...); err != nil { return nil, err } - continuable, err := GetOutputStreamString(local, ss) + continuable, err := GetOutputStreamString(e, ss) if err != nil { return nil, err } - return SignalCondition(local, condition, continuable) + return SignalCondition(e, condition, continuable) } -func Error(local environment.Environment, continueString, errorString ilos.Instance, objs ...ilos.Instance) (ilos.Instance, ilos.Instance) { - arguments, err := List(local, objs...) +func Error(e env.Environment, continueString, errorString ilos.Instance, objs ...ilos.Instance) (ilos.Instance, ilos.Instance) { + arguments, err := List(e, objs...) if err != nil { return nil, err } - condition := instance.Create(local, class.SimpleError, instance.NewSymbol("FORMAT-STRING"), errorString, instance.NewSymbol("FORAMT-OBJECTS"), arguments) - return SignalCondition(local, condition, Nil) + condition := instance.Create(e, class.SimpleError, instance.NewSymbol("FORMAT-STRING"), errorString, instance.NewSymbol("FORAMT-OBJECTS"), arguments) + return SignalCondition(e, condition, Nil) } -func IgnoreError(local environment.Environment, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { - ret, err := Progn(local, forms...) +func IgnoreError(e env.Environment, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { + ret, err := Progn(e, forms...) if err != nil && ilos.InstanceOf(class.Error, err) { return Nil, nil } return ret, err } -func ReportCondition(local environment.Environment, condition, stream ilos.Instance) (ilos.Instance, ilos.Instance) { +func ReportCondition(e env.Environment, condition, stream ilos.Instance) (ilos.Instance, ilos.Instance) { return nil, nil } -func ConditionContinuable(local environment.Environment, condition ilos.Instance) (ilos.Instance, ilos.Instance) { +func ConditionContinuable(e env.Environment, condition ilos.Instance) (ilos.Instance, ilos.Instance) { if continuable, ok := condition.(instance.Instance).GetSlotValue(instance.NewSymbol("IRIS.CONTINUABLE"), class.SeriousCondition); ok { return continuable, nil } return Nil, nil } -func ContinueCondition(local environment.Environment, condition, value ilos.Instance) (ilos.Instance, ilos.Instance) { +func ContinueCondition(e env.Environment, condition, value ilos.Instance) (ilos.Instance, ilos.Instance) { // TODO: return nil, nil } -func WithHandler(local environment.Environment, handler ilos.Instance, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { - fun, err := Eval(local, handler) +func WithHandler(e env.Environment, handler ilos.Instance, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { + fun, err := Eval(e, handler) if err != nil { return nil, err } - ret, err := Progn(local, forms...) + ret, err := Progn(e, forms...) if err != nil { - return fun.(instance.Applicable).Apply(local, err) + return fun.(instance.Applicable).Apply(e, err) } return ret, err } diff --git a/runtime/conditional_expressions.go b/runtime/conditional_expressions.go index 141582f..9fb1726 100644 --- a/runtime/conditional_expressions.go +++ b/runtime/conditional_expressions.go @@ -5,7 +5,7 @@ package runtime import ( - "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/env" "github.com/ta2gch/iris/runtime/ilos" "github.com/ta2gch/iris/runtime/ilos/class" "github.com/ta2gch/iris/runtime/ilos/instance" @@ -18,13 +18,13 @@ import ( // is evaluated and its value is returned. // // If no else-form is provided, it defaults to nil. -func If(local environment.Environment, testForm, thenForm ilos.Instance, elseForm ...ilos.Instance) (ilos.Instance, ilos.Instance) { - tf, err := Eval(local, testForm) +func If(e env.Environment, testForm, thenForm ilos.Instance, elseForm ...ilos.Instance) (ilos.Instance, ilos.Instance) { + tf, err := Eval(e, testForm) if err != nil { return nil, err } if tf == T { - return Eval(local, thenForm) + return Eval(e, thenForm) } if len(elseForm) > 1 { return nil, instance.NewArityError() @@ -32,7 +32,7 @@ func If(local environment.Environment, testForm, thenForm ilos.Instance, elseFor if len(elseForm) == 0 { return Nil, nil } - return Eval(local, elseForm[0]) + return Eval(e, elseForm[0]) } // Cond the clauses (test form*) are scanned sequentially @@ -41,7 +41,7 @@ func If(local environment.Environment, testForm, thenForm ilos.Instance, elseFor //are sequentially evaluated and the value of the last one is returned. // If no test is true, then nil is returned. // If no form exists for the successful test then the value of this test is returned. -func Cond(local environment.Environment, testFrom ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Cond(e env.Environment, testFrom ...ilos.Instance) (ilos.Instance, ilos.Instance) { for _, tf := range testFrom { if err := ensure(class.List, tf); err != nil { return nil, err @@ -50,12 +50,12 @@ func Cond(local environment.Environment, testFrom ...ilos.Instance) (ilos.Instan if len(s) == 0 { return nil, instance.NewArityError() } - ret, err := Eval(local, s[0]) + ret, err := Eval(e, s[0]) if err != nil { return nil, err } if ret == T { - return Progn(local, s[1:]...) + return Progn(e, s[1:]...) } } return Nil, nil @@ -74,8 +74,8 @@ func Cond(local environment.Environment, testFrom ...ilos.Instance) (ilos.Instan // the value returned by keyform and key. If no form exists for a matching key, the case form evaluates to nil. // If the value of keyform is different from every key, and there is a default clause, its forms, if any, // are evaluated sequentially, and the value of the last one is the result of the case form. -func Case(local environment.Environment, key ilos.Instance, pattern ...ilos.Instance) (ilos.Instance, ilos.Instance) { - key, err := Eval(local, key) +func Case(e env.Environment, key ilos.Instance, pattern ...ilos.Instance) (ilos.Instance, ilos.Instance) { + key, err := Eval(e, key) if err != nil { return nil, err } @@ -88,14 +88,14 @@ func Case(local environment.Environment, key ilos.Instance, pattern ...ilos.Inst return nil, instance.NewArityError() } if idx == len(pattern)-1 && form[0] == T { - return Progn(local, form[1:]...) + return Progn(e, form[1:]...) } if err := ensure(class.List, form[0]); err != nil { return nil, err } for _, k := range form[0].(instance.List).Slice() { if k == key { - return Progn(local, form[1:]...) + return Progn(e, form[1:]...) } } } @@ -117,8 +117,8 @@ func Case(local environment.Environment, key ilos.Instance, pattern ...ilos.Inst // the value returned by keyform and key. If no form exists for a matching key, the case form evaluates to nil. // If the value of keyform is different from every key, and there is a default clause, its forms, if any, // are evaluated sequentially, and the value of the last one is the result of the case form. -func CaseUsing(local environment.Environment, key, pred ilos.Instance, pattern ...ilos.Instance) (ilos.Instance, ilos.Instance) { - key, err := Eval(local, key) +func CaseUsing(e env.Environment, key, pred ilos.Instance, pattern ...ilos.Instance) (ilos.Instance, ilos.Instance) { + key, err := Eval(e, key) if err != nil { return nil, err } @@ -134,18 +134,18 @@ func CaseUsing(local environment.Environment, key, pred ilos.Instance, pattern . return nil, instance.NewArityError() } if idx == len(pattern)-1 && form[0] == T { - return Progn(local, form[1:]...) + return Progn(e, form[1:]...) } if err := ensure(class.List, form[0]); err != nil { return nil, err } for _, k := range form[0].(instance.List).Slice() { - ret, err := pred.(instance.Applicable).Apply(local, k, key) + ret, err := pred.(instance.Applicable).Apply(e, k, key) if err != nil { return nil, err } if ret != Nil { - return Progn(local, form[1:]...) + return Progn(e, form[1:]...) } } } diff --git a/runtime/cons.go b/runtime/cons.go index dc8135e..c17d342 100644 --- a/runtime/cons.go +++ b/runtime/cons.go @@ -5,7 +5,7 @@ package runtime import ( - "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/env" "github.com/ta2gch/iris/runtime/ilos" "github.com/ta2gch/iris/runtime/ilos/class" "github.com/ta2gch/iris/runtime/ilos/instance" @@ -13,7 +13,7 @@ import ( // Consp returns t if obj is a cons (instance of class cons); // otherwise, returns nil. obj may be any ISLISP object. -func Consp(local environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { +func Consp(e env.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { if ilos.InstanceOf(class.Cons, obj) { return T, nil } @@ -25,13 +25,13 @@ func Consp(local environment.Environment, obj ilos.Instance) (ilos.Instance, ilo // An error shall be signaled if the requested cons cannot // be allocated (error-id. cannot-create-cons). Both obj1 // and obj2 may be any ISLISP object. -func Cons(local environment.Environment, obj1, obj2 ilos.Instance) (ilos.Instance, ilos.Instance) { +func Cons(e env.Environment, obj1, obj2 ilos.Instance) (ilos.Instance, ilos.Instance) { return instance.NewCons(obj1, obj2), nil } // Car returns the left component of the cons. // An error shall be signaled if cons is not a cons (error-id. domain-error). -func Car(local environment.Environment, cons ilos.Instance) (ilos.Instance, ilos.Instance) { +func Car(e env.Environment, cons ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Cons, cons); err != nil { return nil, err } @@ -40,7 +40,7 @@ func Car(local environment.Environment, cons ilos.Instance) (ilos.Instance, ilos // Cdr returns the right component of the cons. // An error shall be signaled if cons is not a cons (error-id. domain-error). -func Cdr(local environment.Environment, cons ilos.Instance) (ilos.Instance, ilos.Instance) { +func Cdr(e env.Environment, cons ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Cons, cons); err != nil { return nil, err } @@ -50,7 +50,7 @@ func Cdr(local environment.Environment, cons ilos.Instance) (ilos.Instance, ilos // SetCar updates the left component of cons with obj. The returned value is obj . // An error shall be signaled if cons is not a cons (error-id. domain-error). // obj may be any ISLISP object. -func SetCar(local environment.Environment, obj, cons ilos.Instance) (ilos.Instance, ilos.Instance) { +func SetCar(e env.Environment, obj, cons ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Cons, cons); err != nil { return nil, err } @@ -61,7 +61,7 @@ func SetCar(local environment.Environment, obj, cons ilos.Instance) (ilos.Instan // SetCdr updates the right component of cons with obj. The returned value is obj . // An error shall be signaled if cons is not a cons (error-id. domain-error). // obj may be any ISLISP object. -func SetCdr(local environment.Environment, obj, cons ilos.Instance) (ilos.Instance, ilos.Instance) { +func SetCdr(e env.Environment, obj, cons ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Cons, cons); err != nil { return nil, err } diff --git a/runtime/constants.go b/runtime/constants.go index 6ced8f0..7334a0e 100644 --- a/runtime/constants.go +++ b/runtime/constants.go @@ -5,12 +5,12 @@ package runtime import ( - "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/env" "github.com/ta2gch/iris/runtime/ilos" ) // Quote is used to include any object in an ISLisp text. // A quoted expression denotes a reference to an object. -func Quote(local environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { +func Quote(e env.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { return obj, nil } diff --git a/runtime/defining_classes.go b/runtime/defining_classes.go index add825b..0e80d51 100644 --- a/runtime/defining_classes.go +++ b/runtime/defining_classes.go @@ -8,7 +8,7 @@ import ( "fmt" "reflect" - "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/env" "github.com/ta2gch/iris/runtime/ilos" "github.com/ta2gch/iris/runtime/ilos/class" "github.com/ta2gch/iris/runtime/ilos/instance" @@ -34,7 +34,7 @@ func checkSuperClass(a, b ilos.Class) bool { return false } -func Defclass(local environment.Environment, className, scNames, slotSpecs ilos.Instance, classOpts ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Defclass(e env.Environment, className, scNames, slotSpecs ilos.Instance, classOpts ...ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Symbol, className); err != nil { return nil, err } @@ -43,7 +43,7 @@ func Defclass(local environment.Environment, className, scNames, slotSpecs ilos. } supers := []ilos.Class{class.StandardObject} for _, scName := range scNames.(instance.List).Slice() { - super, err := Class(local, scName) + super, err := Class(e, scName) if err != nil { return nil, err } @@ -69,7 +69,7 @@ func Defclass(local environment.Environment, className, scNames, slotSpecs ilos. for i := 0; i < len(slotOpts); i += 2 { switch slotOpts[i] { case instance.NewSymbol(":INITFORM"): - closure, err := newNamedFunction(local, instance.NewSymbol("CLOSURE"), Nil, slotOpts[i+1]) + closure, err := newNamedFunction(e, instance.NewSymbol("CLOSURE"), Nil, slotOpts[i+1]) if err != nil { return nil, err } @@ -85,11 +85,11 @@ func Defclass(local environment.Environment, className, scNames, slotSpecs ilos. var err ilos.Instance switch classOpt.(*instance.Cons).Car { case instance.NewSymbol(":METACLASS"): - if metaclass, err = Class(local, classOpt.(instance.List).Nth(1)); err != nil { + if metaclass, err = Class(e, classOpt.(instance.List).Nth(1)); err != nil { return nil, err } case instance.NewSymbol(":ABSTRACTP"): - if abstractp, err = Eval(local, classOpt.(instance.List).Nth(1)); err != nil { + if abstractp, err = Eval(e, classOpt.(instance.List).Nth(1)); err != nil { return nil, err } } @@ -117,15 +117,15 @@ func Defclass(local environment.Environment, className, scNames, slotSpecs ilos. } } if readerFunctionName != nil { - lambdaList, err := List(local, instance.NewSymbol("INSTANCE")) + lambdaList, err := List(e, instance.NewSymbol("INSTANCE")) if err != nil { return nil, err } - if g, ok := local.Function.Get(readerFunctionName); !ok || !ilos.InstanceOf(class.GenericFunction, g) { - Defgeneric(local, readerFunctionName, lambdaList) + if g, ok := e.Function.Get(readerFunctionName); !ok || !ilos.InstanceOf(class.GenericFunction, g) { + Defgeneric(e, readerFunctionName, lambdaList) } - fun, _ := local.Function.Get(readerFunctionName) - fun.(*instance.GenericFunction).AddMethod(nil, lambdaList, []ilos.Class{classObject}, instance.NewFunction(readerFunctionName, func(local environment.Environment, object ilos.Instance) (ilos.Instance, ilos.Instance) { + fun, _ := e.Function.Get(readerFunctionName) + fun.(*instance.GenericFunction).AddMethod(nil, lambdaList, []ilos.Class{classObject}, instance.NewFunction(readerFunctionName, func(e env.Environment, object ilos.Instance) (ilos.Instance, ilos.Instance) { slot, ok := object.(instance.Instance).GetSlotValue(slotName, classObject) if ok { return slot, nil @@ -134,15 +134,15 @@ func Defclass(local environment.Environment, className, scNames, slotSpecs ilos. })) } if writerFunctionName != nil { - lambdaList, err := List(local, instance.NewSymbol("Y"), instance.NewSymbol("X")) + lambdaList, err := List(e, instance.NewSymbol("Y"), instance.NewSymbol("X")) if err != nil { return nil, err } - if g, ok := local.Function.Get(writerFunctionName); !ok || !ilos.InstanceOf(class.GenericFunction, g) { - Defgeneric(local, writerFunctionName, lambdaList) + if g, ok := e.Function.Get(writerFunctionName); !ok || !ilos.InstanceOf(class.GenericFunction, g) { + Defgeneric(e, writerFunctionName, lambdaList) } - fun, _ := local.Function.Get(writerFunctionName) - fun.(*instance.GenericFunction).AddMethod(nil, lambdaList, []ilos.Class{class.Object, classObject}, instance.NewFunction(writerFunctionName, func(local environment.Environment, obj, object ilos.Instance) (ilos.Instance, ilos.Instance) { + fun, _ := e.Function.Get(writerFunctionName) + fun.(*instance.GenericFunction).AddMethod(nil, lambdaList, []ilos.Class{class.Object, classObject}, instance.NewFunction(writerFunctionName, func(e env.Environment, obj, object ilos.Instance) (ilos.Instance, ilos.Instance) { ok := object.(instance.Instance).SetSlotValue(obj, slotName, classObject) if ok { return obj, nil @@ -151,15 +151,15 @@ func Defclass(local environment.Environment, className, scNames, slotSpecs ilos. })) } if boundpFunctionName != nil { - lambdaList, err := List(local, instance.NewSymbol("INSTANCE")) + lambdaList, err := List(e, instance.NewSymbol("INSTANCE")) if err != nil { return nil, err } - if g, ok := local.Function.Get(boundpFunctionName); !ok || !ilos.InstanceOf(class.GenericFunction, g) { - Defgeneric(local, boundpFunctionName, lambdaList) + if g, ok := e.Function.Get(boundpFunctionName); !ok || !ilos.InstanceOf(class.GenericFunction, g) { + Defgeneric(e, boundpFunctionName, lambdaList) } - fun, _ := local.Function.Get(boundpFunctionName) - fun.(*instance.GenericFunction).AddMethod(nil, lambdaList, []ilos.Class{classObject}, instance.NewFunction(boundpFunctionName, func(local environment.Environment, object ilos.Instance) (ilos.Instance, ilos.Instance) { + fun, _ := e.Function.Get(boundpFunctionName) + fun.(*instance.GenericFunction).AddMethod(nil, lambdaList, []ilos.Class{classObject}, instance.NewFunction(boundpFunctionName, func(e env.Environment, object ilos.Instance) (ilos.Instance, ilos.Instance) { _, ok := object.(instance.Instance).GetSlotValue(slotName, classObject) if ok { return T, nil @@ -171,16 +171,16 @@ func Defclass(local environment.Environment, className, scNames, slotSpecs ilos. return className, nil } -func Create(local environment.Environment, c ilos.Instance, i ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Create(e env.Environment, c ilos.Instance, i ...ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.StandardClass, c); err != nil { return nil, err } - return instance.Create(local, c, i...), nil + return instance.Create(e, c, i...), nil } -func InitializeObject(local environment.Environment, object ilos.Instance, inits ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func InitializeObject(e env.Environment, object ilos.Instance, inits ...ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.StandardObject, object); err != nil { return nil, err } - return instance.InitializeObject(local, object, inits...), nil + return instance.InitializeObject(e, object, inits...), nil } diff --git a/runtime/defining_operators.go b/runtime/defining_operators.go index 909f037..076648d 100644 --- a/runtime/defining_operators.go +++ b/runtime/defining_operators.go @@ -5,7 +5,7 @@ package runtime import ( - "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/env" "github.com/ta2gch/iris/runtime/ilos" "github.com/ta2gch/iris/runtime/ilos/class" "github.com/ta2gch/iris/runtime/ilos/instance" @@ -14,20 +14,20 @@ import ( // Defconstant is used to define a named constant in the variable namespace of the current toplevel // scope. The scope of name is the entire current toplevel scope except the body form. // -// Although name is globally constant, a variable binding for name can be locally established by a +// Although name is globally constant, a variable binding for name can be ely established by a // binding form. // // The result of the evaluation of form is bound to the variable named by name. The binding and // the object created as the result of evaluating the second argument are immutable. The symbol named // name is returned. -func Defconstant(local environment.Environment, name, form ilos.Instance) (ilos.Instance, ilos.Instance) { +func Defconstant(e env.Environment, name, form ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Symbol, name); err != nil { return nil, err } if _, ok := TopLevel.Constant.Get(name); ok { return nil, instance.NewImmutableBinding() } - ret, err := Eval(local, form) + ret, err := Eval(e, form) if err != nil { return nil, err } @@ -42,16 +42,16 @@ func Defconstant(local environment.Environment, name, form ilos.Instance) (ilos. // defglobal is used only for defining variables and not for modifying them. The symbol named name is // returned. // -// A lexical variable binding for name can still be locally established by a binding form; in that -// case, the local binding lexically shadows the outer binding of name defined by deflocal. -func Defglobal(local environment.Environment, name, form ilos.Instance) (ilos.Instance, ilos.Instance) { +// A lexical variable binding for name can still be ely established by a binding form; in that +// case, the e binding lexically shadows the outer binding of name defined by defe. +func Defglobal(e env.Environment, name, form ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Symbol, name); err != nil { return nil, err } if _, ok := TopLevel.Constant.Get(name); ok { return nil, instance.NewImmutableBinding() } - ret, err := Eval(local, form) + ret, err := Eval(e, form) if err != nil { return nil, err } @@ -63,14 +63,14 @@ func Defglobal(local environment.Environment, name, form ilos.Instance) (ilos.In // The scope of name is the entire current toplevel scope except the body form. // //The symbol named name is returned. -func Defdynamic(local environment.Environment, name, form ilos.Instance) (ilos.Instance, ilos.Instance) { +func Defdynamic(e env.Environment, name, form ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Symbol, name); err != nil { return nil, err } if _, ok := TopLevel.Constant.Get(name); ok { return nil, instance.NewImmutableBinding() } - ret, err := Eval(local, form) + ret, err := Eval(e, form) if err != nil { return nil, err } @@ -88,11 +88,11 @@ func Defdynamic(local environment.Environment, name, form ilos.Instance) (ilos.I // defun returns the function name which is the symbol named function-name. The free identifiers in // the body form* (i.e., those which are not contained in the lambda list) follow the rules of lexical // scoping. -func Defun(local environment.Environment, functionName, lambdaList ilos.Instance, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Defun(e env.Environment, functionName, lambdaList ilos.Instance, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Symbol, functionName); err != nil { return nil, err } - ret, err := newNamedFunction(local, functionName, lambdaList, forms...) + ret, err := newNamedFunction(e, functionName, lambdaList, forms...) if err != nil { return nil, err } diff --git a/runtime/dynamic_variables.go b/runtime/dynamic_variables.go index df10178..1bd95ac 100644 --- a/runtime/dynamic_variables.go +++ b/runtime/dynamic_variables.go @@ -5,7 +5,7 @@ package runtime import ( - "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/env" "github.com/ta2gch/iris/runtime/ilos" "github.com/ta2gch/iris/runtime/ilos/class" "github.com/ta2gch/iris/runtime/ilos/instance" @@ -19,14 +19,14 @@ import ( // returned that was established most recently and is still in effect. An // error shall be signaled if such a binding does not exist // (error-id. unbound-variable). -func Dynamic(local environment.Environment, var1 ilos.Instance) (ilos.Instance, ilos.Instance) { +func Dynamic(e env.Environment, var1 ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Symbol, var1); err != nil { return nil, err } - if v, ok := local.DynamicVariable.Get(var1); ok { + if v, ok := e.DynamicVariable.Get(var1); ok { return v, nil } - if v, ok := local.DynamicVariable.Get(var1); ok { + if v, ok := e.DynamicVariable.Get(var1); ok { return v, nil } return nil, instance.NewUndefinedVariable(var1) @@ -41,18 +41,18 @@ func Dynamic(local environment.Environment, var1 ilos.Instance) (ilos.Instance, // An error shall be signaled if var has no dynamic value // (error-id. unbound-variable). setf of dynamic can be used only for // modifying bindings, and not for establishing them. -func SetDynamic(local environment.Environment, form, var1 ilos.Instance) (ilos.Instance, ilos.Instance) { +func SetDynamic(e env.Environment, form, var1 ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Symbol, var1); err != nil { return nil, err } - form, err := Eval(local, form) + form, err := Eval(e, form) if err != nil { return nil, form } - if local.DynamicVariable.Set(var1, form) { + if e.DynamicVariable.Set(var1, form) { return form, nil } - if local.DynamicVariable.Set(var1, form) { + if e.DynamicVariable.Set(var1, form) { return form, nil } return nil, instance.NewUndefinedVariable(var1) @@ -75,7 +75,7 @@ func SetDynamic(local environment.Environment, form, var1 ilos.Instance) (ilos.I // returned value of dynamic-let is that of the last body-form of the body (or // nil if there is none). The bindings are undone when control leaves the // prepared dynamic-let special form. -func DynamicLet(local environment.Environment, varForm ilos.Instance, bodyForm ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func DynamicLet(e env.Environment, varForm ilos.Instance, bodyForm ...ilos.Instance) (ilos.Instance, ilos.Instance) { vfs := map[ilos.Instance]ilos.Instance{} if err := ensure(class.List, varForm); err != nil { return nil, err @@ -87,16 +87,16 @@ func DynamicLet(local environment.Environment, varForm ilos.Instance, bodyForm . if cadr.(instance.List).Length() != 2 { return nil, instance.NewArityError() } - f, err := Eval(local, cadr.(instance.List).Nth(1)) + f, err := Eval(e, cadr.(instance.List).Nth(1)) if err != nil { return nil, err } vfs[cadr.(instance.List).Nth(0)] = f } for v, f := range vfs { - if !local.DynamicVariable.Define(v, f) { + if !e.DynamicVariable.Define(v, f) { return nil, instance.NewImmutableBinding() } } - return Progn(local, bodyForm...) + return Progn(e, bodyForm...) } diff --git a/runtime/env/environment.go b/runtime/env/environment.go new file mode 100644 index 0000000..dddd550 --- /dev/null +++ b/runtime/env/environment.go @@ -0,0 +1,154 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package env + +import ( + "github.com/ta2gch/iris/runtime/ilos" +) + +// Environment struct is the struct for keeping functions and variables +type Environment struct { + // Lexical + BlockTag stack + TagbodyTag stack + Function stack + Variable stack + + // Global + Class stack + Macro stack + Special stack + Property map2 + GensymID int + Constant stack + + // Dynamic + CatchTag stack + DynamicVariable stack // deep biding + StandardInput ilos.Instance + StandardOutput ilos.Instance + ErrorOutput ilos.Instance + Handler stack +} + +// New creates new eironment +func NewEnvironment(stdin, stdout, stderr ilos.Instance) Environment { + e := new(Environment) + + // Lexical + e.BlockTag = NewStack() + e.TagbodyTag = NewStack() + e.Function = NewStack() + e.Variable = NewStack() + + // Global + e.Macro = NewStack() + e.Class = NewStack() + e.Special = NewStack() + e.Constant = NewStack() + e.Property = NewMap2() + e.GensymID = 0 + + // Dynamic + e.CatchTag = NewStack() + e.DynamicVariable = NewStack() + e.StandardInput = stdin + e.StandardOutput = stdout + e.ErrorOutput = stderr + e.Handler = NewStack() + return *e +} + +func (e *Environment) MergeLexical(before Environment) { + e.BlockTag = append(before.BlockTag, e.BlockTag[1:]...) + e.TagbodyTag = append(before.TagbodyTag, e.TagbodyTag[1:]...) + e.Variable = append(before.Variable, e.Variable[1:]...) + e.Function = append(before.Function, e.Function[1:]...) + + e.Macro = append(before.Macro, e.Macro[1:]...) + e.Class = append(before.Class, e.Class[1:]...) + e.Special = append(before.Special, e.Special[1:]...) + e.Constant = append(before.Constant, e.Constant[1:]...) + e.Property = before.Property + e.GensymID = before.GensymID + + e.CatchTag = append(before.CatchTag, e.CatchTag[1:]...) + e.DynamicVariable = append(before.DynamicVariable, e.DynamicVariable[1:]...) + e.StandardInput = before.StandardInput + e.StandardOutput = before.StandardOutput + e.ErrorOutput = before.ErrorOutput + e.Handler = append(before.Handler, e.Handler[1:]...) +} + +func (e *Environment) MergeDynamic(before Environment) { + e.BlockTag = append(stack{before.BlockTag[0]}, e.BlockTag[1:]...) + e.TagbodyTag = append(stack{before.TagbodyTag[0]}, e.TagbodyTag[1:]...) + e.Variable = append(stack{before.Variable[0]}, e.Variable[1:]...) + e.Function = append(stack{before.Function[0]}, e.Function[1:]...) + + e.Macro = append(stack{before.Macro[0]}, e.Macro[1:]...) + e.Class = append(stack{before.Class[0]}, e.Class[1:]...) + e.Special = append(stack{before.Special[0]}, e.Special[1:]...) + e.Constant = append(stack{before.Constant[0]}, e.Constant[1:]...) + e.Property = before.Property + e.GensymID = before.GensymID + + e.CatchTag = append(before.CatchTag, e.CatchTag[1:]...) + e.DynamicVariable = append(before.DynamicVariable, e.DynamicVariable[1:]...) + e.StandardInput = before.StandardInput + e.StandardOutput = before.StandardOutput + e.ErrorOutput = before.ErrorOutput + e.Handler = append(before.Handler, e.Handler[1:]...) +} + +func (before *Environment) NewLexical() Environment { + e := NewEnvironment(before.StandardInput, before.StandardOutput, before.ErrorOutput) + + e.BlockTag = append(before.BlockTag, e.BlockTag[0]) + e.TagbodyTag = append(before.TagbodyTag, e.TagbodyTag[0]) + e.Variable = append(before.Variable, e.Variable[0]) + e.Function = append(before.Function, e.Function[0]) + + e.Macro = append(before.Macro, e.Macro[0]) + e.Class = append(before.Class, e.Class[0]) + e.Special = append(before.Special, e.Special[0]) + e.Constant = append(before.Constant, e.Constant[0]) + e.Property = before.Property + e.GensymID = before.GensymID + + e.CatchTag = append(before.CatchTag, e.CatchTag[0]) + e.DynamicVariable = append(before.DynamicVariable, e.DynamicVariable[0]) + e.StandardInput = before.StandardInput + e.StandardOutput = before.StandardOutput + e.ErrorOutput = before.ErrorOutput + e.Handler = append(before.Handler, e.Handler[0]) + + return e +} + +func (before *Environment) NewDynamic() Environment { + e := NewEnvironment(before.StandardInput, before.StandardOutput, before.ErrorOutput) + + e.BlockTag = append(stack{before.BlockTag[0]}, e.BlockTag[0]) + e.TagbodyTag = append(stack{before.TagbodyTag[0]}, e.TagbodyTag[0]) + e.Variable = append(stack{before.Variable[0]}, e.Variable[0]) + e.Function = append(stack{before.Function[0]}, e.Function[0]) + + e.Macro = append(stack{before.Macro[0]}, e.Macro[0]) + e.Class = append(stack{before.Class[0]}, e.Class[0]) + e.Special = append(stack{before.Special[0]}, e.Special[0]) + e.Constant = append(stack{before.Constant[0]}, e.Constant[0]) + e.Property = before.Property + e.GensymID = before.GensymID + + e.CatchTag = append(before.CatchTag, e.CatchTag[0]) + e.DynamicVariable = append(before.DynamicVariable, e.DynamicVariable[0]) + e.StandardInput = before.StandardInput + e.StandardOutput = before.StandardOutput + e.ErrorOutput = before.ErrorOutput + e.Handler = append(before.Handler, e.Handler[0]) + + return e +} diff --git a/runtime/environment/map2.go b/runtime/env/map2.go similarity index 97% rename from runtime/environment/map2.go rename to runtime/env/map2.go index 4d5fcb0..697c71e 100644 --- a/runtime/environment/map2.go +++ b/runtime/env/map2.go @@ -2,7 +2,7 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -package environment +package env import ( "github.com/ta2gch/iris/runtime/ilos" diff --git a/runtime/environment/stack.go b/runtime/env/stack.go similarity index 97% rename from runtime/environment/stack.go rename to runtime/env/stack.go index 9b72e46..c69dea5 100644 --- a/runtime/environment/stack.go +++ b/runtime/env/stack.go @@ -2,7 +2,7 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -package environment +package env import ( "github.com/ta2gch/iris/runtime/ilos" diff --git a/runtime/environment/environment.go b/runtime/environment/environment.go deleted file mode 100644 index 41f6485..0000000 --- a/runtime/environment/environment.go +++ /dev/null @@ -1,154 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at http://mozilla.org/MPL/2.0/. - -package environment - -import ( - "github.com/ta2gch/iris/runtime/ilos" -) - -// Environment struct is the struct for keeping functions and variables -type Environment struct { - // Lexical - BlockTag stack - TagbodyTag stack - Function stack - Variable stack - - // Global - Class stack - Macro stack - Special stack - Property map2 - GensymID int - Constant stack - - // Dynamic - CatchTag stack - DynamicVariable stack // deep biding - StandardInput ilos.Instance - StandardOutput ilos.Instance - ErrorOutput ilos.Instance - Handler stack -} - -// New creates new environment -func NewEnvironment(stdin, stdout, stderr ilos.Instance) Environment { - env := new(Environment) - - // Lexical - env.BlockTag = NewStack() - env.TagbodyTag = NewStack() - env.Function = NewStack() - env.Variable = NewStack() - - // Global - env.Macro = NewStack() - env.Class = NewStack() - env.Special = NewStack() - env.Constant = NewStack() - env.Property = NewMap2() - env.GensymID = 0 - - // Dynamic - env.CatchTag = NewStack() - env.DynamicVariable = NewStack() - env.StandardInput = stdin - env.StandardOutput = stdout - env.ErrorOutput = stderr - env.Handler = NewStack() - return *env -} - -func (env *Environment) Merge(before Environment) { - env.BlockTag = append(before.BlockTag, env.BlockTag[1:]...) - env.TagbodyTag = append(before.TagbodyTag, env.TagbodyTag[1:]...) - env.Variable = append(before.Variable, env.Variable[1:]...) - env.Function = append(before.Function, env.Function[1:]...) - - env.Macro = append(before.Macro, env.Macro[1:]...) - env.Class = append(before.Class, env.Class[1:]...) - env.Special = append(before.Special, env.Special[1:]...) - env.Constant = append(before.Constant, env.Constant[1:]...) - env.Property = before.Property - env.GensymID = before.GensymID - - env.CatchTag = append(before.CatchTag, env.CatchTag[1:]...) - env.DynamicVariable = append(before.DynamicVariable, env.DynamicVariable[1:]...) - env.StandardInput = before.StandardInput - env.StandardOutput = before.StandardOutput - env.ErrorOutput = before.ErrorOutput - env.Handler = append(before.Handler, env.Handler[1:]...) -} - -func (env *Environment) MergeDynamic(before Environment) { - env.BlockTag = append(stack{before.BlockTag[0]}, env.BlockTag[1:]...) - env.TagbodyTag = append(stack{before.TagbodyTag[0]}, env.TagbodyTag[1:]...) - env.Variable = append(stack{before.Variable[0]}, env.Variable[1:]...) - env.Function = append(stack{before.Function[0]}, env.Function[1:]...) - - env.Macro = append(stack{before.Macro[0]}, env.Macro[1:]...) - env.Class = append(stack{before.Class[0]}, env.Class[1:]...) - env.Special = append(stack{before.Special[0]}, env.Special[1:]...) - env.Constant = append(stack{before.Constant[0]}, env.Constant[1:]...) - env.Property = before.Property - env.GensymID = before.GensymID - - env.CatchTag = append(before.CatchTag, env.CatchTag[1:]...) - env.DynamicVariable = append(before.DynamicVariable, env.DynamicVariable[1:]...) - env.StandardInput = before.StandardInput - env.StandardOutput = before.StandardOutput - env.ErrorOutput = before.ErrorOutput - env.Handler = append(before.Handler, env.Handler[1:]...) -} - -func Push(before Environment) Environment { - env := NewEnvironment(before.StandardInput, before.StandardOutput, before.ErrorOutput) - - env.BlockTag = append(before.BlockTag, env.BlockTag[0]) - env.TagbodyTag = append(before.TagbodyTag, env.TagbodyTag[0]) - env.Variable = append(before.Variable, env.Variable[0]) - env.Function = append(before.Function, env.Function[0]) - - env.Macro = append(before.Macro, env.Macro[0]) - env.Class = append(before.Class, env.Class[0]) - env.Special = append(before.Special, env.Special[0]) - env.Constant = append(before.Constant, env.Constant[0]) - env.Property = before.Property - env.GensymID = before.GensymID - - env.CatchTag = append(before.CatchTag, env.CatchTag[0]) - env.DynamicVariable = append(before.DynamicVariable, env.DynamicVariable[0]) - env.StandardInput = before.StandardInput - env.StandardOutput = before.StandardOutput - env.ErrorOutput = before.ErrorOutput - env.Handler = append(before.Handler, env.Handler[0]) - - return env -} - -func PushDynamic(before Environment) Environment { - env := NewEnvironment(before.StandardInput, before.StandardOutput, before.ErrorOutput) - - env.BlockTag = append(stack{before.BlockTag[0]}, env.BlockTag[0]) - env.TagbodyTag = append(stack{before.TagbodyTag[0]}, env.TagbodyTag[0]) - env.Variable = append(stack{before.Variable[0]}, env.Variable[0]) - env.Function = append(stack{before.Function[0]}, env.Function[0]) - - env.Macro = append(stack{before.Macro[0]}, env.Macro[0]) - env.Class = append(stack{before.Class[0]}, env.Class[0]) - env.Special = append(stack{before.Special[0]}, env.Special[0]) - env.Constant = append(stack{before.Constant[0]}, env.Constant[0]) - env.Property = before.Property - env.GensymID = before.GensymID - - env.CatchTag = append(before.CatchTag, env.CatchTag[0]) - env.DynamicVariable = append(before.DynamicVariable, env.DynamicVariable[0]) - env.StandardInput = before.StandardInput - env.StandardOutput = before.StandardOutput - env.ErrorOutput = before.ErrorOutput - env.Handler = append(before.Handler, env.Handler[0]) - - return env -} diff --git a/runtime/equality.go b/runtime/equality.go index 3798118..e8c6b67 100644 --- a/runtime/equality.go +++ b/runtime/equality.go @@ -7,7 +7,7 @@ package runtime import ( "reflect" - "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/env" "github.com/ta2gch/iris/runtime/ilos" "github.com/ta2gch/iris/runtime/ilos/class" ) @@ -33,7 +33,7 @@ func isComparable(t reflect.Type) bool { // They return t if the objects are the same; otherwise, they return nil. // Two objects are the same if there is no operation that could distinguish // them (without modifying them), and if modifying one would modify the other the same way. -func Eq(local environment.Environment, obj1, obj2 ilos.Instance) (ilos.Instance, ilos.Instance) { +func Eq(e env.Environment, obj1, obj2 ilos.Instance) (ilos.Instance, ilos.Instance) { v1, v2 := reflect.ValueOf(obj1), reflect.ValueOf(obj2) if v1 == v2 || ilos.InstanceOf(class.Symbol, obj1) && ilos.InstanceOf(class.Symbol, obj2) && obj1 == obj2 { return T, nil @@ -45,7 +45,7 @@ func Eq(local environment.Environment, obj1, obj2 ilos.Instance) (ilos.Instance, // They return t if the objects are the same; otherwise, they return nil. // Two objects are the same if there is no operation that could distinguish // them (without modifying them), and if modifying one would modify the other the same way. -func Eql(local environment.Environment, obj1, obj2 ilos.Instance) (ilos.Instance, ilos.Instance) { +func Eql(e env.Environment, obj1, obj2 ilos.Instance) (ilos.Instance, ilos.Instance) { t1, t2 := reflect.TypeOf(obj1), reflect.TypeOf(obj2) if isComparable(t1) || isComparable(t2) { if obj1 == obj2 { @@ -65,7 +65,7 @@ func Eql(local environment.Environment, obj1, obj2 ilos.Instance) (ilos.Instance // Specifically: // // If obj1 and obj2 are direct instances of the same class, equal returns t if they are eql. -func Equal(local environment.Environment, obj1, obj2 ilos.Instance) (ilos.Instance, ilos.Instance) { +func Equal(e env.Environment, obj1, obj2 ilos.Instance) (ilos.Instance, ilos.Instance) { if reflect.DeepEqual(obj1, obj2) { return T, nil } diff --git a/runtime/eval.go b/runtime/eval.go index 8db2e59..9d46799 100644 --- a/runtime/eval.go +++ b/runtime/eval.go @@ -5,13 +5,13 @@ package runtime import ( - "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/env" "github.com/ta2gch/iris/runtime/ilos" "github.com/ta2gch/iris/runtime/ilos/class" "github.com/ta2gch/iris/runtime/ilos/instance" ) -func evalArguments(local environment.Environment, arguments ilos.Instance) (ilos.Instance, ilos.Instance) { +func evalArguments(e env.Environment, arguments ilos.Instance) (ilos.Instance, ilos.Instance) { // if arguments ends here if arguments == Nil { return Nil, nil @@ -21,11 +21,11 @@ func evalArguments(local environment.Environment, arguments ilos.Instance) (ilos } car := arguments.(*instance.Cons).Car // Checked there cdr := arguments.(*instance.Cons).Cdr // Checked there - a, err := Eval(local, car) + a, err := Eval(e, car) if err != nil { return nil, err } - b, err := evalArguments(local, cdr) + b, err := evalArguments(e, cdr) if err != nil { return nil, err } @@ -33,21 +33,21 @@ func evalArguments(local environment.Environment, arguments ilos.Instance) (ilos } -func evalLambda(local environment.Environment, car, cdr ilos.Instance) (ilos.Instance, ilos.Instance, bool) { +func evalLambda(e env.Environment, car, cdr ilos.Instance) (ilos.Instance, ilos.Instance, bool) { // eval if lambda form if ilos.InstanceOf(class.Cons, car) { caar := car.(*instance.Cons).Car // Checked at the top of// This sentence if caar == instance.NewSymbol("LAMBDA") { - fun, err := Eval(local, car) + fun, err := Eval(e, car) if err != nil { return nil, err, true } - arguments, err := evalArguments(local, cdr) + arguments, err := evalArguments(e, cdr) if err != nil { return nil, err, true } - ret, err := fun.(instance.Applicable).Apply(environment.PushDynamic(local), arguments.(instance.List).Slice()...) + ret, err := fun.(instance.Applicable).Apply(e.NewDynamic(), arguments.(instance.List).Slice()...) if err != nil { return nil, err, true } @@ -57,14 +57,14 @@ func evalLambda(local environment.Environment, car, cdr ilos.Instance) (ilos.Ins return nil, nil, false } -func evalSpecial(local environment.Environment, car, cdr ilos.Instance) (ilos.Instance, ilos.Instance, bool) { +func evalSpecial(e env.Environment, car, cdr ilos.Instance) (ilos.Instance, ilos.Instance, bool) { // get special instance has value of Function interface var spl ilos.Instance - if s, ok := local.Special.Get(car); ok { + if s, ok := e.Special.Get(car); ok { spl = s } if spl != nil { - ret, err := spl.(instance.Applicable).Apply(environment.Push(local), cdr.(instance.List).Slice()...) + ret, err := spl.(instance.Applicable).Apply(e.NewLexical(), cdr.(instance.List).Slice()...) if err != nil { return nil, err, true } @@ -73,18 +73,18 @@ func evalSpecial(local environment.Environment, car, cdr ilos.Instance) (ilos.In return nil, nil, false } -func evalMacro(local environment.Environment, car, cdr ilos.Instance) (ilos.Instance, ilos.Instance, bool) { +func evalMacro(e env.Environment, car, cdr ilos.Instance) (ilos.Instance, ilos.Instance, bool) { // get special instance has value of Function interface var mac ilos.Instance - if m, ok := local.Macro.Get(car); ok { + if m, ok := e.Macro.Get(car); ok { mac = m } if mac != nil { - ret, err := mac.(instance.Applicable).Apply(environment.PushDynamic(local), cdr.(instance.List).Slice()...) + ret, err := mac.(instance.Applicable).Apply(e.NewDynamic(), cdr.(instance.List).Slice()...) if err != nil { return nil, err, true } - ret, err = Eval(local, ret) + ret, err = Eval(e, ret) if err != nil { return nil, err, true } @@ -93,18 +93,18 @@ func evalMacro(local environment.Environment, car, cdr ilos.Instance) (ilos.Inst return nil, nil, false } -func evalFunction(local environment.Environment, car, cdr ilos.Instance) (ilos.Instance, ilos.Instance, bool) { +func evalFunction(e env.Environment, car, cdr ilos.Instance) (ilos.Instance, ilos.Instance, bool) { // get special instance has value of Function interface var fun ilos.Instance - if f, ok := local.Function.Get(car); ok { + if f, ok := e.Function.Get(car); ok { fun = f } if fun != nil { - arguments, err := evalArguments(local, cdr) + arguments, err := evalArguments(e, cdr) if err != nil { return nil, err, true } - ret, err := fun.(instance.Applicable).Apply(environment.PushDynamic(local), arguments.(instance.List).Slice()...) + ret, err := fun.(instance.Applicable).Apply(e.NewDynamic(), arguments.(instance.List).Slice()...) if err != nil { return nil, err, true } @@ -113,7 +113,7 @@ func evalFunction(local environment.Environment, car, cdr ilos.Instance) (ilos.I return nil, nil, false } -func evalCons(local environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { +func evalCons(e env.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Cons, obj); err != nil { return nil, err } @@ -121,48 +121,48 @@ func evalCons(local environment.Environment, obj ilos.Instance) (ilos.Instance, cdr := obj.(*instance.Cons).Cdr // Checked at the top of// This function // eval if lambda form - if a, b, c := evalLambda(local, car, cdr); c { + if a, b, c := evalLambda(e, car, cdr); c { return a, b } // get special instance has value of Function interface - if a, b, c := evalSpecial(local, car, cdr); c { + if a, b, c := evalSpecial(e, car, cdr); c { return a, b } // get macro instance has value of Function interface - if a, b, c := evalMacro(local, car, cdr); c { + if a, b, c := evalMacro(e, car, cdr); c { return a, b } // get function instance has value of Function interface - if a, b, c := evalFunction(local, car, cdr); c { + if a, b, c := evalFunction(e, car, cdr); c { return a, b } return nil, instance.NewUndefinedFunction(car) } -func evalVariable(local environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { - if val, ok := local.Variable.Get(obj); ok { +func evalVariable(e env.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { + if val, ok := e.Variable.Get(obj); ok { return val, nil } - if val, ok := local.Constant.Get(obj); ok { + if val, ok := e.Constant.Get(obj); ok { return val, nil } return nil, instance.NewUndefinedVariable(obj) } // Eval evaluates any classs -func Eval(local environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { +func Eval(e env.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { if obj == Nil { return Nil, nil } if ilos.InstanceOf(class.Symbol, obj) { - ret, err := evalVariable(local, obj) + ret, err := evalVariable(e, obj) if err != nil { return nil, err } return ret, nil } if ilos.InstanceOf(class.Cons, obj) { - ret, err := evalCons(local, obj) + ret, err := evalCons(e, obj) if err != nil { return nil, err } diff --git a/runtime/float_class.go b/runtime/float_class.go index 6d4029b..67a3a29 100644 --- a/runtime/float_class.go +++ b/runtime/float_class.go @@ -7,7 +7,7 @@ package runtime import ( "math" - "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/env" "github.com/ta2gch/iris/runtime/ilos" "github.com/ta2gch/iris/runtime/ilos/class" "github.com/ta2gch/iris/runtime/ilos/instance" @@ -25,7 +25,7 @@ var ( // Floatp returns t if obj is a float (instance of class float); // otherwise, returns nil. The obj may be any ISLISP object. -func Floatp(local environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { +func Floatp(e env.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { if ilos.InstanceOf(class.Float, obj) { return T, nil } @@ -35,7 +35,7 @@ func Floatp(local environment.Environment, obj ilos.Instance) (ilos.Instance, il // Float returns x itself if it is an instance of the class float // and returns a floating-point approximation of x otherwise. // An error shall be signaled if x is not a number (error-id. domain-error). -func Float(local environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { +func Float(e env.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { f, _, err := convFloat64(x) if err != nil { return nil, err @@ -46,7 +46,7 @@ func Float(local environment.Environment, x ilos.Instance) (ilos.Instance, ilos. // Floor returns the greatest integer less than or equal to x . // That is, x is truncated towards negative infinity. An error // shall be signaled if x is not a number (error-id. domain-error). -func Floor(local environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { +func Floor(e env.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { f, _, err := convFloat64(x) if err != nil { return nil, err @@ -57,7 +57,7 @@ func Floor(local environment.Environment, x ilos.Instance) (ilos.Instance, ilos. // Ceiling Returns the smallest integer that is not smaller than x. // That is, x is truncated towards positive infinity. An error // shall be signaled if x is not a number (error-id. domain-error). -func Ceiling(local environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { +func Ceiling(e env.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { f, _, err := convFloat64(x) if err != nil { return nil, err @@ -68,7 +68,7 @@ func Ceiling(local environment.Environment, x ilos.Instance) (ilos.Instance, ilo // Truncate returns the integer between 0 and x (inclusive) that is nearest to x. // That is, x is truncated towards zero. An error shall be signaled // if x is not a number (error-id. domain-error). -func Truncate(local environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { +func Truncate(e env.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { f, _, err := convFloat64(x) if err != nil { return nil, err @@ -79,7 +79,7 @@ func Truncate(local environment.Environment, x ilos.Instance) (ilos.Instance, il // Round returns the integer nearest to x. // If x is exactly halfway between two integers, the even one is chosen. // An error shall be signaled if x is not a number (error-id. domain-error). -func Round(local environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { +func Round(e env.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { f, _, err := convFloat64(x) if err != nil { return nil, err diff --git a/runtime/functions.go b/runtime/functions.go index 150225d..b3b27f0 100644 --- a/runtime/functions.go +++ b/runtime/functions.go @@ -5,7 +5,7 @@ package runtime import ( - "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/env" "github.com/ta2gch/iris/runtime/ilos" "github.com/ta2gch/iris/runtime/ilos/class" "github.com/ta2gch/iris/runtime/ilos/instance" @@ -19,7 +19,7 @@ import ( // A function binding is an association between an identifier, function-name, // and a function object that is denoted by function-name—if in operator // position—or by (function function-name) elsewhere. -func Functionp(local environment.Environment, fun ilos.Instance) (ilos.Instance, ilos.Instance) { +func Functionp(e env.Environment, fun ilos.Instance) (ilos.Instance, ilos.Instance) { if ilos.InstanceOf(class.Function, fun) { return T, nil } @@ -29,17 +29,17 @@ func Functionp(local environment.Environment, fun ilos.Instance) (ilos.Instance, // Function returns the function object named by function-name. // // An error shall be signaled if no binding has been established for the identifier -// in the function namespace of current lexical environment (error-id. undefined-function). +// in the function namespace of current lexical eironment (error-id. undefined-function). // The consequences are undefined if the function-name names a macro or special form -func Function(local environment.Environment, fun ilos.Instance) (ilos.Instance, ilos.Instance) { +func Function(e env.Environment, fun ilos.Instance) (ilos.Instance, ilos.Instance) { // car must be a symbol if err := ensure(class.Symbol, fun); err != nil { return nil, err } - if f, ok := local.Function.Get(fun); ok { + if f, ok := e.Function.Get(fun); ok { return f, nil } - if f, ok := local.Function.Get(fun); ok { + if f, ok := e.Function.Get(fun); ok { return f, nil } return nil, instance.NewUndefinedFunction(fun) @@ -62,18 +62,18 @@ func Function(local environment.Environment, fun ilos.Instance) (ilos.Instance, // // Once the lambda variables have been bound, the body is executed. // If the body is empty, nil is returned otherwise the result of the evaluation of -// the last form of body is returned if the body was not left by a non-local exit. +// the last form of body is returned if the body was not left by a non-e exit. // // If the function receives a &rest or :rest parameter R, the list L1 to which that // parameter is bound has indefinite extent. L1 is newly allocated unless the function // was called with apply and R corresponds to the final argument, L2 , to that call // to apply (or some subtail of L2), in which case it is implementation defined whether // L1 shares structure with L2 . -func Lambda(local environment.Environment, lambdaList ilos.Instance, form ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Lambda(e env.Environment, lambdaList ilos.Instance, form ...ilos.Instance) (ilos.Instance, ilos.Instance) { if err := checkLambdaList(lambdaList); err != nil { return nil, err } - return newNamedFunction(local, instance.NewSymbol("ANONYMOUS-FUNCTION"), lambdaList, form...) + return newNamedFunction(e, instance.NewSymbol("ANONYMOUS-FUNCTION"), lambdaList, form...) } // Labels special form allow the definition of new identifiers in the function @@ -85,13 +85,13 @@ func Lambda(local environment.Environment, lambdaList ilos.Instance, form ...ilo // each function-name is bound to a function object whose behavior is equivalent // to (lambda lambda-list form*), where free identifier references are resolved as follows: // -// For a labels form, such free references are resolved in the lexical environment +// For a labels form, such free references are resolved in the lexical eironment // that was active immediately outside the labels form augmented by the function // bindings for the given function-names (i.e., any reference to a function // function-name refers to a binding created by the labels). // // For a flet form, free identifier references in the lambda-expression are resolved -// in the lexical environment that was active immediately outside the flet form +// in the lexical eironment that was active immediately outside the flet form // (i.e., any reference to a function function-name are not visible). // // During activation, the prepared labels or flet establishes function bindings and @@ -99,7 +99,7 @@ func Lambda(local environment.Environment, lambdaList ilos.Instance, form ...ilo // (or nil if there is none) is the value returned by the special form activation. // // No function-name may appear more than once in the function bindings. -func Labels(local environment.Environment, functions ilos.Instance, bodyForm ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Labels(e env.Environment, functions ilos.Instance, bodyForm ...ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.List, functions); err != nil { return nil, err } @@ -114,24 +114,24 @@ func Labels(local environment.Environment, functions ilos.Instance, bodyForm ... functionName := definition[0] lambdaList := definition[1] forms := definition[2:] - fun, err := newNamedFunction(local, functionName, lambdaList, forms...) + fun, err := newNamedFunction(e, functionName, lambdaList, forms...) if err != nil { return nil, err } - if !local.Function.Define(functionName, fun) { + if !e.Function.Define(functionName, fun) { return nil, instance.NewImmutableBinding() } } - return Progn(local, bodyForm...) + return Progn(e, bodyForm...) } // Flet special form allow the definition of new identifiers in the function // namespace for function objects (see Labels). -func Flet(local environment.Environment, functions ilos.Instance, bodyForm ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Flet(e env.Environment, functions ilos.Instance, bodyForm ...ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.List, functions); err != nil { return nil, err } - env := environment.Push(local) + newEnv := e.NewLexical() for _, function := range functions.(instance.List).Slice() { if err := ensure(class.List, function); err != nil { return nil, err @@ -143,15 +143,15 @@ func Flet(local environment.Environment, functions ilos.Instance, bodyForm ...il functionName := definition[0] lambdaList := definition[1] forms := definition[2:] - fun, err := newNamedFunction(local, functionName, lambdaList, forms...) + fun, err := newNamedFunction(e, functionName, lambdaList, forms...) if err != nil { return nil, err } - if !env.Function.Define(functionName, fun) { + if !newEnv.Function.Define(functionName, fun) { return nil, instance.NewImmutableBinding() } } - return Progn(env, bodyForm...) + return Progn(newEnv, bodyForm...) } // Apply applies function to the arguments, obj*, followed by the elements of list, @@ -160,7 +160,7 @@ func Flet(local environment.Environment, functions ilos.Instance, bodyForm ...il // An error shall be signaled if function is not a function (error-id. domain-error). // Each obj may be any ISLISP object. An error shall be signaled // if list is not a proper list (error-id. improper-argument-list). -func Apply(local environment.Environment, function ilos.Instance, obj ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Apply(e env.Environment, function ilos.Instance, obj ...ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Function, function); err != nil { return nil, err } @@ -168,7 +168,7 @@ func Apply(local environment.Environment, function ilos.Instance, obj ...ilos.In return nil, err } obj = append(obj[:len(obj)-1], obj[len(obj)-1].(instance.List).Slice()...) - return function.(instance.Applicable).Apply(local, obj...) + return function.(instance.Applicable).Apply(e, obj...) } // Funcall activates the specified function function and returns the value that the function returns. @@ -176,7 +176,7 @@ func Apply(local environment.Environment, function ilos.Instance, obj ...ilos.In // // An error shall be signaled if function is not a function (error-id. domain-error). // Each obj may be any ISLISP object. -func Funcall(local environment.Environment, function ilos.Instance, obj ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Funcall(e env.Environment, function ilos.Instance, obj ...ilos.Instance) (ilos.Instance, ilos.Instance) { obj = append(obj, Nil) - return Apply(local, function, obj...) + return Apply(e, function, obj...) } diff --git a/runtime/generic_functions.go b/runtime/generic_functions.go index 4a28d0a..cd3ce3d 100644 --- a/runtime/generic_functions.go +++ b/runtime/generic_functions.go @@ -5,13 +5,13 @@ package runtime import ( - "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/env" "github.com/ta2gch/iris/runtime/ilos" "github.com/ta2gch/iris/runtime/ilos/class" "github.com/ta2gch/iris/runtime/ilos/instance" ) -func Defmethod(local environment.Environment, arguments ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Defmethod(e env.Environment, arguments ...ilos.Instance) (ilos.Instance, ilos.Instance) { if len(arguments) < 2 { return nil, instance.NewArityError() } @@ -30,7 +30,7 @@ func Defmethod(local environment.Environment, arguments ...ilos.Instance) (ilos. parameterList = append(parameterList, pp.(instance.List).Nth(0)) } } - lambdaList, err := List(local, parameterList...) + lambdaList, err := List(e, parameterList...) if err != nil { return nil, err } @@ -49,7 +49,7 @@ func Defmethod(local environment.Environment, arguments ...ilos.Instance) (ilos. classList = append(classList, class.(ilos.Class)) } } - fun, err := newNamedFunction(local, name, lambdaList, arguments[i+2:]...) + fun, err := newNamedFunction(e, name, lambdaList, arguments[i+2:]...) if err != nil { return nil, err } @@ -63,7 +63,7 @@ func Defmethod(local environment.Environment, arguments ...ilos.Instance) (ilos. return name, nil } -func Defgeneric(local environment.Environment, funcSpec, lambdaList ilos.Instance, optionsOrMethodDescs ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Defgeneric(e env.Environment, funcSpec, lambdaList ilos.Instance, optionsOrMethodDescs ...ilos.Instance) (ilos.Instance, ilos.Instance) { var methodCombination ilos.Instance genericFunctionClass := class.StandardGenericFunction forms := []ilos.Instance{} @@ -82,6 +82,6 @@ func Defgeneric(local environment.Environment, funcSpec, lambdaList ilos.Instanc } } TopLevel.Function.Define(funcSpec, instance.NewGenericFunction(funcSpec, lambdaList, methodCombination, genericFunctionClass)) - Progn(local, forms...) + Progn(e, forms...) return funcSpec, nil } diff --git a/runtime/ilos/instance/error.go b/runtime/ilos/instance/error.go index 24044fc..f9accec 100644 --- a/runtime/ilos/instance/error.go +++ b/runtime/ilos/instance/error.go @@ -9,7 +9,7 @@ import ( "runtime" "strings" - "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/env" "github.com/ta2gch/iris/runtime/ilos" ) @@ -35,28 +35,28 @@ func stackTrace() { } func NewArithmeticError(operation, operands ilos.Instance) ilos.Instance { - return Create(environment.NewEnvironment(nil, nil, nil), + return Create(env.NewEnvironment(nil, nil, nil), ArithmeticErrorClass, NewSymbol("OPERATION"), operation, NewSymbol("OPERANDS"), operands) } func NewDivisionByZero(operation, operands ilos.Instance) ilos.Instance { - return Create(environment.NewEnvironment(nil, nil, nil), + return Create(env.NewEnvironment(nil, nil, nil), DivisionByZeroClass, NewSymbol("OPERATION"), operation, NewSymbol("OPERANDS"), operands) } func NewParseError(str, expectedClass ilos.Instance) ilos.Instance { - return Create(environment.NewEnvironment(nil, nil, nil), + return Create(env.NewEnvironment(nil, nil, nil), ParseErrorClass, NewSymbol("STRING"), str, NewSymbol("EXPECTED-CLASS"), expectedClass) } func NewDomainError(object ilos.Instance, expectedClass ilos.Class) ilos.Instance { - return Create(environment.NewEnvironment(nil, nil, nil), + return Create(env.NewEnvironment(nil, nil, nil), DomainErrorClass, NewSymbol("CAUSE"), NewSymbol("DOMAIN-ERROR"), NewSymbol("OBJECT"), object, @@ -64,21 +64,21 @@ func NewDomainError(object ilos.Instance, expectedClass ilos.Class) ilos.Instanc } func NewUndefinedFunction(name ilos.Instance) ilos.Instance { - return Create(environment.NewEnvironment(nil, nil, nil), + return Create(env.NewEnvironment(nil, nil, nil), UndefinedFunctionClass, NewSymbol("NAME"), name, NewSymbol("NAMESPACE"), NewSymbol("FUNCTION")) } func NewUndefinedVariable(name ilos.Instance) ilos.Instance { - return Create(environment.NewEnvironment(nil, nil, nil), + return Create(env.NewEnvironment(nil, nil, nil), UndefinedVariableClass, NewSymbol("NAME"), name, NewSymbol("NAMESPACE"), NewSymbol("VARIABLE")) } func NewUndefinedClass(name ilos.Instance) ilos.Instance { - return Create(environment.NewEnvironment(nil, nil, nil), + return Create(env.NewEnvironment(nil, nil, nil), UndefinedEntityClass, NewSymbol("NAME"), name, NewSymbol("NAMESPACE"), NewSymbol("CLASS")) @@ -86,26 +86,26 @@ func NewUndefinedClass(name ilos.Instance) ilos.Instance { func NewArityError() ilos.Instance { stackTrace() - return Create(environment.NewEnvironment(nil, nil, nil), ProgramErrorClass) + return Create(env.NewEnvironment(nil, nil, nil), ProgramErrorClass) } func NewIndexOutOfRange() ilos.Instance { stackTrace() - return Create(environment.NewEnvironment(nil, nil, nil), ProgramErrorClass) + return Create(env.NewEnvironment(nil, nil, nil), ProgramErrorClass) } func NewImmutableBinding() ilos.Instance { stackTrace() - return Create(environment.NewEnvironment(nil, nil, nil), ProgramErrorClass) + return Create(env.NewEnvironment(nil, nil, nil), ProgramErrorClass) } func NewSimpleError(formatString, formatArguments ilos.Instance) ilos.Instance { - return Create(environment.NewEnvironment(nil, nil, nil), + return Create(env.NewEnvironment(nil, nil, nil), SimpleErrorClass, NewSymbol("FORMAT-STRING"), formatString, NewSymbol("FORMAT-ARGUMENTS"), formatArguments) } func NewControlError() ilos.Instance { - return Create(environment.NewEnvironment(nil, nil, nil), ControlErrorClass) + return Create(env.NewEnvironment(nil, nil, nil), ControlErrorClass) } diff --git a/runtime/ilos/instance/function.go b/runtime/ilos/instance/function.go index 570b86d..7f9c5e5 100644 --- a/runtime/ilos/instance/function.go +++ b/runtime/ilos/instance/function.go @@ -9,12 +9,12 @@ import ( "reflect" "sort" - "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/env" "github.com/ta2gch/iris/runtime/ilos" ) type Applicable interface { - Apply(environment.Environment, ...ilos.Instance) (ilos.Instance, ilos.Instance) + Apply(env.Environment, ...ilos.Instance) (ilos.Instance, ilos.Instance) } type Function struct { @@ -34,10 +34,10 @@ func (f Function) String() string { return fmt.Sprintf("#%v", f.Class()) } -func (f Function) Apply(local environment.Environment, arguments ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func (f Function) Apply(e env.Environment, arguments ...ilos.Instance) (ilos.Instance, ilos.Instance) { fv := reflect.ValueOf(f.function) ft := reflect.TypeOf(f.function) - argv := []reflect.Value{reflect.ValueOf(local)} + argv := []reflect.Value{reflect.ValueOf(e)} for _, cadr := range arguments { argv = append(argv, reflect.ValueOf(cadr)) } @@ -98,7 +98,7 @@ func (f *GenericFunction) String() string { return fmt.Sprintf("#%v", f.Class()) } -func (f *GenericFunction) Apply(local environment.Environment, arguments ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func (f *GenericFunction) Apply(e env.Environment, arguments ...ilos.Instance) (ilos.Instance, ilos.Instance) { parameters := f.lambdaList.(List).Slice() variadic := false { @@ -139,34 +139,34 @@ func (f *GenericFunction) Apply(local environment.Environment, arguments ...ilos return t[methods[a].qualifier] > t[methods[b].qualifier] }) - nextMethodPisNil := NewFunction(NewSymbol("NEXT-METHOD-P"), func(local environment.Environment) (ilos.Instance, ilos.Instance) { + nextMethodPisNil := NewFunction(NewSymbol("NEXT-METHOD-P"), func(e env.Environment) (ilos.Instance, ilos.Instance) { return Nil, nil }) - nextMethodPisT := NewFunction(NewSymbol("NEXT-METHOD-P"), func(local environment.Environment) (ilos.Instance, ilos.Instance) { + nextMethodPisT := NewFunction(NewSymbol("NEXT-METHOD-P"), func(e env.Environment) (ilos.Instance, ilos.Instance) { return T, nil }) if f.methodCombination == NewSymbol("NIL") { - var callNextMethod func(local environment.Environment) (ilos.Instance, ilos.Instance) // To Recursive - callNextMethod = func(local environment.Environment) (ilos.Instance, ilos.Instance) { // CALL-NEXT-METHOD - depth, _ := local.DynamicVariable.Get(NewSymbol("IRIS/DEPTH")) // Get previous depth - index := int(depth.(Integer)) + 1 // Get index of next method - local.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) // Set current depth - // If Generic Function has no next-mehtods, NEXT-METHOD-P local function returns nil - local.Function.Define(NewSymbol("NEXT-METHOD-P"), NewFunction(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil)) + var callNextMethod func(e env.Environment) (ilos.Instance, ilos.Instance) // To Recursive + callNextMethod = func(e env.Environment) (ilos.Instance, ilos.Instance) { // CALL-NEXT-METHOD + depth, _ := e.DynamicVariable.Get(NewSymbol("IRIS/DEPTH")) // Get previous depth + index := int(depth.(Integer)) + 1 // Get index of next method + e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) // Set current depth + // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil + e.Function.Define(NewSymbol("NEXT-METHOD-P"), NewFunction(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil)) if int(depth.(Integer))+1 < len(methods) { // If Generic Function has next method, set these functionss - local.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) - local.Function.Define(NewSymbol("NEXT-METHOD-P"), NewFunction(NewSymbol("NEXT-METHOD-P"), nextMethodPisT)) + e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) + e.Function.Define(NewSymbol("NEXT-METHOD-P"), NewFunction(NewSymbol("NEXT-METHOD-P"), nextMethodPisT)) } - return methods[index].function.Apply(local, arguments...) // Call next method + return methods[index].function.Apply(e, arguments...) // Call next method } - local.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(0)) // Set current depth - // If Generic Function has no next-mehtods, NEXT-METHOD-P local function returns nil - local.Function.Define(NewSymbol("NEXT-METHOD-P"), NewFunction(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil)) + e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(0)) // Set current depth + // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil + e.Function.Define(NewSymbol("NEXT-METHOD-P"), NewFunction(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil)) if 1 < len(methods) { // If Generic Function has next method, set these functionss - local.Function.Define(NewSymbol("NEXT-METHOD-P"), NewFunction(NewSymbol("NEXT-METHOD-P"), nextMethodPisT)) - local.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) + e.Function.Define(NewSymbol("NEXT-METHOD-P"), NewFunction(NewSymbol("NEXT-METHOD-P"), nextMethodPisT)) + e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } - return methods[0].function.Apply(local, arguments...) //Call first of method + return methods[0].function.Apply(e, arguments...) //Call first of method } // if f.methodCombination == NewSymbol("STANDARD") { @@ -174,132 +174,132 @@ func (f *GenericFunction) Apply(local environment.Environment, arguments ...ilos width := len(methods) if index := sort.Search(width, test); index < width { // if has :around methods // This callNextMethod is called in :around methods - var callNextMethod func(local environment.Environment) (ilos.Instance, ilos.Instance) - callNextMethod = func(local environment.Environment) (ilos.Instance, ilos.Instance) { - depth, _ := local.DynamicVariable.Get(NewSymbol("IRIS/DEPTH")) // Get previous depth + var callNextMethod func(e env.Environment) (ilos.Instance, ilos.Instance) + callNextMethod = func(e env.Environment) (ilos.Instance, ilos.Instance) { + depth, _ := e.DynamicVariable.Get(NewSymbol("IRIS/DEPTH")) // Get previous depth for index, method := range methods[:int(depth.(Integer))+1] { if method.qualifier == around { // If have :around method - local.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) // Set Current depth - // If Generic Function has no next-mehtods, NEXT-METHOD-P local function returns nil - local.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) + e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) // Set Current depth + // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil + e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) { // If Generic Function has next method, set these functionss width := len(methods) - index - 1 test := func(i int) bool { return methods[index+i+1].qualifier == nil || methods[index+i+1].qualifier == around } if sort.Search(width, test) < width { - local.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) - local.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) + e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) + e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } } - return methods[int(depth.(Integer))].function.Apply(local, arguments...) // Call next method + return methods[int(depth.(Integer))].function.Apply(e, arguments...) // Call next method } } // If has no :around method then, // Do All :before mehtods for _, method := range methods { if method.qualifier == before { - if _, err := method.function.Apply(local, arguments...); err != nil { + if _, err := method.function.Apply(e, arguments...); err != nil { return nil, err } } } // Do the first of primary methods // this callNextMethod is called in primary methods - var callNextMethod func(local environment.Environment) (ilos.Instance, ilos.Instance) - callNextMethod = func(local environment.Environment) (ilos.Instance, ilos.Instance) { - depth, _ := local.DynamicVariable.Get(NewSymbol("IRIS/DEPTH")) // Get previous depth - index := int(depth.(Integer)) // Convert depth to integer + var callNextMethod func(e env.Environment) (ilos.Instance, ilos.Instance) + callNextMethod = func(e env.Environment) (ilos.Instance, ilos.Instance) { + depth, _ := e.DynamicVariable.Get(NewSymbol("IRIS/DEPTH")) // Get previous depth + index := int(depth.(Integer)) // Convert depth to integer { width := len(methods) - index - 1 test := func(i int) bool { return methods[index+i+1].qualifier == nil } - index = sort.Search(width, test) // Get index of next mehotd - local.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) // Set current depth + index = sort.Search(width, test) // Get index of next mehotd + e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) // Set current depth } - // If Generic Function has no next-mehtods, NEXT-METHOD-P local function returns nil - local.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) + // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil + e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) { // If Generic Function has next method, set these functionss width := len(methods) - index - 1 test := func(i int) bool { return methods[index+i+1].qualifier == nil } if sort.Search(width, test) < width { - local.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) - local.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) + e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) + e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } } - return methods[index].function.Apply(local, arguments...) // Call next method + return methods[index].function.Apply(e, arguments...) // Call next method } // callNextMethod ends here index := 0 // index of the first primary method { // index != 0 is always true because this function has :around methods width := len(methods) - index - 1 test := func(i int) bool { return methods[index+i+1].qualifier == nil } index = sort.Search(width, test) - local.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) + e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) } - // If Generic Function has no next-mehtods, NEXT-METHOD-P local function returns nil - local.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) + // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil + e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) { // If Generic Function has next method, set these functionss test := func(i int) bool { return methods[index+i+1].qualifier == nil } width := len(methods) - index - 1 if sort.Search(width, test) < width { - local.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) - local.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) + e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) + e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } } // Do primary methods - ret, err := methods[index].function.Apply(local, arguments...) + ret, err := methods[index].function.Apply(e, arguments...) if err != nil { return nil, err } // Do all :after methods for i := len(methods) - 1; i >= 0; i-- { if methods[i].qualifier == after { - if _, err := methods[i].function.Apply(local, arguments...); err != nil { + if _, err := methods[i].function.Apply(e, arguments...); err != nil { return nil, err } } } return ret, err } - local.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) // Set Current depth - // If Generic Function has no next-mehtods, NEXT-METHOD-P local function returns nil - local.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) + e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) // Set Current depth + // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil + e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) { // If Generic Function has next method, set these functionss test := func(i int) bool { return methods[index+i+1].qualifier == nil } width := len(methods) - index - 1 if sort.Search(width, test) < width { - local.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) - local.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) + e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) + e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } } - return methods[index].function.Apply(local, arguments...) + return methods[index].function.Apply(e, arguments...) } } { // Function has no :around methods // This callNextMethod is called in primary methods - var callNextMethod func(local environment.Environment) (ilos.Instance, ilos.Instance) - callNextMethod = func(local environment.Environment) (ilos.Instance, ilos.Instance) { - depth, _ := local.DynamicVariable.Get(NewSymbol("IRIS/DEPTH")) // Get previous depth - index := int(depth.(Integer)) // Convert depth to integer + var callNextMethod func(e env.Environment) (ilos.Instance, ilos.Instance) + callNextMethod = func(e env.Environment) (ilos.Instance, ilos.Instance) { + depth, _ := e.DynamicVariable.Get(NewSymbol("IRIS/DEPTH")) // Get previous depth + index := int(depth.(Integer)) // Convert depth to integer { test := func(i int) bool { return methods[index+i+1].qualifier == nil } width := len(methods) - index - 1 index = sort.Search(width, test) } - local.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) // Set Current depth - // If Generic Function has no next-mehtods, NEXT-METHOD-P local function returns nil - local.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) + e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) // Set Current depth + // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil + e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) { // If Generic Function has next method, set these functionss test := func(i int) bool { return methods[index+i+1].qualifier == nil } width := len(methods) - index - 1 if sort.Search(width, test) < width { - local.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) - local.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) + e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) + e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } } - return methods[int(depth.(Integer))].function.Apply(local, arguments...) + return methods[int(depth.(Integer))].function.Apply(e, arguments...) } // callNextMethod ends here // Do All :before mehtods for _, method := range methods { if method.qualifier == before { - if _, err := method.function.Apply(local, arguments...); err != nil { + if _, err := method.function.Apply(e, arguments...); err != nil { return nil, err } } @@ -309,25 +309,25 @@ func (f *GenericFunction) Apply(local environment.Environment, arguments ...ilos test := func(i int) bool { return methods[i].qualifier == nil } width := len(methods) index := sort.Search(width, test) - local.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) + e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) if index == len(methods) { return nil, NewUndefinedFunction(f.funcSpec) } } - local.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) + e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) { // If Generic Function has next method, set these functions test := func(i int) bool { return methods[index+i+1].qualifier == nil } width := len(methods) - index - 1 if sort.Search(width, test) < width { - local.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) - local.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) + e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) + e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } } - ret, err := methods[index].function.Apply(local, arguments...) + ret, err := methods[index].function.Apply(e, arguments...) // Do all :after methods for i := len(methods) - 1; i >= 0; i-- { if methods[i].qualifier == after { - if _, err := methods[i].function.Apply(local, arguments...); err != nil { + if _, err := methods[i].function.Apply(e, arguments...); err != nil { return nil, err } } diff --git a/runtime/ilos/instance/instance.go b/runtime/ilos/instance/instance.go index d602676..556bbf1 100644 --- a/runtime/ilos/instance/instance.go +++ b/runtime/ilos/instance/instance.go @@ -8,7 +8,7 @@ import ( "fmt" "reflect" - "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/env" "github.com/ta2gch/iris/runtime/ilos" ) @@ -16,17 +16,17 @@ import ( // instance // -func Create(local environment.Environment, c ilos.Instance, i ...ilos.Instance) ilos.Instance { +func Create(e env.Environment, c ilos.Instance, i ...ilos.Instance) ilos.Instance { p := []ilos.Instance{} for _, q := range c.(ilos.Class).Supers() { - p = append(p, Create(local, q, i...)) + p = append(p, Create(e, q, i...)) } - return InitializeObject(local, Instance{c.(ilos.Class), p, map[ilos.Instance]ilos.Instance{}}, i...) + return InitializeObject(e, Instance{c.(ilos.Class), p, map[ilos.Instance]ilos.Instance{}}, i...) } -func InitializeObject(local environment.Environment, object ilos.Instance, inits ...ilos.Instance) ilos.Instance { +func InitializeObject(e env.Environment, object ilos.Instance, inits ...ilos.Instance) ilos.Instance { for _, super := range object.(Instance).supers { - InitializeObject(local, super, inits...) + InitializeObject(e, super, inits...) } for i := 0; i < len(inits); i += 2 { argName := inits[i] @@ -43,7 +43,7 @@ func InitializeObject(local environment.Environment, object ilos.Instance, inits for _, slotName := range object.Class().Slots() { if _, ok := object.(Instance).GetSlotValue(slotName, object.Class()); !ok { if form, ok := object.Class().Initform(slotName); ok { - value, _ := form.(Applicable).Apply(local) + value, _ := form.(Applicable).Apply(e) object.(Instance).SetSlotValue(slotName, value, object.Class()) } } diff --git a/runtime/ilos/instance/tag.go b/runtime/ilos/instance/tag.go index a27ac22..d3184df 100644 --- a/runtime/ilos/instance/tag.go +++ b/runtime/ilos/instance/tag.go @@ -5,22 +5,22 @@ package instance import ( - "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/env" "github.com/ta2gch/iris/runtime/ilos" ) func NewBlockTag(tag, object ilos.Instance) ilos.Instance { - return Create(environment.NewEnvironment(nil, nil, nil), + return Create(env.NewEnvironment(nil, nil, nil), BlockTagClass, NewSymbol("TAG"), tag, NewSymbol("OBJECT"), object) } func NewCatchTag(tag, object ilos.Instance) ilos.Instance { - return Create(environment.NewEnvironment(nil, nil, nil), + return Create(env.NewEnvironment(nil, nil, nil), CatchTagClass, NewSymbol("TAG"), tag, NewSymbol("OBJECT"), object) } func NewTagbodyTag(tag ilos.Instance) ilos.Instance { - return Create(environment.NewEnvironment(nil, nil, nil), TagbodyTagClass, NewSymbol("TAG"), tag) + return Create(env.NewEnvironment(nil, nil, nil), TagbodyTagClass, NewSymbol("TAG"), tag) } diff --git a/runtime/integer_class.go b/runtime/integer_class.go index 2a97d8a..6f11b40 100644 --- a/runtime/integer_class.go +++ b/runtime/integer_class.go @@ -7,7 +7,7 @@ package runtime import ( "math" - "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/env" "github.com/ta2gch/iris/runtime/ilos" "github.com/ta2gch/iris/runtime/ilos/class" "github.com/ta2gch/iris/runtime/ilos/instance" @@ -22,7 +22,7 @@ func convInt(z ilos.Instance) (int, ilos.Instance) { // Integerp returns t if obj is an integer (instance of class integer); // otherwise, returns nil. obj may be any ISLISP object. -func Integerp(local environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { +func Integerp(e env.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { if ilos.InstanceOf(class.Integer, obj) { return T, nil } @@ -31,7 +31,7 @@ func Integerp(local environment.Environment, obj ilos.Instance) (ilos.Instance, // Div returns the greatest integer less than or equal to the quotient of z1 and z2. // An error shall be signaled if z2 is zero (error-id. division-by-zero). -func Div(local environment.Environment, z1, z2 ilos.Instance) (ilos.Instance, ilos.Instance) { +func Div(e env.Environment, z1, z2 ilos.Instance) (ilos.Instance, ilos.Instance) { a, err := convInt(z1) if err != nil { return nil, err @@ -42,7 +42,7 @@ func Div(local environment.Environment, z1, z2 ilos.Instance) (ilos.Instance, il } if b == 0 { operation := instance.NewSymbol("DIV") - operands, err := List(local, z1, z2) + operands, err := List(e, z1, z2) if err != nil { return nil, err } @@ -57,7 +57,7 @@ func Div(local environment.Environment, z1, z2 ilos.Instance) (ilos.Instance, il // and this result is divisible by z2 without remainder. // // An error shall be signaled if either z1 or z2 is not an integer (error-id. domain-error). -func Mod(local environment.Environment, z1, z2 ilos.Instance) (ilos.Instance, ilos.Instance) { +func Mod(e env.Environment, z1, z2 ilos.Instance) (ilos.Instance, ilos.Instance) { a, err := convInt(z1) if err != nil { return nil, err @@ -68,7 +68,7 @@ func Mod(local environment.Environment, z1, z2 ilos.Instance) (ilos.Instance, il } if b == 0 { operation := instance.NewSymbol("MOD") - operands, err := List(local, z1, z2) + operands, err := List(e, z1, z2) if err != nil { return nil, err } @@ -84,7 +84,7 @@ func Mod(local environment.Environment, z1, z2 ilos.Instance) (ilos.Instance, il // // An error shall be signaled if either z1 or z2 is not an integer // (error-id. domain-error). -func Gcd(local environment.Environment, z1, z2 ilos.Instance) (ilos.Instance, ilos.Instance) { +func Gcd(e env.Environment, z1, z2 ilos.Instance) (ilos.Instance, ilos.Instance) { gcd := func(x, y int) int { for y != 0 { x, y = y, x%y @@ -106,7 +106,7 @@ func Gcd(local environment.Environment, z1, z2 ilos.Instance) (ilos.Instance, il // // An error shall be signaled if either z1 or z2 is not an integer // (error-id. domain-error). -func Lcm(local environment.Environment, z1, z2 ilos.Instance) (ilos.Instance, ilos.Instance) { +func Lcm(e env.Environment, z1, z2 ilos.Instance) (ilos.Instance, ilos.Instance) { gcd := func(x, y int) int { for y != 0 { x, y = y, x%y @@ -127,7 +127,7 @@ func Lcm(local environment.Environment, z1, z2 ilos.Instance) (ilos.Instance, il // Isqrt Returns the greatest integer less than or equal to // the exact positive square root of z . An error shall be signaled // if z is not a non-negative integer (error-id. domain-error). -func Isqrt(local environment.Environment, z ilos.Instance) (ilos.Instance, ilos.Instance) { +func Isqrt(e env.Environment, z ilos.Instance) (ilos.Instance, ilos.Instance) { a, err := convInt(z) if err != nil { return nil, err diff --git a/runtime/iteration.go b/runtime/iteration.go index a51ced4..7cce174 100644 --- a/runtime/iteration.go +++ b/runtime/iteration.go @@ -5,7 +5,7 @@ package runtime import ( - "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/env" "github.com/ta2gch/iris/runtime/ilos" "github.com/ta2gch/iris/runtime/ilos/class" "github.com/ta2gch/iris/runtime/ilos/instance" @@ -20,17 +20,17 @@ import ( // 3. Otherwise, if Vt is non-nil, the forms body-form* are evaluated sequentially (from left to right). // // 4. Upon successful completion of the body-forms*, the while form begins again with step 1. -func While(local environment.Environment, testForm ilos.Instance, bodyForm ...ilos.Instance) (ilos.Instance, ilos.Instance) { - test, err := Eval(local, testForm) +func While(e env.Environment, testForm ilos.Instance, bodyForm ...ilos.Instance) (ilos.Instance, ilos.Instance) { + test, err := Eval(e, testForm) if err != nil { return nil, err } for test == T { - _, err := Progn(local, bodyForm...) + _, err := Progn(e, bodyForm...) if err != nil { return nil, err } - test, err = Eval(local, testForm) + test, err = Eval(e, testForm) if err != nil { return nil, err } @@ -39,7 +39,7 @@ func While(local environment.Environment, testForm ilos.Instance, bodyForm ...il } // For repeatedly executes a sequence of forms form*, called its body. It specifies a set of identifiers naming -// variables that will be local to the for form, their initialization, and their update for each iteration. +// variables that will be e to the for form, their initialization, and their update for each iteration. // When a termination condition is met, the iteration exits with a specified result value. // // The scope of an identifier var is the body, the steps, the end-test , and the result *. A step might be omitted, @@ -55,7 +55,7 @@ func While(local environment.Environment, testForm ilos.Instance, bodyForm ...il // order from left to right. Then their values are assigned to the corresponding variables and the next iteration begins. // If end-test returns a non-nil value, then the result * are evaluated sequentially and the value of the // last one is returned as value of the whole for macro. If no result is present, then the value of the for macro is nil. -func For(local environment.Environment, iterationSpecs, endTestAndResults ilos.Instance, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func For(e env.Environment, iterationSpecs, endTestAndResults ilos.Instance, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.List, iterationSpecs); err != nil { return nil, err } @@ -68,7 +68,7 @@ func For(local environment.Environment, iterationSpecs, endTestAndResults ilos.I case 2, 3: var1 := i[0] init := i[1] - if !local.Variable.Define(var1, init) { + if !e.Variable.Define(var1, init) { return nil, instance.NewImmutableBinding() } default: @@ -84,12 +84,12 @@ func For(local environment.Environment, iterationSpecs, endTestAndResults ilos.I } endTest := ends[0] results := ends[1:] - test, err := Eval(local, endTest) + test, err := Eval(e, endTest) if err != nil { return nil, err } for test == Nil { - _, err := Progn(local, forms...) + _, err := Progn(e, forms...) if err != nil { return nil, err } @@ -102,17 +102,17 @@ func For(local environment.Environment, iterationSpecs, endTestAndResults ilos.I case 3: var1 := is.(instance.List).Nth(0) step := is.(instance.List).Nth(2) - if local.Variable.Set(var1, step) { + if e.Variable.Set(var1, step) { return nil, instance.NewImmutableBinding() } default: return nil, instance.NewArityError() } } - test, err = Eval(local, endTest) + test, err = Eval(e, endTest) if err != nil { return nil, err } } - return Progn(local, results...) + return Progn(e, results...) } diff --git a/runtime/list_operations.go b/runtime/list_operations.go index 59808c0..391c9c9 100644 --- a/runtime/list_operations.go +++ b/runtime/list_operations.go @@ -7,7 +7,7 @@ package runtime import ( "math" - "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/env" "github.com/ta2gch/iris/runtime/ilos" "github.com/ta2gch/iris/runtime/ilos/class" "github.com/ta2gch/iris/runtime/ilos/instance" @@ -15,7 +15,7 @@ import ( // Listp returns t if obj is a list (instance of class list); otherwise, returns nil. // obj may be any ISLISP object. -func Listp(local environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { +func Listp(e env.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { if ilos.InstanceOf(class.Cons, obj) { return T, nil } @@ -27,7 +27,7 @@ func Listp(local environment.Environment, obj ilos.Instance) (ilos.Instance, ilo // error shall be signaled if the requested list cannot be allocated (error-id. cannot-create-list). // An error shall be signaled if i is not a non-negative integer (error-id. domain-error). //initial-element may be any ISLISP object. -func CreateList(local environment.Environment, i ilos.Instance, initialElement ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func CreateList(e env.Environment, i ilos.Instance, initialElement ...ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Integer, i); err != nil { return nil, err } @@ -48,7 +48,7 @@ func CreateList(local environment.Environment, i ilos.Instance, initialElement . // List returns a new list whose length is the number of arguments and whose elements are the // arguments in the same order as in the list-form. An error shall be signaled if the requested list // cannot be allocated (error-id. cannot-create-list). Each obj may be any ISLISP object. -func List(local environment.Environment, objs ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func List(e env.Environment, objs ...ilos.Instance) (ilos.Instance, ilos.Instance) { cons := Nil for i := len(objs) - 1; i >= 0; i-- { cons = instance.NewCons(objs[i], cons) @@ -61,7 +61,7 @@ func List(local environment.Environment, objs ...ilos.Instance) (ilos.Instance, // // For reverse, no side-effect to the given list occurs. The resulting list is permitted but not // required to share structure with the input list. -func Reverse(local environment.Environment, list ilos.Instance) (ilos.Instance, ilos.Instance) { +func Reverse(e env.Environment, list ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.List, list); err != nil { return nil, err } @@ -78,7 +78,7 @@ func Reverse(local environment.Environment, list ilos.Instance) (ilos.Instance, // For nreverse, the conses which make up the top level of the given list are permitted, but not // required, to be side-effected in order to produce this new list. nreverse should never be called // on a literal object. -func Nreverse(local environment.Environment, list ilos.Instance) (ilos.Instance, ilos.Instance) { +func Nreverse(e env.Environment, list ilos.Instance) (ilos.Instance, ilos.Instance) { // TODO: tests literal object if err := ensure(class.List, list); err != nil { return nil, err @@ -97,10 +97,10 @@ func Nreverse(local environment.Environment, list ilos.Instance) (ilos.Instance, // result shares structure with its list arguments. // // An error shall be signaled if the list cannot be allocated (error-id. cannot-create-list). -func Append(local environment.Environment, lists ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Append(e env.Environment, lists ...ilos.Instance) (ilos.Instance, ilos.Instance) { // Ref: https://github.com/sbcl/sbcl/blob/fe4faef65315c6ad52b3b89b62b6c6497cb78d09/src/code/list.lisp#L364 - result, err := List(local, Nil) + result, err := List(e, Nil) if err != nil { return nil, err } @@ -110,7 +110,7 @@ func Append(local environment.Environment, lists ...ilos.Instance) (ilos.Instanc } for _, list := range lists { for _, elt := range list.(instance.List).Slice() { - it, err := List(local, elt) + it, err := List(e, elt) if err != nil { return nil, err } @@ -124,7 +124,7 @@ func Append(local environment.Environment, lists ...ilos.Instance) (ilos.Instanc // Member returnes the first sublist of list whose car is obj if list contains at least one // occurrence of obj (as determined by eql). Otherwise, nil is returned. An error shall be signaled // if list is not a list (error-id. domain-error). -func Member(local environment.Environment, obj, list ilos.Instance) (ilos.Instance, ilos.Instance) { +func Member(e env.Environment, obj, list ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.List, list); err != nil { return nil, err } @@ -140,7 +140,7 @@ func Member(local environment.Environment, obj, list ilos.Instance) (ilos.Instan // each list, then to the second element of each list, and so on. The iteration terminates when the // shortest list runs out, and excess elements in other lists are ignored. The value returned by // mapcar is a list of the results of successive calls to function. -func Mapcar(local environment.Environment, function, list1 ilos.Instance, lists ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Mapcar(e env.Environment, function, list1 ilos.Instance, lists ...ilos.Instance) (ilos.Instance, ilos.Instance) { lists = append([]ilos.Instance{list1}, lists...) if err := ensure(class.Function, function); err != nil { return nil, err @@ -158,18 +158,18 @@ func Mapcar(local environment.Environment, function, list1 ilos.Instance, lists for j, list := range lists { arguments[j] = list.(instance.List).Nth(i) } - ret, err := function.(instance.Applicable).Apply(local, arguments...) + ret, err := function.(instance.Applicable).Apply(e, arguments...) if err != nil { return nil, err } result = append(result, ret) } - return List(local, result...) + return List(e, result...) } // Mapc is like mapcar except that the results of applying function are not accumulated; // list1 is returned. -func Mapc(local environment.Environment, function, list1 ilos.Instance, lists ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Mapc(e env.Environment, function, list1 ilos.Instance, lists ...ilos.Instance) (ilos.Instance, ilos.Instance) { lists = append([]ilos.Instance{list1}, lists...) if err := ensure(class.Function, function); err != nil { return nil, err @@ -186,7 +186,7 @@ func Mapc(local environment.Environment, function, list1 ilos.Instance, lists .. for j, list := range lists { arguments[j] = list.(instance.List).Nth(i) } - if _, err := function.(instance.Applicable).Apply(local, arguments...); err != nil { + if _, err := function.(instance.Applicable).Apply(e, arguments...); err != nil { return nil, err } } @@ -196,7 +196,7 @@ func Mapc(local environment.Environment, function, list1 ilos.Instance, lists .. // Mapcan is like mapcar respectively, except that the results of applying // function are combined into a list by the use of an operation that performs a destructive form of // append rather than list. -func Mapcan(local environment.Environment, function, list1 ilos.Instance, lists ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Mapcan(e env.Environment, function, list1 ilos.Instance, lists ...ilos.Instance) (ilos.Instance, ilos.Instance) { lists = append([]ilos.Instance{list1}, lists...) if err := ensure(class.Function, function); err != nil { return nil, err @@ -214,19 +214,19 @@ func Mapcan(local environment.Environment, function, list1 ilos.Instance, lists for j, list := range lists { arguments[j] = list.(instance.List).Nth(i) } - ret, err := function.(instance.Applicable).Apply(local, arguments...) + ret, err := function.(instance.Applicable).Apply(e, arguments...) if err != nil { return nil, err } result = append(result, ret) } - return Append(local, result...) + return Append(e, result...) } // Maplist is like mapcar except that function is applied to successive sublists of the lists. // function is first applied to the lists themselves, and then to the cdr of each list, and then to // the cdr of the cdr of each list, and so on. -func Maplist(local environment.Environment, function, list1 ilos.Instance, lists ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Maplist(e env.Environment, function, list1 ilos.Instance, lists ...ilos.Instance) (ilos.Instance, ilos.Instance) { lists = append([]ilos.Instance{list1}, lists...) if err := ensure(class.Function, function); err != nil { return nil, err @@ -244,18 +244,18 @@ func Maplist(local environment.Environment, function, list1 ilos.Instance, lists for j, list := range lists { arguments[j] = list.(instance.List).NthCdr(i) } - ret, err := function.(instance.Applicable).Apply(local, arguments...) + ret, err := function.(instance.Applicable).Apply(e, arguments...) if err != nil { return nil, err } result = append(result, ret) } - return List(local, result...) + return List(e, result...) } // Mapl is like maplist except that the results of applying function are not accumulated; // list1 is returned. -func Mapl(local environment.Environment, function, list1 ilos.Instance, lists ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Mapl(e env.Environment, function, list1 ilos.Instance, lists ...ilos.Instance) (ilos.Instance, ilos.Instance) { lists = append([]ilos.Instance{list1}, lists...) if err := ensure(class.Function, function); err != nil { return nil, err @@ -272,7 +272,7 @@ func Mapl(local environment.Environment, function, list1 ilos.Instance, lists .. for j, list := range lists { arguments[j] = list.(instance.List).NthCdr(i) } - if _, err := function.(instance.Applicable).Apply(local, arguments...); err != nil { + if _, err := function.(instance.Applicable).Apply(e, arguments...); err != nil { return nil, err } } @@ -282,7 +282,7 @@ func Mapl(local environment.Environment, function, list1 ilos.Instance, lists .. // Mapcon is like maplist respectively, except that the results of applying // function are combined into a list by the use of an operation that performs a destructive form of // append rather than list. -func Mapcon(local environment.Environment, function, list1 ilos.Instance, lists ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Mapcon(e env.Environment, function, list1 ilos.Instance, lists ...ilos.Instance) (ilos.Instance, ilos.Instance) { lists = append([]ilos.Instance{list1}, lists...) if err := ensure(class.Function, function); err != nil { return nil, err @@ -300,19 +300,19 @@ func Mapcon(local environment.Environment, function, list1 ilos.Instance, lists for j, list := range lists { arguments[j] = list.(instance.List).NthCdr(i) } - ret, err := function.(instance.Applicable).Apply(local, arguments...) + ret, err := function.(instance.Applicable).Apply(e, arguments...) if err != nil { return nil, err } result = append(result, ret) } - return Append(local, result...) + return Append(e, result...) } // Assoc returns the first cons if assocation-list contains at least one cons whose car is // obj (as determined by eql). Otherwise, nil is returned. An error shall be signaled // if association-list is not a list of conses (error-id. domain-error). -func Assoc(local environment.Environment, obj, associationList ilos.Instance) (ilos.Instance, ilos.Instance) { +func Assoc(e env.Environment, obj, associationList ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.List, associationList); err != nil { return nil, err } diff --git a/runtime/logical_connectives.go b/runtime/logical_connectives.go index ba80181..6b748de 100644 --- a/runtime/logical_connectives.go +++ b/runtime/logical_connectives.go @@ -5,13 +5,13 @@ package runtime import ( - "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/env" "github.com/ta2gch/iris/runtime/ilos" ) // Not is the logical “not” (or “¬”). It returns t if obj is nil // and nil otherwise. obj may be any ISLISP object. -func Not(local environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { +func Not(e env.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { if obj == Nil { return T, nil } @@ -22,12 +22,12 @@ func Not(local environment.Environment, obj ilos.Instance) (ilos.Instance, ilos. // from left to right until either one of them evaluates to nil or else // none are left. If one of them evaluates to nil, then nil is returned // from the and; otherwise, the value of the last evaluated form is returned. -func And(local environment.Environment, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func And(e env.Environment, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { var ret ilos.Instance for _, form := range forms { - //fmt.Printf("%v\n%#v\n", form, local.Variable) + //fmt.Printf("%v\n%#v\n", form, e.Variable) var err ilos.Instance - ret, err = Eval(local, form) + ret, err = Eval(e, form) if err != nil { return nil, err } @@ -45,11 +45,11 @@ func And(local environment.Environment, forms ...ilos.Instance) (ilos.Instance, // from left to right until either one of them evaluates to a non-nil value // or else none are left. If one of them evaluates to a non-nil value, // then this non-nil value is returned, otherwise nil is returned. -func Or(local environment.Environment, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Or(e env.Environment, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { var ret ilos.Instance for _, form := range forms { var err ilos.Instance - ret, err = Eval(local, form) + ret, err = Eval(e, form) if err != nil { return nil, err } diff --git a/runtime/macros.go b/runtime/macros.go index 7990a57..4256522 100644 --- a/runtime/macros.go +++ b/runtime/macros.go @@ -5,7 +5,7 @@ package runtime import ( - "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/env" "github.com/ta2gch/iris/runtime/ilos" "github.com/ta2gch/iris/runtime/ilos/class" "github.com/ta2gch/iris/runtime/ilos/instance" @@ -16,15 +16,15 @@ import ( // must be an identifier whose scope is the current toplevel scope in which the // defmacro form appears. lambda-list is as defined in page 23. The definition // point of macro-name is the closing parenthesis of the lambda-list. -func Defmacro(local environment.Environment, macroName, lambdaList ilos.Instance, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Defmacro(e env.Environment, macroName, lambdaList ilos.Instance, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Symbol, macroName); err != nil { return nil, err } - ret, err := newNamedFunction(local, macroName, lambdaList, forms...) + ret, err := newNamedFunction(e, macroName, lambdaList, forms...) if err != nil { return nil, err } - local.Macro.Define(macroName, ret) + e.Macro.Define(macroName, ret) return macroName, nil } @@ -45,11 +45,11 @@ func Defmacro(local environment.Environment, macroName, lambdaList ilos.Instance // expressions appearing at the same nesting level, which increases by one // inside each successive quasiquotation and decreases by one inside each // unquotation. -func Quasiquote(local environment.Environment, form ilos.Instance) (ilos.Instance, ilos.Instance) { - return expand(local, form, 0) +func Quasiquote(e env.Environment, form ilos.Instance) (ilos.Instance, ilos.Instance) { + return expand(e, form, 0) } -func expand(local environment.Environment, form ilos.Instance, level int) (ilos.Instance, ilos.Instance) { +func expand(e env.Environment, form ilos.Instance, level int) (ilos.Instance, ilos.Instance) { if !ilos.InstanceOf(class.Cons, form) { return form, nil } // If form is a instance of then, @@ -61,7 +61,7 @@ func expand(local environment.Environment, form ilos.Instance, level int) (ilos. // To expand `((foo ,(- 10 3)) ,@(cdr '(c)) . ,(car '(cons))) if cadr == instance.NewSymbol("UNQUOTE") && level == 0 { caddr := cddr.(*instance.Cons).Car - elt, err := Eval(local, caddr) + elt, err := Eval(e, caddr) if err != nil { return nil, err } @@ -69,7 +69,7 @@ func expand(local environment.Environment, form ilos.Instance, level int) (ilos. break } if !ilos.InstanceOf(class.Cons, cadr) { - lst, err := List(local, cadr) + lst, err := List(e, cadr) if err != nil { return nil, err } @@ -83,11 +83,11 @@ func expand(local environment.Environment, form ilos.Instance, level int) (ilos. cadadr := cdadr.(*instance.Cons).Car var elt, err ilos.Instance if level == 0 { - elt, err = Eval(local, cadadr) + elt, err = Eval(e, cadadr) if err != nil { return nil, err } - lst, err := List(local, elt) + lst, err := List(e, elt) if err != nil { return nil, err } @@ -95,15 +95,15 @@ func expand(local environment.Environment, form ilos.Instance, level int) (ilos. cdr = cdr.(*instance.Cons).Cdr continue } else { - elt, err = expand(local, cadadr, level-1) + elt, err = expand(e, cadadr, level-1) if err != nil { return nil, err } - lst, err := List(local, caadr, elt) + lst, err := List(e, caadr, elt) if err != nil { return nil, err } - lstlst, err := List(local, lst) + lstlst, err := List(e, lst) if err != nil { return nil, err } @@ -115,7 +115,7 @@ func expand(local environment.Environment, form ilos.Instance, level int) (ilos. if caadr == instance.NewSymbol("UNQUOTE-SPLICING") { cadadr := cdadr.(*instance.Cons).Car if level == 0 { - elt, err := Eval(local, cadadr) + elt, err := Eval(e, cadadr) if err != nil { return nil, err } @@ -123,15 +123,15 @@ func expand(local environment.Environment, form ilos.Instance, level int) (ilos. cdr = cdr.(*instance.Cons).Cdr continue } else { - elt, err := expand(local, cadadr, level-1) + elt, err := expand(e, cadadr, level-1) if err != nil { return nil, err } - lst, err := List(local, caadr, elt) + lst, err := List(e, caadr, elt) if err != nil { return nil, err } - lstlst, err := List(local, lst) + lstlst, err := List(e, lst) if err != nil { return nil, err } @@ -142,15 +142,15 @@ func expand(local environment.Environment, form ilos.Instance, level int) (ilos. } if caadr == instance.NewSymbol("QUASIQUOTE") { cadadr := cdadr.(*instance.Cons).Car - elt, err := expand(local, cadadr, level+1) + elt, err := expand(e, cadadr, level+1) if err != nil { return nil, err } - lst, err := List(local, caadr, elt) + lst, err := List(e, caadr, elt) if err != nil { return nil, err } - lstlst, err := List(local, lst) + lstlst, err := List(e, lst) if err != nil { return nil, err } @@ -159,11 +159,11 @@ func expand(local environment.Environment, form ilos.Instance, level int) (ilos. continue } // If the cadr is not special forms then, - elt, err := expand(local, cadr, level) + elt, err := expand(e, cadr, level) if err != nil { return nil, err } - lst, err := List(local, elt) + lst, err := List(e, elt) if err != nil { return nil, err } @@ -178,7 +178,7 @@ func expand(local environment.Environment, form ilos.Instance, level int) (ilos. for i := len(exp) - 2; i >= 0; i-- { if ilos.InstanceOf(class.List, lst) { var err ilos.Instance - lst, err = Append(local, exp[i], lst) + lst, err = Append(e, exp[i], lst) if err != nil { return nil, err } diff --git a/runtime/namedfunc.go b/runtime/namedfunc.go index ee34849..0bc20a0 100644 --- a/runtime/namedfunc.go +++ b/runtime/namedfunc.go @@ -5,7 +5,7 @@ package runtime import ( - "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/env" "github.com/ta2gch/iris/runtime/ilos" "github.com/ta2gch/iris/runtime/ilos/class" "github.com/ta2gch/iris/runtime/ilos/instance" @@ -28,8 +28,8 @@ func checkLambdaList(lambdaList ilos.Instance) ilos.Instance { return nil } -func newNamedFunction(local environment.Environment, functionName, lambdaList ilos.Instance, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { - lexical := local +func newNamedFunction(e env.Environment, functionName, lambdaList ilos.Instance, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { + lexical := e if err := ensure(class.Symbol, functionName); err != nil { return nil, err } @@ -44,8 +44,8 @@ func newNamedFunction(local environment.Environment, functionName, lambdaList il } parameters = append(parameters, cadr) } - return instance.NewFunction(functionName.(instance.Symbol), func(local environment.Environment, arguments ...ilos.Instance) (ilos.Instance, ilos.Instance) { - local.Merge(lexical) + return instance.NewFunction(functionName.(instance.Symbol), func(e env.Environment, arguments ...ilos.Instance) (ilos.Instance, ilos.Instance) { + e.MergeLexical(lexical) if (variadic && len(parameters)-2 > len(arguments)) || (!variadic && len(parameters) != len(arguments)) { return nil, instance.NewArityError() } @@ -53,20 +53,20 @@ func newNamedFunction(local environment.Environment, functionName, lambdaList il key := parameters[idx] if key == instance.NewSymbol(":REST") || key == instance.NewSymbol("&REST") { key := parameters[idx+1] - value, err := List(local, arguments[idx:]...) + value, err := List(e, arguments[idx:]...) if err != nil { return nil, err } - if !local.Variable.Define(key, value) { + if !e.Variable.Define(key, value) { return nil, instance.NewImmutableBinding() } break } value := arguments[idx] - if !local.Variable.Define(key, value) { + if !e.Variable.Define(key, value) { return nil, instance.NewImmutableBinding() } } - return Progn(local, forms...) + return Progn(e, forms...) }), nil } diff --git a/runtime/non-local_exits.go b/runtime/non-local_exits.go index a11eb69..23c5878 100644 --- a/runtime/non-local_exits.go +++ b/runtime/non-local_exits.go @@ -5,55 +5,55 @@ package runtime import ( - "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/env" "github.com/ta2gch/iris/runtime/ilos" "github.com/ta2gch/iris/runtime/ilos/class" "github.com/ta2gch/iris/runtime/ilos/instance" ) /* -ISLISP defines three ways in which to perform non-local exits: +ISLISP defines three ways in which to perform non-e exits: Destination Kind Established by Invoked by Operation Performed block name block return-from lexical exit tagbody tag tagbody go lexical transfer of control catch tag atch throw dynamic exit -A non-local exit, is an operation that forces transfer of control and possibly +A non-e exit, is an operation that forces transfer of control and possibly data from an invoking special form to a previously established point in a program, called the destination of the exit. -A lexical exit is a non-local exit from a return-from form to a block form +A lexical exit is a non-e exit from a return-from form to a block form which contains it both lexically and dynamically, forcing the block to return an object specified in the return-from form. -A dynamic exit is a non-local exit from a throw form to a catch form +A dynamic exit is a non-e exit from a throw form to a catch form which contains it dynamically (but not necessarily lexically), forcing the catch to return an object specified in the throw form. -A lexical transfer of control is a non-local exit from a go form to a tagged point +A lexical transfer of control is a non-e exit from a go form to a tagged point in a tagbody form which contains it both lexically and dynamically. -When a non-local exit is initiated, any potential destination that was established +When a non-e exit is initiated, any potential destination that was established more recently than the destination to which control is being transferred is immediately considered invalid. */ -func Block(local environment.Environment, tag ilos.Instance, body ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Block(e env.Environment, tag ilos.Instance, body ...ilos.Instance) (ilos.Instance, ilos.Instance) { var err ilos.Instance - tag, err = Eval(local, tag) // Checked at the top of// This function + tag, err = Eval(e, tag) // Checked at the top of// This function if err != nil { return nil, err } if ilos.InstanceOf(class.Number, tag) || ilos.InstanceOf(class.Character, tag) { return nil, instance.NewDomainError(tag, class.Object) } - if !local.BlockTag.Define(tag, nil) { + if !e.BlockTag.Define(tag, nil) { return nil, instance.NewImmutableBinding() } var fail ilos.Instance sucess := Nil for _, cadr := range body { - sucess, fail = Eval(local, cadr) + sucess, fail = Eval(e, cadr) if fail != nil { if ilos.InstanceOf(class.BlockTag, fail) { tag1, _ := fail.(instance.Instance).GetSlotValue(instance.NewSymbol("TAG"), class.Escape) // Checked at the head of// This condition @@ -68,41 +68,41 @@ func Block(local environment.Environment, tag ilos.Instance, body ...ilos.Instan return sucess, nil } -func ReturnFrom(local environment.Environment, tag, object ilos.Instance) (ilos.Instance, ilos.Instance) { +func ReturnFrom(e env.Environment, tag, object ilos.Instance) (ilos.Instance, ilos.Instance) { var err ilos.Instance - tag, err = Eval(local, tag) + tag, err = Eval(e, tag) if err != nil { return nil, err } if ilos.InstanceOf(class.Number, tag) || ilos.InstanceOf(class.Character, tag) { return nil, instance.NewDomainError(tag, class.Object) } - object, err = Eval(local, object) + object, err = Eval(e, object) if err != nil { return nil, err } - if _, ok := local.BlockTag.Get(tag); !ok { + if _, ok := e.BlockTag.Get(tag); !ok { return nil, instance.NewSimpleError(instance.NewString("%v is not defined as the tag"), tag) } return nil, instance.NewBlockTag(tag, object) } -func Catch(local environment.Environment, tag ilos.Instance, body ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Catch(e env.Environment, tag ilos.Instance, body ...ilos.Instance) (ilos.Instance, ilos.Instance) { var err ilos.Instance - tag, err = Eval(local, tag) + tag, err = Eval(e, tag) if err != nil { return nil, err } if ilos.InstanceOf(class.Number, tag) || ilos.InstanceOf(class.Character, tag) { return nil, instance.NewDomainError(tag, class.Object) } - if !local.CatchTag.Define(tag, nil) { + if !e.CatchTag.Define(tag, nil) { return nil, instance.NewImmutableBinding() } var fail ilos.Instance sucess := Nil for _, cadr := range body { - sucess, fail = Eval(local, cadr) + sucess, fail = Eval(e, cadr) if fail != nil { if ilos.InstanceOf(class.CatchTag, fail) { tag1, _ := fail.(instance.Instance).GetSlotValue(instance.NewSymbol("TAG"), class.Escape) // Checked at the head of// This condition @@ -117,38 +117,38 @@ func Catch(local environment.Environment, tag ilos.Instance, body ...ilos.Instan return sucess, nil } -func Throw(local environment.Environment, tag, object ilos.Instance) (ilos.Instance, ilos.Instance) { +func Throw(e env.Environment, tag, object ilos.Instance) (ilos.Instance, ilos.Instance) { var err ilos.Instance - tag, err = Eval(local, tag) + tag, err = Eval(e, tag) if err != nil { return nil, err } if ilos.InstanceOf(class.Number, tag) || ilos.InstanceOf(class.Character, tag) { return nil, instance.NewDomainError(tag, class.Object) } - object, err = Eval(local, object) + object, err = Eval(e, object) if err != nil { return nil, err } - if _, ok := local.CatchTag.Get(tag); !ok { + if _, ok := e.CatchTag.Get(tag); !ok { return nil, instance.NewSimpleError(instance.NewString("%v is not defined as the tag"), tag) } return nil, instance.NewCatchTag(tag, object) } -func Tagbody(local environment.Environment, body ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Tagbody(e env.Environment, body ...ilos.Instance) (ilos.Instance, ilos.Instance) { for idx, cadr := range body { cddr := instance.GeneralVector(body[idx+1:]) if !ilos.InstanceOf(class.Cons, cadr) { - if !local.TagbodyTag.Define(cadr, cddr) { + if !e.TagbodyTag.Define(cadr, cddr) { return nil, instance.NewImmutableBinding() } } } for _, cadr := range body { if ilos.InstanceOf(class.Cons, cadr) { - _, fail := Eval(local, cadr) + _, fail := Eval(e, cadr) if fail != nil { TAG: if ilos.InstanceOf(class.TagbodyTag, fail) { @@ -161,10 +161,10 @@ func Tagbody(local environment.Environment, body ...ilos.Instance) (ilos.Instanc } } if found { - forms, _ := local.TagbodyTag.Get(tag) // Checked in the function, tagbodyGo + forms, _ := e.TagbodyTag.Get(tag) // Checked in the function, tagbodyGo for _, form := range forms.(instance.GeneralVector) { if ilos.InstanceOf(class.Cons, form) { - _, fail = Eval(local, form) + _, fail = Eval(e, form) if fail != nil { goto TAG } @@ -181,8 +181,8 @@ func Tagbody(local environment.Environment, body ...ilos.Instance) (ilos.Instanc return Nil, nil } -func Go(local environment.Environment, tag ilos.Instance) (ilos.Instance, ilos.Instance) { - if _, ok := local.TagbodyTag.Get(tag); !ok { +func Go(e env.Environment, tag ilos.Instance) (ilos.Instance, ilos.Instance) { + if _, ok := e.TagbodyTag.Get(tag); !ok { return nil, instance.NewSimpleError(instance.NewString("%v is not defined as the tag"), tag) } @@ -190,36 +190,36 @@ func Go(local environment.Environment, tag ilos.Instance) (ilos.Instance, ilos.I } // UnwindProtect first evaluates form. Evaluation of the cleanup-forms always -// occurs, regardless of whether the exit is normal or non-local. +// occurs, regardless of whether the exit is normal or non-e. // // If the form exits normally yielding a value R, then if all of the // cleanup-forms exit normally the value R is returned by the // unwind-protect form. // -// If a non-local exit from form occurs, then the cleanup-forms are executed as +// If a non-e exit from form occurs, then the cleanup-forms are executed as // part of that exit, and then if all of the cleanup-forms exit normally the -// original non-local exit continues. +// original non-e exit continues. // // The cleanup-forms are evaluated from left to right, discarding the resulting // values. If execution of the cleanup-forms finishes normally, exit from the // unwind-protect form proceeds as described above. It is permissible for a -// cleanup-form to contain a non-local exit from the unwind-protect form, +// cleanup-form to contain a non-e exit from the unwind-protect form, // subject to the following constraint: // // An error shall be signaled if during execution of the cleanup-forms of an -// unwind-protect form, a non-local exit is executed to a destination which has -// been marked as invalid due to some other non-local exit that is already in +// unwind-protect form, a non-e exit is executed to a destination which has +// been marked as invalid due to some other non-e exit that is already in // progress (error-id. control-error). // // Note: Because ISLISP does not specify an interactive debugger, it is // unspecified whether or how error recovery can occur interactively if // programmatic handling fails. The intent is that if the ISLISP processor does -// not terminate abnormally, normal mechanisms for non-local exit (return-from, +// not terminate abnormally, normal mechanisms for non-e exit (return-from, // throw, or go) would be used as necessary and would respect these // cleanup-forms. -func UnwindProtect(local environment.Environment, form ilos.Instance, cleanupForms ...ilos.Instance) (ilos.Instance, ilos.Instance) { - ret1, err1 := Eval(local, form) - ret2, err2 := Progn(local, cleanupForms...) +func UnwindProtect(e env.Environment, form ilos.Instance, cleanupForms ...ilos.Instance) (ilos.Instance, ilos.Instance) { + ret1, err1 := Eval(e, form) + ret2, err2 := Progn(e, cleanupForms...) if ilos.InstanceOf(class.Escape, err2) { return nil, instance.NewControlError() } diff --git a/runtime/null_class.go b/runtime/null_class.go index 7f8d6c1..234381d 100644 --- a/runtime/null_class.go +++ b/runtime/null_class.go @@ -5,12 +5,12 @@ package runtime import ( - "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/env" "github.com/ta2gch/iris/runtime/ilos" ) // Null returns t if obj is nil; otherwise, returns nil obj may be any ISLISP object. -func Null(local environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { +func Null(e env.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { if obj == Nil { return T, nil } diff --git a/runtime/number_class.go b/runtime/number_class.go index c7d0cb7..234544f 100644 --- a/runtime/number_class.go +++ b/runtime/number_class.go @@ -8,7 +8,7 @@ import ( "math" "github.com/ta2gch/iris/reader/parser" - "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/env" "github.com/ta2gch/iris/runtime/ilos" "github.com/ta2gch/iris/runtime/ilos/class" "github.com/ta2gch/iris/runtime/ilos/instance" @@ -16,7 +16,7 @@ import ( // Numberp returns t if obj is a number (instance of class number); otherwise, // returns nil. The obj may be any ISLISP object. -func Numberp(local environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { +func Numberp(e env.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { if ilos.InstanceOf(class.Number, obj) { return T, nil } @@ -29,7 +29,7 @@ func Numberp(local environment.Environment, obj ilos.Instance) (ilos.Instance, i // An error shall be signaled if string is not a string (error-id. domain-error). // An error shall be signaled if string is not the textual representation // of a number (error-id. cannot-parse-number). -func ParseNumber(local environment.Environment, str ilos.Instance) (ilos.Instance, ilos.Instance) { +func ParseNumber(e env.Environment, str ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.String, str); err != nil { return nil, err } @@ -46,7 +46,7 @@ func ParseNumber(local environment.Environment, str ilos.Instance) (ilos.Instanc // // Note: = differs from eql because = compares only the mathematical values of its arguments, // whereas eql also compares the representations -func NumberEqual(local environment.Environment, x1, x2 ilos.Instance) (ilos.Instance, ilos.Instance) { +func NumberEqual(e env.Environment, x1, x2 ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Number, x1, x2); err != nil { return nil, err } @@ -70,16 +70,16 @@ func NumberEqual(local environment.Environment, x1, x2 ilos.Instance) (ilos.Inst // NumberNotEqual returns t if x1 and x2 have mathematically distinct values; // otherwise, returns nil. An error shall be signaled if either x1 or x2 is not // a number (error-id. domain-error). -func NumberNotEqual(local environment.Environment, x1, x2 ilos.Instance) (ilos.Instance, ilos.Instance) { - ret, err := NumberEqual(local, x1, x2) +func NumberNotEqual(e env.Environment, x1, x2 ilos.Instance) (ilos.Instance, ilos.Instance) { + ret, err := NumberEqual(e, x1, x2) if err != nil { return ret, err } - return Not(local, ret) + return Not(e, ret) } // NumberGreaterThan returns t if x1 is greater than x2 -func NumberGreaterThan(local environment.Environment, x1, x2 ilos.Instance) (ilos.Instance, ilos.Instance) { +func NumberGreaterThan(e env.Environment, x1, x2 ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Number, x1, x2); err != nil { return nil, err } @@ -101,12 +101,12 @@ func NumberGreaterThan(local environment.Environment, x1, x2 ilos.Instance) (ilo } // NumberGreaterThanOrEqual returns t if x1 is greater than or = x2 -func NumberGreaterThanOrEqual(local environment.Environment, x1, x2 ilos.Instance) (ilos.Instance, ilos.Instance) { - gt, err := NumberGreaterThan(local, x1, x2) +func NumberGreaterThanOrEqual(e env.Environment, x1, x2 ilos.Instance) (ilos.Instance, ilos.Instance) { + gt, err := NumberGreaterThan(e, x1, x2) if err != nil { return nil, err } - eq, err := NumberEqual(local, x1, x2) + eq, err := NumberEqual(e, x1, x2) if err != nil { return nil, err } @@ -117,27 +117,27 @@ func NumberGreaterThanOrEqual(local environment.Environment, x1, x2 ilos.Instanc } // NumberLessThan returns t if x1 is less than x2 -func NumberLessThan(local environment.Environment, x1, x2 ilos.Instance) (ilos.Instance, ilos.Instance) { - ge, err := NumberGreaterThanOrEqual(local, x1, x2) +func NumberLessThan(e env.Environment, x1, x2 ilos.Instance) (ilos.Instance, ilos.Instance) { + ge, err := NumberGreaterThanOrEqual(e, x1, x2) if err != nil { return nil, err } - return Not(local, ge) + return Not(e, ge) } // NumberLessThanOrEqulal returns t if x1 is less than or = x2 -func NumberLessThanOrEqulal(local environment.Environment, x1, x2 ilos.Instance) (ilos.Instance, ilos.Instance) { - gt, err := NumberGreaterThan(local, x1, x2) +func NumberLessThanOrEqulal(e env.Environment, x1, x2 ilos.Instance) (ilos.Instance, ilos.Instance) { + gt, err := NumberGreaterThan(e, x1, x2) if err != nil { return nil, err } - return Not(local, gt) + return Not(e, gt) } // Add returns the sum, respectively, of their arguments. If all arguments are integers, // the result is an integer. If any argument is a float, the result is a float. When given no arguments, // + returns 0. An error shall be signaled if any x is not a number (error-id. domain-error). -func Add(local environment.Environment, x ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Add(e env.Environment, x ...ilos.Instance) (ilos.Instance, ilos.Instance) { flt := false sum := 0.0 for _, a := range x { @@ -157,7 +157,7 @@ func Add(local environment.Environment, x ...ilos.Instance) (ilos.Instance, ilos // Multiply returns the product, respectively, of their arguments. If all arguments are integers, // the result is an integer. If any argument is a float, the result is a float. When given no arguments, // Multiply returns 1. An error shall be signaled if any x is not a number (error-id. domain-error). -func Multiply(local environment.Environment, x ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Multiply(e env.Environment, x ...ilos.Instance) (ilos.Instance, ilos.Instance) { flt := false pdt := 1.0 for _, a := range x { @@ -181,9 +181,9 @@ func Multiply(local environment.Environment, x ...ilos.Instance) (ilos.Instance, // returns -0.0; in implementations where -0.0 and 0.0 are not distinct, (- 0.0) returns 0.0. // Given more than one argument, x1 … xn , - returns their successive differences, // x1 −x2 − … −xn. An error shall be signaled if any x is not a number (error-id. domain-error). -func Substruct(local environment.Environment, x ilos.Instance, xs ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Substruct(e env.Environment, x ilos.Instance, xs ...ilos.Instance) (ilos.Instance, ilos.Instance) { if len(xs) == 0 { - ret, err := Substruct(local, instance.NewInteger(0), x) + ret, err := Substruct(e, instance.NewInteger(0), x) return ret, err } sub, flt, err := convFloat64(x) @@ -208,7 +208,7 @@ func Substruct(local environment.Environment, x ilos.Instance, xs ...ilos.Instan // // Given more than two arguments, quotient operates iteratively on each of the divisor1 … divisorn as in dividend /divisor1 / … /divisorn. The type of the result follows from the two-argument case because the three-or-more-argument quotient can be defined as follows: // An error shall be signaled if dividend is not a number (error-id. domain-error). An error shall be signaled if any divisor is not a number (error-id. domain-error). An error shall be signaled if any divisor is zero (error-id. division-by-zero). -func Quotient(local environment.Environment, dividend, divisor1 ilos.Instance, divisor ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Quotient(e env.Environment, dividend, divisor1 ilos.Instance, divisor ...ilos.Instance) (ilos.Instance, ilos.Instance) { divisor = append([]ilos.Instance{divisor1}, divisor...) quotient, flt, err := convFloat64(dividend) if err != nil { @@ -239,16 +239,16 @@ func Quotient(local environment.Environment, dividend, divisor1 ilos.Instance, d // Reciprocal returns the reciprocal of its argument x ; that is, 1/x . // An error shall be signaled if x is zero (error-id. division-by-zero). -func Reciprocal(local environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { - return Quotient(local, instance.NewInteger(1), x) +func Reciprocal(e env.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { + return Quotient(e, instance.NewInteger(1), x) } // Max returns the greatest (closest to positive infinity) of its arguments. The comparison is done by >. // An error shall be signaled if any x is not a number (error-id. domain-error). -func Max(local environment.Environment, x ilos.Instance, xs ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Max(e env.Environment, x ilos.Instance, xs ...ilos.Instance) (ilos.Instance, ilos.Instance) { max := x for _, y := range xs { - ret, err := NumberGreaterThan(local, y, max) + ret, err := NumberGreaterThan(e, y, max) if err != nil { return nil, err } @@ -261,10 +261,10 @@ func Max(local environment.Environment, x ilos.Instance, xs ...ilos.Instance) (i // Min returns the least (closest to negative infinity) of its arguments. The comparison is done by <. // An error shall be signaled if any x is not a number (error-id. domain-error). -func Min(local environment.Environment, x ilos.Instance, xs ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Min(e env.Environment, x ilos.Instance, xs ...ilos.Instance) (ilos.Instance, ilos.Instance) { min := x for _, y := range xs { - ret, err := NumberLessThan(local, y, min) + ret, err := NumberLessThan(e, y, min) if err != nil { return nil, err } @@ -277,20 +277,20 @@ func Min(local environment.Environment, x ilos.Instance, xs ...ilos.Instance) (i // Abs returns the absolute value of its argument. // An error shall be signaled if x is not a number (error-id. domain-error). -func Abs(local environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { - ret, err := NumberLessThan(local, x, instance.NewInteger(0)) +func Abs(e env.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { + ret, err := NumberLessThan(e, x, instance.NewInteger(0)) if err != nil { return nil, err } if ret == T { - return Substruct(local, x) + return Substruct(e, x) } return x, nil } // Exp returns e raised to the power x , where e is the base of the natural logarithm. // An error shall be signaled if x is not a number (error-id. domain-error). -func Exp(local environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { +func Exp(e env.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { f, _, err := convFloat64(x) if err != nil { return nil, err @@ -300,7 +300,7 @@ func Exp(local environment.Environment, x ilos.Instance) (ilos.Instance, ilos.In // Log returns the natural logarithm of x. // An error shall be signaled if x is not a positive number (error-id. domain-error). -func Log(local environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { +func Log(e env.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { f, _, err := convFloat64(x) if err != nil { return nil, err @@ -316,7 +316,7 @@ func Log(local environment.Environment, x ilos.Instance) (ilos.Instance, ilos.In // An error shall be signaled if x1 is zero and x2 is negative, // or if x1 is zero and x2 is a zero float, or if x1 is negative // and x2 is not an integer. -func Expt(local environment.Environment, x1, x2 ilos.Instance) (ilos.Instance, ilos.Instance) { +func Expt(e env.Environment, x1, x2 ilos.Instance) (ilos.Instance, ilos.Instance) { a, af, err := convFloat64(x1) if err != nil { return nil, err @@ -330,7 +330,7 @@ func Expt(local environment.Environment, x1, x2 ilos.Instance) (ilos.Instance, i } if (a == 0 && b < 0) || (a == 0 && bf && b == 0) || (a < 0 && bf) { operation := instance.NewSymbol("EXPT") - operands, err := List(local, x1, x2) + operands, err := List(e, x1, x2) if err != nil { return nil, err } @@ -341,7 +341,7 @@ func Expt(local environment.Environment, x1, x2 ilos.Instance) (ilos.Instance, i // Sqrt returns the non-negative square root of x. An error shall be signaled // if x is not a non-negative number (error-id. domain-error). -func Sqrt(local environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { +func Sqrt(e env.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { a, _, err := convFloat64(x) if err != nil { return nil, err @@ -360,7 +360,7 @@ var Pi = instance.NewFloat(3.141592653589793) // Sin returns the sine of x . x must be given in radians. // An error shall be signaled if x is not a number (error-id. domain-error). -func Sin(local environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { +func Sin(e env.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { a, _, err := convFloat64(x) if err != nil { return nil, err @@ -370,7 +370,7 @@ func Sin(local environment.Environment, x ilos.Instance) (ilos.Instance, ilos.In // Cos returns the cosine of x . x must be given in radians. // An error shall be signaled if x is not a number (error-id. domain-error). -func Cos(local environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { +func Cos(e env.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { a, _, err := convFloat64(x) if err != nil { return nil, err @@ -380,7 +380,7 @@ func Cos(local environment.Environment, x ilos.Instance) (ilos.Instance, ilos.In // Tan returns the tangent of x . x must be given in radians. // An error shall be signaled if x is not a number (error-id. domain-error). -func Tan(local environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { +func Tan(e env.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { a, _, err := convFloat64(x) if err != nil { return nil, err @@ -391,7 +391,7 @@ func Tan(local environment.Environment, x ilos.Instance) (ilos.Instance, ilos.In // Atan returns the arc tangent of x. // The result is a (real) number that lies between −π/2 and π/2 (both exclusive). // An error shall be signaled if x is not a number (error-id. domain-error). -func Atan(local environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { +func Atan(e env.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { a, _, err := convFloat64(x) if err != nil { return nil, err @@ -408,7 +408,7 @@ func Atan(local environment.Environment, x ilos.Instance) (ilos.Instance, ilos.I // is not supported; when minus zero is supported, the range includes −π. // // The signs of x1 (indicated as y) and x2 (indicated as x) are used to derive quadrant information. -func Atan2(local environment.Environment, x1, x2 ilos.Instance) (ilos.Instance, ilos.Instance) { +func Atan2(e env.Environment, x1, x2 ilos.Instance) (ilos.Instance, ilos.Instance) { a, _, err := convFloat64(x1) if err != nil { return nil, err @@ -419,7 +419,7 @@ func Atan2(local environment.Environment, x1, x2 ilos.Instance) (ilos.Instance, } if a == 0 && b == 0 { operation := instance.NewSymbol("ATAN2") - operands, err := List(local, x1, x2) + operands, err := List(e, x1, x2) if err != nil { return nil, err } @@ -430,7 +430,7 @@ func Atan2(local environment.Environment, x1, x2 ilos.Instance) (ilos.Instance, // Sinh returns the hyperbolic sine of x . x must be given in radians. // An error shall be signaled if x is not a number (error-id. domain-error). -func Sinh(local environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { +func Sinh(e env.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { a, _, err := convFloat64(x) if err != nil { return nil, err @@ -440,7 +440,7 @@ func Sinh(local environment.Environment, x ilos.Instance) (ilos.Instance, ilos.I // Cosh returns the hyperbolic cosine of x . x must be given in radians. // An error shall be signaled if x is not a number (error-id. domain-error). -func Cosh(local environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { +func Cosh(e env.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { a, _, err := convFloat64(x) if err != nil { return nil, err @@ -450,7 +450,7 @@ func Cosh(local environment.Environment, x ilos.Instance) (ilos.Instance, ilos.I // Tanh returns the hyperbolic tangent of x . x must be given in radians. // An error shall be signaled if x is not a number (error-id. domain-error). -func Tanh(local environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { +func Tanh(e env.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { a, _, err := convFloat64(x) if err != nil { return nil, err @@ -460,7 +460,7 @@ func Tanh(local environment.Environment, x ilos.Instance) (ilos.Instance, ilos.I // Atanh returns the hyperbolic arc tangent of x. // An error shall be signaled if x is not a number with absolute value less than 1 (error-id. domain-error). -func Atanh(local environment.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { +func Atanh(e env.Environment, x ilos.Instance) (ilos.Instance, ilos.Instance) { a, _, err := convFloat64(x) if err != nil { return nil, err diff --git a/runtime/sequence_functions.go b/runtime/sequence_functions.go index 8dcbd1e..e5a1fc3 100644 --- a/runtime/sequence_functions.go +++ b/runtime/sequence_functions.go @@ -7,7 +7,7 @@ package runtime import ( "math" - "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/env" "github.com/ta2gch/iris/runtime/ilos" "github.com/ta2gch/iris/runtime/ilos/class" "github.com/ta2gch/iris/runtime/ilos/instance" @@ -24,7 +24,7 @@ import ( // // An error shall be signaled if sequence is not a basic-vector or a list // (error-id. domain-error). -func Length(local environment.Environment, sequence ilos.Instance) (ilos.Instance, ilos.Instance) { +func Length(e env.Environment, sequence ilos.Instance) (ilos.Instance, ilos.Instance) { switch { case ilos.InstanceOf(class.String, sequence): return instance.NewInteger(len(sequence.(instance.String))), nil @@ -44,7 +44,7 @@ func Length(local environment.Environment, sequence ilos.Instance) (ilos.Instanc // // An error shall be signaled if sequence is not a basic-vector or a list or if z is not an // integer (error-id. domain-error). -func Elt(local environment.Environment, sequence, z ilos.Instance) (ilos.Instance, ilos.Instance) { +func Elt(e env.Environment, sequence, z ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Integer, z); err != nil { return nil, err } @@ -80,7 +80,7 @@ func Elt(local environment.Environment, sequence, z ilos.Instance) (ilos.Instanc // An error shall be signaled if z is an integer outside of the valid range of indices // (error-id. index-out-of-range). An error shall be signaled if sequence is not a basic-vector // or a list or if z is not an integer (error-id. domain-error). obj may be any ISLISP object. -func SetElt(local environment.Environment, obj, sequence, z ilos.Instance) (ilos.Instance, ilos.Instance) { +func SetElt(e env.Environment, obj, sequence, z ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Integer, z); err != nil { return nil, err } @@ -130,7 +130,7 @@ func SetElt(local environment.Environment, obj, sequence, z ilos.Instance) (ilos // mentioned (error-id. index-out-of-range). An error shall be signaled if sequence is not a // basic-vector or a list, or if z1 is not an integer, or if z2 is not an integer // (error-id. domain-error). -func Subseq(local environment.Environment, sequence, z1, z2 ilos.Instance) (ilos.Instance, ilos.Instance) { +func Subseq(e env.Environment, sequence, z1, z2 ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Integer, z1, z2); err != nil { return nil, err } @@ -154,7 +154,7 @@ func Subseq(local environment.Environment, sequence, z1, z2 ilos.Instance) (ilos if !(0 < start && start < len(seq) && 0 < end && end < len(seq) && start <= end) { return nil, instance.NewIndexOutOfRange() } - return List(local, seq[start:end]...) + return List(e, seq[start:end]...) } return nil, instance.NewDomainError(sequence, class.Object) } @@ -175,7 +175,7 @@ func Subseq(local environment.Environment, sequence, z1, z2 ilos.Instance) (ilos // // An error shall be signaled if any sequence is not a basic-vector or a list // (error-id. domain-error). -func mapInto(local environment.Environment, destination, function ilos.Instance, sequences ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func mapInto(e env.Environment, destination, function ilos.Instance, sequences ...ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.List, append(sequences, destination)...); err != nil { if err := ensure(class.BasicVector, append(sequences, destination)...); err != nil { return nil, err @@ -199,16 +199,16 @@ func mapInto(local environment.Environment, destination, function ilos.Instance, arguments := make([]ilos.Instance, int(max)) for _, seq := range sequences { var err ilos.Instance - arguments[i], err = Elt(local, seq, instance.NewInteger(i)) + arguments[i], err = Elt(e, seq, instance.NewInteger(i)) if err != nil { return nil, err } } - ret, err := function.(instance.Applicable).Apply(local, arguments...) + ret, err := function.(instance.Applicable).Apply(e, arguments...) if err != nil { return nil, err } - _, err = SetElt(local, ret, destination, instance.NewInteger(i)) + _, err = SetElt(e, ret, destination, instance.NewInteger(i)) if err != nil { return nil, err } diff --git a/runtime/sequencing_forms.go b/runtime/sequencing_forms.go index 3b8ec56..640cd9f 100644 --- a/runtime/sequencing_forms.go +++ b/runtime/sequencing_forms.go @@ -5,7 +5,7 @@ package runtime import ( - "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/env" "github.com/ta2gch/iris/runtime/ilos" ) @@ -14,11 +14,11 @@ import ( // The result of evaluation of the last form of form* is returned. All the forms are // evaluated from left to right. The values of all the forms but the last are discarded, // so they are executed only for their side-effects. progn without forms returns nil. -func Progn(local environment.Environment, form ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Progn(e env.Environment, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { var err ilos.Instance ret := Nil - for _, e := range form { - ret, err = Eval(local, e) + for _, form := range forms { + ret, err = Eval(e, form) if err != nil { return nil, err } diff --git a/runtime/stream.go b/runtime/stream.go index ae24430..4b633c7 100644 --- a/runtime/stream.go +++ b/runtime/stream.go @@ -14,86 +14,86 @@ import ( "github.com/ta2gch/iris/reader/parser" "github.com/ta2gch/iris/reader/tokenizer" - "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/env" "github.com/ta2gch/iris/runtime/ilos" "github.com/ta2gch/iris/runtime/ilos/class" "github.com/ta2gch/iris/runtime/ilos/instance" ) -func Streamp(local environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { +func Streamp(e env.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { if ilos.InstanceOf(class.Stream, obj) { return T, nil } return Nil, nil } -func OpenStreamP(local environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { +func OpenStreamP(e env.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { return T, nil } -func InputStreamp(local environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { +func InputStreamp(e env.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { if s, ok := obj.(instance.Stream); ok && s.Reader != nil { return T, nil } return Nil, nil } -func OutputStreamp(local environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { +func OutputStreamp(e env.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { if s, ok := obj.(instance.Stream); ok && s.Writer != nil { return T, nil } return Nil, nil } -func StandardInput(local environment.Environment) (ilos.Instance, ilos.Instance) { - return local.StandardInput, nil +func StandardInput(e env.Environment) (ilos.Instance, ilos.Instance) { + return e.StandardInput, nil } -func StandardOutput(local environment.Environment) (ilos.Instance, ilos.Instance) { - return local.StandardOutput, nil +func StandardOutput(e env.Environment) (ilos.Instance, ilos.Instance) { + return e.StandardOutput, nil } -func ErrorOutput(local environment.Environment) (ilos.Instance, ilos.Instance) { - return local.ErrorOutput, nil +func ErrorOutput(e env.Environment) (ilos.Instance, ilos.Instance) { + return e.ErrorOutput, nil } -func WithStandardInput(local environment.Environment, streamForm ilos.Instance, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func WithStandardInput(e env.Environment, streamForm ilos.Instance, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { var err ilos.Instance - local.StandardInput, err = Eval(local, streamForm) + e.StandardInput, err = Eval(e, streamForm) if err != nil { return nil, err } - if err := ensure(class.Stream, local.ErrorOutput); err != nil { + if err := ensure(class.Stream, e.ErrorOutput); err != nil { return nil, err } - return Progn(local, forms...) + return Progn(e, forms...) } -func WithStandardOutput(local environment.Environment, streamForm ilos.Instance, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func WithStandardOutput(e env.Environment, streamForm ilos.Instance, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { var err ilos.Instance - local.StandardOutput, err = Eval(local, streamForm) + e.StandardOutput, err = Eval(e, streamForm) if err != nil { return nil, err } - if err := ensure(class.Stream, local.ErrorOutput); err != nil { + if err := ensure(class.Stream, e.ErrorOutput); err != nil { return nil, err } - return Progn(local, forms...) + return Progn(e, forms...) } -func WithErrorOutput(local environment.Environment, streamForm ilos.Instance, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func WithErrorOutput(e env.Environment, streamForm ilos.Instance, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { var err ilos.Instance - local.ErrorOutput, err = Eval(local, streamForm) + e.ErrorOutput, err = Eval(e, streamForm) if err != nil { return nil, err } - if err := ensure(class.Stream, local.ErrorOutput); err != nil { + if err := ensure(class.Stream, e.ErrorOutput); err != nil { return nil, err } - return Progn(local, forms...) + return Progn(e, forms...) } -func OpenInputFile(local environment.Environment, filename ilos.Instance, elementClass ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func OpenInputFile(e env.Environment, filename ilos.Instance, elementClass ...ilos.Instance) (ilos.Instance, ilos.Instance) { // TODO: elementClass if err := ensure(class.String, filename); err != nil { return nil, err @@ -105,7 +105,7 @@ func OpenInputFile(local environment.Environment, filename ilos.Instance, elemen return instance.NewStream(file, nil), nil } -func OpenOutputFile(local environment.Environment, filename ilos.Instance, elementClass ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func OpenOutputFile(e env.Environment, filename ilos.Instance, elementClass ...ilos.Instance) (ilos.Instance, ilos.Instance) { // TODO: elementClass if err := ensure(class.String, filename); err != nil { return nil, err @@ -117,7 +117,7 @@ func OpenOutputFile(local environment.Environment, filename ilos.Instance, eleme return instance.NewStream(nil, file), nil } -func OpenIoFile(local environment.Environment, filename ilos.Instance, elementClass ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func OpenIoFile(e env.Environment, filename ilos.Instance, elementClass ...ilos.Instance) (ilos.Instance, ilos.Instance) { // TODO: elementClass if err := ensure(class.String, filename); err != nil { return nil, err @@ -129,46 +129,46 @@ func OpenIoFile(local environment.Environment, filename ilos.Instance, elementCl return instance.NewStream(file, file), nil } -func WithOpenInputFile(local environment.Environment, fileSpec ilos.Instance, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func WithOpenInputFile(e env.Environment, fileSpec ilos.Instance, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Cons, fileSpec); err != nil { return nil, err } n := fileSpec.(*instance.Cons).Car - s, err := Eval(local, instance.NewCons(instance.NewSymbol("OPEN-INPUT-FILE"), fileSpec.(*instance.Cons).Cdr)) + s, err := Eval(e, instance.NewCons(instance.NewSymbol("OPEN-INPUT-FILE"), fileSpec.(*instance.Cons).Cdr)) if err != nil { return nil, err } - local.Variable.Define(n, s) - return Progn(local, forms...) + e.Variable.Define(n, s) + return Progn(e, forms...) } -func WithOpenOutputFile(local environment.Environment, fileSpec ilos.Instance, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func WithOpenOutputFile(e env.Environment, fileSpec ilos.Instance, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Cons, fileSpec); err != nil { return nil, err } n := fileSpec.(*instance.Cons).Car - s, err := Eval(local, instance.NewCons(instance.NewSymbol("OPEN-OUTPUT-FILE"), fileSpec.(*instance.Cons).Cdr)) + s, err := Eval(e, instance.NewCons(instance.NewSymbol("OPEN-OUTPUT-FILE"), fileSpec.(*instance.Cons).Cdr)) if err != nil { return nil, err } - local.Variable.Define(n, s) - return Progn(local, forms...) + e.Variable.Define(n, s) + return Progn(e, forms...) } -func WithOpenIoFile(local environment.Environment, fileSpec ilos.Instance, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func WithOpenIoFile(e env.Environment, fileSpec ilos.Instance, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Cons, fileSpec); err != nil { return nil, err } n := fileSpec.(*instance.Cons).Car - s, err := Eval(local, instance.NewCons(instance.NewSymbol("OPEN-IO-FILE"), fileSpec.(*instance.Cons).Cdr)) + s, err := Eval(e, instance.NewCons(instance.NewSymbol("OPEN-IO-FILE"), fileSpec.(*instance.Cons).Cdr)) if err != nil { return nil, err } - local.Variable.Define(n, s) - return Progn(local, forms...) + e.Variable.Define(n, s) + return Progn(e, forms...) } -func Close(local environment.Environment, stream ilos.Instance) (ilos.Instance, ilos.Instance) { +func Close(e env.Environment, stream ilos.Instance) (ilos.Instance, ilos.Instance) { // It works on file or std stream. if err := ensure(class.Stream, stream); err != nil { return nil, err @@ -182,7 +182,7 @@ func Close(local environment.Environment, stream ilos.Instance) (ilos.Instance, return Nil, nil } -func FlushOutput(local environment.Environment, stream ilos.Instance) (ilos.Instance, ilos.Instance) { +func FlushOutput(e env.Environment, stream ilos.Instance) (ilos.Instance, ilos.Instance) { // It works on file or std stream. if err := ensure(class.Stream, stream); err != nil { return nil, err @@ -193,27 +193,27 @@ func FlushOutput(local environment.Environment, stream ilos.Instance) (ilos.Inst return Nil, nil } -func CreateStringInputStream(local environment.Environment, str ilos.Instance) (ilos.Instance, ilos.Instance) { +func CreateStringInputStream(e env.Environment, str ilos.Instance) (ilos.Instance, ilos.Instance) { return instance.NewStream(strings.NewReader(string(str.(instance.String))), nil), nil } -func CreateStringOutputStream(local environment.Environment) (ilos.Instance, ilos.Instance) { +func CreateStringOutputStream(e env.Environment) (ilos.Instance, ilos.Instance) { return instance.NewStream(nil, new(bytes.Buffer)), nil } -func GetOutputStreamString(local environment.Environment, stream ilos.Instance) (ilos.Instance, ilos.Instance) { +func GetOutputStreamString(e env.Environment, stream ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Stream, stream); err != nil { return nil, err } return instance.NewString(stream.(instance.Stream).Writer.(*bytes.Buffer).String()), nil } -func Read(local environment.Environment, options ...ilos.Instance) (ilos.Instance, ilos.Instance) { - s := local.StandardInput +func Read(e env.Environment, options ...ilos.Instance) (ilos.Instance, ilos.Instance) { + s := e.StandardInput if len(options) > 0 { s = options[0] } - if b, _ := InputStreamp(local, s); b == Nil { + if b, _ := InputStreamp(e, s); b == Nil { return nil, nil // throw Error } eosErrorP := true @@ -238,12 +238,12 @@ func Read(local environment.Environment, options ...ilos.Instance) (ilos.Instanc return v, nil } -func ReadChar(local environment.Environment, options ...ilos.Instance) (ilos.Instance, ilos.Instance) { - s := local.StandardInput +func ReadChar(e env.Environment, options ...ilos.Instance) (ilos.Instance, ilos.Instance) { + s := e.StandardInput if len(options) > 0 { s = options[0] } - if b, _ := InputStreamp(local, s); b == Nil { + if b, _ := InputStreamp(e, s); b == Nil { return nil, nil // throw Error } eosErrorP := true @@ -261,19 +261,19 @@ func ReadChar(local environment.Environment, options ...ilos.Instance) (ilos.Ins v, _, err := bufio.NewReader(s.(instance.Stream).Reader).ReadRune() if err != nil { if eosErrorP { - return nil, instance.Create(local, class.EndOfStream) + return nil, instance.Create(e, class.EndOfStream) } return eosValue, nil } return instance.NewCharacter(v), nil } -func ReadLine(local environment.Environment, options ...ilos.Instance) (ilos.Instance, ilos.Instance) { - s := local.StandardInput +func ReadLine(e env.Environment, options ...ilos.Instance) (ilos.Instance, ilos.Instance) { + s := e.StandardInput if len(options) > 0 { s = options[0] } - if b, _ := InputStreamp(local, s); b == Nil { + if b, _ := InputStreamp(e, s); b == Nil { return nil, nil // throw Error } eosErrorP := true @@ -291,7 +291,7 @@ func ReadLine(local environment.Environment, options ...ilos.Instance) (ilos.Ins v, _, err := bufio.NewReader(s.(instance.Stream).Reader).ReadLine() if err != nil { if eosErrorP { - return nil, instance.Create(local, class.EndOfStream) + return nil, instance.Create(e, class.EndOfStream) } return eosValue, nil } @@ -300,16 +300,16 @@ func ReadLine(local environment.Environment, options ...ilos.Instance) (ilos.Ins // TODO: preview-char (Hint: Bufio.Rreader) -func StreamReadyP(local environment.Environment, inputStream ilos.Instance) (ilos.Instance, ilos.Instance) { +func StreamReadyP(e env.Environment, inputStream ilos.Instance) (ilos.Instance, ilos.Instance) { // TODO: stream-ready-p return T, nil } -func Format(local environment.Environment, stream, formatString ilos.Instance, objs ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Format(e env.Environment, stream, formatString ilos.Instance, objs ...ilos.Instance) (ilos.Instance, ilos.Instance) { f := regexp.MustCompile("([^~])~A").ReplaceAllString(string(formatString.(instance.String)), "%1%v") f = regexp.MustCompile(`\`).ReplaceAllString(string(formatString.(instance.String)), `\\`) f = regexp.MustCompile("([^~])~%").ReplaceAllString(string(formatString.(instance.String)), "%1\n") - if b, _ := OutputStreamp(local, stream); b == Nil { + if b, _ := OutputStreamp(e, stream); b == Nil { return nil, nil // throw Error } args := []interface{}{} diff --git a/runtime/string_class.go b/runtime/string_class.go index c75b54b..39de2ef 100644 --- a/runtime/string_class.go +++ b/runtime/string_class.go @@ -7,7 +7,7 @@ package runtime import ( "strings" - "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/env" "github.com/ta2gch/iris/runtime/ilos" "github.com/ta2gch/iris/runtime/ilos/class" "github.com/ta2gch/iris/runtime/ilos/instance" @@ -15,7 +15,7 @@ import ( // Stringp returns t if obj is a string (instance of class string); // otherwise, returns nil. obj may be any ISLISP object. -func Stringp(local environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { +func Stringp(e env.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { if ilos.InstanceOf(class.String, obj) { return T, nil } @@ -26,7 +26,7 @@ func Stringp(local environment.Environment, obj ilos.Instance) (ilos.Instance, i // the new string are initialized with this character, otherwise the initialization is implementation defined. // An error shall be signaled if the requested string cannot be allocated (error-id. cannot-create-string). // An error shall be signaled if i is not a non-negative integer or if initial-character is not a character (error-id. domain-error). -func CreateString(local environment.Environment, i ilos.Instance, initialElement ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func CreateString(e env.Environment, i ilos.Instance, initialElement ...ilos.Instance) (ilos.Instance, ilos.Instance) { if !ilos.InstanceOf(class.Integer, i) || int(i.(instance.Integer)) < 0 { return nil, instance.NewDomainError(i, class.Integer) } @@ -49,7 +49,7 @@ func CreateString(local environment.Environment, i ilos.Instance, initialElement } // StringEqual tests whether string1 is the same string as string2. -func StringEqual(local environment.Environment, string1, string2 ilos.Instance) (ilos.Instance, ilos.Instance) { +func StringEqual(e env.Environment, string1, string2 ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.String, string1, string2); err != nil { return nil, err } @@ -60,16 +60,16 @@ func StringEqual(local environment.Environment, string1, string2 ilos.Instance) } // StringNotEqual tests whether string1 not is the same string as string2. -func StringNotEqual(local environment.Environment, string1, string2 ilos.Instance) (ilos.Instance, ilos.Instance) { - ret, err := StringEqual(local, string1, string2) +func StringNotEqual(e env.Environment, string1, string2 ilos.Instance) (ilos.Instance, ilos.Instance) { + ret, err := StringEqual(e, string1, string2) if err != nil { return nil, err } - return Not(local, ret) + return Not(e, ret) } // StringGreaterThan tests whether string1 is greater than string2. -func StringGreaterThan(local environment.Environment, string1, string2 ilos.Instance) (ilos.Instance, ilos.Instance) { +func StringGreaterThan(e env.Environment, string1, string2 ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.String, string1, string2); err != nil { return nil, err } @@ -80,12 +80,12 @@ func StringGreaterThan(local environment.Environment, string1, string2 ilos.Inst } // StringGreaterThanOrEqual tests whether string1 is greater than or equal to string2. -func StringGreaterThanOrEqual(local environment.Environment, string1, string2 ilos.Instance) (ilos.Instance, ilos.Instance) { - gt, err := StringGreaterThan(local, string1, string2) +func StringGreaterThanOrEqual(e env.Environment, string1, string2 ilos.Instance) (ilos.Instance, ilos.Instance) { + gt, err := StringGreaterThan(e, string1, string2) if err != nil { return nil, err } - eq, err := StringEqual(local, string1, string2) + eq, err := StringEqual(e, string1, string2) if err != nil { return nil, err } @@ -96,21 +96,21 @@ func StringGreaterThanOrEqual(local environment.Environment, string1, string2 il } // StringLessThan tests whether string1 is less than string2. -func StringLessThan(local environment.Environment, string1, string2 ilos.Instance) (ilos.Instance, ilos.Instance) { - gt, err := StringGreaterThanOrEqual(local, string1, string2) +func StringLessThan(e env.Environment, string1, string2 ilos.Instance) (ilos.Instance, ilos.Instance) { + gt, err := StringGreaterThanOrEqual(e, string1, string2) if err != nil { return nil, err } - return Not(local, gt) + return Not(e, gt) } // StringLessThanOrEqual tests whether string1 is less than or equal to string2. -func StringLessThanOrEqual(local environment.Environment, string1, string2 ilos.Instance) (ilos.Instance, ilos.Instance) { - gt, err := StringGreaterThan(local, string1, string2) +func StringLessThanOrEqual(e env.Environment, string1, string2 ilos.Instance) (ilos.Instance, ilos.Instance) { + gt, err := StringGreaterThan(e, string1, string2) if err != nil { return nil, err } - return Not(local, gt) + return Not(e, gt) } // CharIndex returns the position of char in string, The search starts from the position indicated @@ -119,7 +119,7 @@ func StringLessThanOrEqual(local environment.Environment, string1, string2 ilos. // If the char does not occur in the string, nil is returned. The function char= is used for the comparisons. // // An error shall be signaled if char is not a character or if string is not a string (error-id. domain-error). -func CharIndex(local environment.Environment, char, str ilos.Instance, startPosition ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func CharIndex(e env.Environment, char, str ilos.Instance, startPosition ...ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Character, char); err != nil { return nil, err } @@ -152,7 +152,7 @@ func CharIndex(local environment.Environment, char, str ilos.Instance, startPosi // Presence of the substring is done by sequential use of char= on corresponding elements of the two strings. // // An error shall be signaled if either substring or string is not a string (error-id. domain-error). -func StringIndex(local environment.Environment, sub, str ilos.Instance, startPosition ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func StringIndex(e env.Environment, sub, str ilos.Instance, startPosition ...ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.String, sub); err != nil { return nil, err } @@ -186,7 +186,7 @@ func StringIndex(local environment.Environment, sub, str ilos.Instance, startPos // when the result shares structure with its string arguments. // // An error shall be signaled if the string cannot be allocated (error-id. cannot-create-string). -func StringAppend(local environment.Environment, str ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func StringAppend(e env.Environment, str ...ilos.Instance) (ilos.Instance, ilos.Instance) { ret := "" for _, s := range str { if err := ensure(class.String, s); err != nil { diff --git a/runtime/symbol_class.go b/runtime/symbol_class.go index 2029cb5..b75a4ec 100644 --- a/runtime/symbol_class.go +++ b/runtime/symbol_class.go @@ -7,7 +7,7 @@ package runtime import ( "fmt" - "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/env" "github.com/ta2gch/iris/runtime/ilos" "github.com/ta2gch/iris/runtime/ilos/class" "github.com/ta2gch/iris/runtime/ilos/instance" @@ -15,7 +15,7 @@ import ( // Symbolp returns t if obj is a symbol (instance of class symbol); // otherwise, returns nil. The obj may be any ISLISP object. -func Symbolp(local environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { +func Symbolp(e env.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { if ilos.InstanceOf(class.Symbol, obj) { return T, nil } @@ -28,14 +28,14 @@ func Symbolp(local environment.Environment, obj ilos.Instance) (ilos.Instance, i // // An error shall be signaled if either symbol or property-name is not a // symbol (error-id. domain-error). obj may be any ISLISP object -func Property(local environment.Environment, symbol, propertyName ilos.Instance, obj ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Property(e env.Environment, symbol, propertyName ilos.Instance, obj ...ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Symbol, symbol); err != nil { return nil, err } if len(obj) > 1 { return nil, instance.NewArityError() } - ret, ok := local.Property.Get(symbol, propertyName) + ret, ok := e.Property.Get(symbol, propertyName) if ok { return ret, nil } @@ -49,11 +49,11 @@ func Property(local environment.Environment, symbol, propertyName ilos.Instance, // // An error shall be signaled if either symbol or property-name is not a // symbol (error-id. domain-error). obj may be any ISLISP object -func SetProperty(local environment.Environment, obj, symbol, propertyName ilos.Instance) (ilos.Instance, ilos.Instance) { +func SetProperty(e env.Environment, obj, symbol, propertyName ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Symbol, symbol); err != nil { return nil, err } - local.Property.Set(symbol, propertyName, obj) + e.Property.Set(symbol, propertyName, obj) return obj, nil } @@ -63,11 +63,11 @@ func SetProperty(local environment.Environment, obj, symbol, propertyName ilos.I // // An error shall be signaled if either symbol or property-name is not a // symbol (error-id. domain-error). -func RemoveProperty(local environment.Environment, symbol, propertyName ilos.Instance) (ilos.Instance, ilos.Instance) { +func RemoveProperty(e env.Environment, symbol, propertyName ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Symbol, symbol); err != nil { return nil, err } - if v, ok := local.Property.Delete(symbol, propertyName); ok { + if v, ok := e.Property.Delete(symbol, propertyName); ok { return v, nil } return Nil, nil @@ -75,7 +75,7 @@ func RemoveProperty(local environment.Environment, symbol, propertyName ilos.Ins // Gensym returns an unnamed symbol. gensym is useful for writing macros. // It is impossible for an identifier to name an unnamed symbol. -func Gensym(local environment.Environment) (ilos.Instance, ilos.Instance) { - local.GensymID++ - return instance.NewSymbol(fmt.Sprintf("IRIS/G#%v", local.GensymID)), nil +func Gensym(e env.Environment) (ilos.Instance, ilos.Instance) { + e.GensymID++ + return instance.NewSymbol(fmt.Sprintf("IRIS/G#%v", e.GensymID)), nil } diff --git a/runtime/util.go b/runtime/util.go index 1ef6093..e0eb23f 100644 --- a/runtime/util.go +++ b/runtime/util.go @@ -11,7 +11,7 @@ import ( "runtime" "strings" - "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/env" "github.com/ta2gch/iris/reader/parser" "github.com/ta2gch/iris/reader/tokenizer" @@ -42,12 +42,12 @@ func convFloat64(x ilos.Instance) (float64, bool, ilos.Instance) { } func readFromString(s string) ilos.Instance { - e, _ := parser.Parse(tokenizer.New(strings.NewReader(s))) - return e + ret, _ := parser.Parse(tokenizer.New(strings.NewReader(s))) + return ret } -func evalString(local environment.Environment, s string) ilos.Instance { - e, _ := Eval(local, readFromString(s)) - return e +func evalString(e env.Environment, s string) ilos.Instance { + ret, _ := Eval(e, readFromString(s)) + return ret } func func2symbol(function interface{}) ilos.Instance { @@ -87,4 +87,4 @@ func ensure(c ilos.Class, i ...ilos.Instance) ilos.Instance { return nil } -var TopLevel = environment.NewEnvironment(instance.NewStream(os.Stdin, nil), instance.NewStream(nil, os.Stdout), instance.NewStream(nil, os.Stderr)) +var TopLevel = env.NewEnvironment(instance.NewStream(os.Stdin, nil), instance.NewStream(nil, os.Stdout), instance.NewStream(nil, os.Stderr)) diff --git a/runtime/variables.go b/runtime/variables.go index 536f17f..5aef4f9 100644 --- a/runtime/variables.go +++ b/runtime/variables.go @@ -7,7 +7,7 @@ package runtime import ( "fmt" - "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/env" "github.com/ta2gch/iris/runtime/ilos" "github.com/ta2gch/iris/runtime/ilos/class" "github.com/ta2gch/iris/runtime/ilos/instance" @@ -21,38 +21,38 @@ import ( // setq can be used only for modifying bindings, and not for establishing a variable. // The setq special form must be contained in the scope of var , established by defglobal, // let, let*, for, or a lambda expression. -func Setq(local environment.Environment, var1, form ilos.Instance) (ilos.Instance, ilos.Instance) { - ret, err := Eval(local, form) +func Setq(e env.Environment, var1, form ilos.Instance) (ilos.Instance, ilos.Instance) { + ret, err := Eval(e, form) if err != nil { return nil, err } - if local.Variable.Set(var1, ret) { + if e.Variable.Set(var1, ret) { return ret, nil } - if local.Variable.Set(var1, ret) { + if e.Variable.Set(var1, ret) { return ret, nil } return nil, instance.NewUndefinedVariable(var1) } -func Setf(local environment.Environment, var1, form ilos.Instance) (ilos.Instance, ilos.Instance) { +func Setf(e env.Environment, var1, form ilos.Instance) (ilos.Instance, ilos.Instance) { if ilos.InstanceOf(class.Symbol, var1) { - val, err := Eval(local, form) + val, err := Eval(e, form) if err != nil { return nil, err } - return Setq(local, var1, val) + return Setq(e, var1, val) } funcSpec := instance.NewSymbol(fmt.Sprintf("(SETF %v)", var1.(instance.List).Nth(0))) - fun, ok := local.Function.Get(funcSpec) + fun, ok := e.Function.Get(funcSpec) if !ok { return nil, instance.NewUndefinedFunction(funcSpec) } - arguments, err := evalArguments(local, instance.NewCons(form, var1.(*instance.Cons).Cdr)) + arguments, err := evalArguments(e, instance.NewCons(form, var1.(*instance.Cons).Cdr)) if err != nil { return nil, err } - return fun.(instance.Applicable).Apply(local, arguments.(instance.List).Slice()...) + return fun.(instance.Applicable).Apply(e, arguments.(instance.List).Slice()...) } // Let is used to define a scope for a group of identifiers @@ -67,7 +67,7 @@ func Setf(local environment.Environment, var1, form ilos.Instance) (ilos.Instanc // of the evaluation of the last body-form of its body (or nil if there is none). // // No var may appear more than once in let variable list. -func Let(local environment.Environment, varForm ilos.Instance, bodyForm ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Let(e env.Environment, varForm ilos.Instance, bodyForm ...ilos.Instance) (ilos.Instance, ilos.Instance) { vfs := map[ilos.Instance]ilos.Instance{} if err := ensure(class.List, varForm); err != nil { return nil, err @@ -79,18 +79,18 @@ func Let(local environment.Environment, varForm ilos.Instance, bodyForm ...ilos. if cadr.(instance.List).Length() != 2 { return nil, instance.NewArityError() } - f, err := Eval(local, cadr.(instance.List).Nth(1)) + f, err := Eval(e, cadr.(instance.List).Nth(1)) if err != nil { return nil, err } vfs[cadr.(instance.List).Nth(0)] = f } for v, f := range vfs { - if !local.Variable.Define(v, f) { + if !e.Variable.Define(v, f) { return nil, instance.NewImmutableBinding() } } - return Progn(local, bodyForm...) + return Progn(e, bodyForm...) } // LetStar form is used to define a scope for a group of identifiers for a sequence @@ -104,10 +104,10 @@ func Let(local environment.Environment, varForm ilos.Instance, bodyForm ...ilos. // the evaluation is bound to its associated variable named by the identifier var . // These variable bindings enlarge the set of current valid identifiers perhaps // shadowing previous variable bindings (in case some var was defined outside), -// and in this enlarged or modified environment the body-forms are executed. +// and in this enlarged or modified eironment the body-forms are executed. // The returned value of let* is the result of the evaluation of the last form // of its body (or nil if there is none). -func LetStar(local environment.Environment, varForm ilos.Instance, bodyForm ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func LetStar(e env.Environment, varForm ilos.Instance, bodyForm ...ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.List, varForm); err != nil { return nil, err } @@ -118,13 +118,13 @@ func LetStar(local environment.Environment, varForm ilos.Instance, bodyForm ...i if cadr.(instance.List).Length() != 2 { return nil, instance.NewArityError() } - f, err := Eval(local, cadr.(instance.List).Nth(1)) + f, err := Eval(e, cadr.(instance.List).Nth(1)) if err != nil { return nil, err } - if !local.Variable.Define(cadr.(instance.List).Nth(0), f) { + if !e.Variable.Define(cadr.(instance.List).Nth(0), f) { return nil, instance.NewImmutableBinding() } } - return Progn(local, bodyForm...) + return Progn(e, bodyForm...) } diff --git a/runtime/vectors.go b/runtime/vectors.go index 3a7f82b..165a8d6 100644 --- a/runtime/vectors.go +++ b/runtime/vectors.go @@ -5,7 +5,7 @@ package runtime import ( - "github.com/ta2gch/iris/runtime/environment" + "github.com/ta2gch/iris/runtime/env" "github.com/ta2gch/iris/runtime/ilos" "github.com/ta2gch/iris/runtime/ilos/class" "github.com/ta2gch/iris/runtime/ilos/instance" @@ -13,7 +13,7 @@ import ( // BasicVectorP returns t if obj is a basic-vector (instance of class basic-vector); // otherwise, returns nil. obj may be any ISLISP object. -func BasicVectorP(local environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { +func BasicVectorP(e env.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { if ilos.InstanceOf(class.BasicVector, obj) { return T, nil } @@ -22,7 +22,7 @@ func BasicVectorP(local environment.Environment, obj ilos.Instance) (ilos.Instan // GeneralVectorP returns t if obj is a general-vector (instance of class general-vector); // otherwise, returns nil. obj may be any ISLISP object. -func GeneralVectorP(local environment.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { +func GeneralVectorP(e env.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { if ilos.InstanceOf(class.GeneralVector, obj) { return T, nil } @@ -35,7 +35,7 @@ func GeneralVectorP(local environment.Environment, obj ilos.Instance) (ilos.Inst // if the requested vector cannot be allocated (error-id. cannot-create-vector). // An error shall be signaled if i is not a non-negative integer (error-id. domain-error). // initial-element may be any ISLISP object. -func CreateVector(local environment.Environment, i ilos.Instance, initialElement ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func CreateVector(e env.Environment, i ilos.Instance, initialElement ...ilos.Instance) (ilos.Instance, ilos.Instance) { if !ilos.InstanceOf(class.Integer, i) || int(i.(instance.Integer)) < 0 { return nil, instance.NewDomainError(i, class.Integer) } @@ -59,6 +59,6 @@ func CreateVector(local environment.Environment, i ilos.Instance, initialElement // The vector is indexed by integers ranging from 0 to dimension−1. An error shall be signaled // if the requested vector cannot be allocated (error-id. cannot-create-vector). // Each obj may be any ISLISP object. -func Vector(local environment.Environment, obj ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func Vector(e env.Environment, obj ...ilos.Instance) (ilos.Instance, ilos.Instance) { return instance.GeneralVector(obj), nil } From 0d0c9a7e1251aa3e801c88bc46d57a73031ff9b4 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Wed, 23 Aug 2017 18:15:03 +0900 Subject: [PATCH 209/228] Added condition system --- runtime/condition_system.go | 31 +++++++++++------- runtime/condition_system_test.go | 43 +++++++++++++++++++++++++ runtime/env/environment.go | 18 +++++------ runtime/ilos/class/class.go | 1 + runtime/ilos/instance/class.go | 9 +++--- runtime/ilos/instance/error.go | 26 +++++++-------- runtime/ilos/instance/tag.go | 25 +++++++++------ runtime/non-local_exits.go | 54 ++++++++++++++++++-------------- runtime/stream.go | 2 +- runtime/util.go | 8 ++++- 10 files changed, 144 insertions(+), 73 deletions(-) create mode 100644 runtime/condition_system_test.go diff --git a/runtime/condition_system.go b/runtime/condition_system.go index ce6c4ca..bfdd9d4 100644 --- a/runtime/condition_system.go +++ b/runtime/condition_system.go @@ -15,13 +15,13 @@ func SignalCondition(e env.Environment, condition, continuable ilos.Instance) (i if err := ensure(class.SeriousCondition, condition); err != nil { return nil, err } - if handler, ok := e.Handler.Get(instance.NewSymbol("HANDLER")); ok { - if continuable != Nil { - handler.(instance.Applicable).Apply(e, condition) - } - } condition.(instance.Instance).SetSlotValue(instance.NewSymbol("IRIS.CONTINUABLE"), continuable, class.SeriousCondition) - return nil, condition + _, c := e.Handler.(instance.Applicable).Apply(e, condition) + if ilos.InstanceOf(class.Continue, c) { + o, _ := c.(instance.Instance).GetSlotValue(instance.NewSymbol("IRIS.OBJECT"), class.Continue) + return o, nil + } + return nil, c } func Cerror(e env.Environment, continueString, errorString ilos.Instance, objs ...ilos.Instance) (ilos.Instance, ilos.Instance) { @@ -62,7 +62,7 @@ func IgnoreError(e env.Environment, forms ...ilos.Instance) (ilos.Instance, ilos } func ReportCondition(e env.Environment, condition, stream ilos.Instance) (ilos.Instance, ilos.Instance) { - return nil, nil + return Format(e, e.StandardOutput, instance.NewString("~A"), condition) } func ConditionContinuable(e env.Environment, condition ilos.Instance) (ilos.Instance, ilos.Instance) { @@ -72,9 +72,17 @@ func ConditionContinuable(e env.Environment, condition ilos.Instance) (ilos.Inst return Nil, nil } -func ContinueCondition(e env.Environment, condition, value ilos.Instance) (ilos.Instance, ilos.Instance) { - // TODO: - return nil, nil +func ContinueCondition(e env.Environment, condition ilos.Instance, value ...ilos.Instance) (ilos.Instance, ilos.Instance) { + if b, ok := condition.(instance.Instance).GetSlotValue(instance.NewSymbol("IRIS.CONTINUABLE"), class.SeriousCondition); !ok || b == Nil { + return nil, instance.Create(e, class.ProgramError) + } + if len(value) == 1 { + return nil, instance.Create(e, class.Continue, instance.NewSymbol("IRIS.OBJECT"), value[0]) + } + if len(value) == 0 { + return nil, instance.Create(e, class.Continue, instance.NewSymbol("IRIS.OBJECT"), Nil) + } + return nil, instance.Create(e, class.ProgramError) } func WithHandler(e env.Environment, handler ilos.Instance, forms ...ilos.Instance) (ilos.Instance, ilos.Instance) { @@ -82,9 +90,10 @@ func WithHandler(e env.Environment, handler ilos.Instance, forms ...ilos.Instanc if err != nil { return nil, err } + e.Handler = fun ret, err := Progn(e, forms...) if err != nil { - return fun.(instance.Applicable).Apply(e, err) + return nil, err } return ret, err } diff --git a/runtime/condition_system_test.go b/runtime/condition_system_test.go new file mode 100644 index 0000000..edb67c8 --- /dev/null +++ b/runtime/condition_system_test.go @@ -0,0 +1,43 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package runtime + +import "testing" + +func TestSignalCondition(t *testing.T) { + defspecial(Defun) + defun(Cerror) + defun(ContinueCondition) + defspecial(WithHandler) + defspecial(Function) + defspecial(Quote) + tests := []test{ + { + exp: ` + (defun continue-condition-handler (condition) + (continue-condition condition 999)) + `, + want: `'continue-condition-handler`, + wantErr: false, + }, + { + exp: ` + (with-handler #'continue-condition-handler + (cerror "cont" "err")) + `, + want: `999`, + wantErr: false, + }, + { + exp: ` + (with-handler #'continue-condition-handler + (error "not cont")) + `, + want: ``, + wantErr: true, + }, + } + execTests(t, SignalCondition, tests) +} diff --git a/runtime/env/environment.go b/runtime/env/environment.go index dddd550..c998ab0 100644 --- a/runtime/env/environment.go +++ b/runtime/env/environment.go @@ -30,11 +30,11 @@ type Environment struct { StandardInput ilos.Instance StandardOutput ilos.Instance ErrorOutput ilos.Instance - Handler stack + Handler ilos.Instance } // New creates new eironment -func NewEnvironment(stdin, stdout, stderr ilos.Instance) Environment { +func NewEnvironment(stdin, stdout, stderr, handler ilos.Instance) Environment { e := new(Environment) // Lexical @@ -57,7 +57,7 @@ func NewEnvironment(stdin, stdout, stderr ilos.Instance) Environment { e.StandardInput = stdin e.StandardOutput = stdout e.ErrorOutput = stderr - e.Handler = NewStack() + e.Handler = handler return *e } @@ -79,7 +79,7 @@ func (e *Environment) MergeLexical(before Environment) { e.StandardInput = before.StandardInput e.StandardOutput = before.StandardOutput e.ErrorOutput = before.ErrorOutput - e.Handler = append(before.Handler, e.Handler[1:]...) + e.Handler = before.Handler } func (e *Environment) MergeDynamic(before Environment) { @@ -100,11 +100,11 @@ func (e *Environment) MergeDynamic(before Environment) { e.StandardInput = before.StandardInput e.StandardOutput = before.StandardOutput e.ErrorOutput = before.ErrorOutput - e.Handler = append(before.Handler, e.Handler[1:]...) + e.Handler = before.Handler } func (before *Environment) NewLexical() Environment { - e := NewEnvironment(before.StandardInput, before.StandardOutput, before.ErrorOutput) + e := NewEnvironment(before.StandardInput, before.StandardOutput, before.ErrorOutput, before.Handler) e.BlockTag = append(before.BlockTag, e.BlockTag[0]) e.TagbodyTag = append(before.TagbodyTag, e.TagbodyTag[0]) @@ -123,13 +123,13 @@ func (before *Environment) NewLexical() Environment { e.StandardInput = before.StandardInput e.StandardOutput = before.StandardOutput e.ErrorOutput = before.ErrorOutput - e.Handler = append(before.Handler, e.Handler[0]) + e.Handler = before.Handler return e } func (before *Environment) NewDynamic() Environment { - e := NewEnvironment(before.StandardInput, before.StandardOutput, before.ErrorOutput) + e := NewEnvironment(before.StandardInput, before.StandardOutput, before.ErrorOutput, before.Handler) e.BlockTag = append(stack{before.BlockTag[0]}, e.BlockTag[0]) e.TagbodyTag = append(stack{before.TagbodyTag[0]}, e.TagbodyTag[0]) @@ -148,7 +148,7 @@ func (before *Environment) NewDynamic() Environment { e.StandardInput = before.StandardInput e.StandardOutput = before.StandardOutput e.ErrorOutput = before.ErrorOutput - e.Handler = append(before.Handler, e.Handler[0]) + e.Handler = before.Handler return e } diff --git a/runtime/ilos/class/class.go b/runtime/ilos/class/class.go index e07a054..a365f94 100644 --- a/runtime/ilos/class/class.go +++ b/runtime/ilos/class/class.go @@ -54,3 +54,4 @@ var Escape = instance.EscapeClass var CatchTag = instance.CatchTagClass var TagbodyTag = instance.TagbodyTagClass var BlockTag = instance.BlockTagClass +var Continue = instance.ContinueClass diff --git a/runtime/ilos/instance/class.go b/runtime/ilos/instance/class.go index 8cb8e94..8a1098e 100644 --- a/runtime/ilos/instance/class.go +++ b/runtime/ilos/instance/class.go @@ -38,7 +38,7 @@ var FloatingPointUnderflowClass = NewBuiltInClass("", var ControlErrorClass = NewBuiltInClass("", ErrorClass) var ParseErrorClass = NewBuiltInClass("", ErrorClass, "STRING", "EXPECTED-CLASS") var ProgramErrorClass = NewBuiltInClass("", ErrorClass) -var DomainErrorClass = NewBuiltInClass("", ProgramErrorClass, "OBJECT", "EXPECTED-CLASS") +var DomainErrorClass = NewBuiltInClass("", ProgramErrorClass, "IRIS.OBJECT", "EXPECTED-CLASS") var UndefinedEntityClass = NewBuiltInClass("", ProgramErrorClass, "NAME", "NAMESPACE") var UndefinedVariableClass = NewBuiltInClass("", UndefinedEntityClass) var UndefinedFunctionClass = NewBuiltInClass("", UndefinedEntityClass) @@ -50,7 +50,8 @@ var StandardObjectClass = NewBuiltInClass("", ObjectClass) var StreamClass = NewBuiltInClass("", ObjectClass, "STREAM") // Implementation defined -var EscapeClass = NewBuiltInClass("", ObjectClass, "TAG") -var CatchTagClass = NewBuiltInClass("", EscapeClass, "OBJECT") +var EscapeClass = NewBuiltInClass("", ObjectClass, "IRIS.TAG") +var CatchTagClass = NewBuiltInClass("", EscapeClass, "IRIS.OBJECT") var TagbodyTagClass = NewBuiltInClass("", EscapeClass) -var BlockTagClass = NewBuiltInClass("", EscapeClass, "OBJECT") +var BlockTagClass = NewBuiltInClass("", EscapeClass, "IRIS.OBJECT") +var ContinueClass = NewBuiltInClass("", EscapeClass, "IRIS.OBJECT") diff --git a/runtime/ilos/instance/error.go b/runtime/ilos/instance/error.go index f9accec..f35fc1e 100644 --- a/runtime/ilos/instance/error.go +++ b/runtime/ilos/instance/error.go @@ -35,50 +35,50 @@ func stackTrace() { } func NewArithmeticError(operation, operands ilos.Instance) ilos.Instance { - return Create(env.NewEnvironment(nil, nil, nil), + return Create(env.NewEnvironment(nil, nil, nil, nil), ArithmeticErrorClass, NewSymbol("OPERATION"), operation, NewSymbol("OPERANDS"), operands) } func NewDivisionByZero(operation, operands ilos.Instance) ilos.Instance { - return Create(env.NewEnvironment(nil, nil, nil), + return Create(env.NewEnvironment(nil, nil, nil, nil), DivisionByZeroClass, NewSymbol("OPERATION"), operation, NewSymbol("OPERANDS"), operands) } func NewParseError(str, expectedClass ilos.Instance) ilos.Instance { - return Create(env.NewEnvironment(nil, nil, nil), + return Create(env.NewEnvironment(nil, nil, nil, nil), ParseErrorClass, NewSymbol("STRING"), str, NewSymbol("EXPECTED-CLASS"), expectedClass) } func NewDomainError(object ilos.Instance, expectedClass ilos.Class) ilos.Instance { - return Create(env.NewEnvironment(nil, nil, nil), + return Create(env.NewEnvironment(nil, nil, nil, nil), DomainErrorClass, NewSymbol("CAUSE"), NewSymbol("DOMAIN-ERROR"), - NewSymbol("OBJECT"), object, + NewSymbol("IRIS.OBJECT"), object, NewSymbol("EXPECTED-CLASS"), expectedClass) } func NewUndefinedFunction(name ilos.Instance) ilos.Instance { - return Create(env.NewEnvironment(nil, nil, nil), + return Create(env.NewEnvironment(nil, nil, nil, nil), UndefinedFunctionClass, NewSymbol("NAME"), name, NewSymbol("NAMESPACE"), NewSymbol("FUNCTION")) } func NewUndefinedVariable(name ilos.Instance) ilos.Instance { - return Create(env.NewEnvironment(nil, nil, nil), + return Create(env.NewEnvironment(nil, nil, nil, nil), UndefinedVariableClass, NewSymbol("NAME"), name, NewSymbol("NAMESPACE"), NewSymbol("VARIABLE")) } func NewUndefinedClass(name ilos.Instance) ilos.Instance { - return Create(env.NewEnvironment(nil, nil, nil), + return Create(env.NewEnvironment(nil, nil, nil, nil), UndefinedEntityClass, NewSymbol("NAME"), name, NewSymbol("NAMESPACE"), NewSymbol("CLASS")) @@ -86,26 +86,26 @@ func NewUndefinedClass(name ilos.Instance) ilos.Instance { func NewArityError() ilos.Instance { stackTrace() - return Create(env.NewEnvironment(nil, nil, nil), ProgramErrorClass) + return Create(env.NewEnvironment(nil, nil, nil, nil), ProgramErrorClass) } func NewIndexOutOfRange() ilos.Instance { stackTrace() - return Create(env.NewEnvironment(nil, nil, nil), ProgramErrorClass) + return Create(env.NewEnvironment(nil, nil, nil, nil), ProgramErrorClass) } func NewImmutableBinding() ilos.Instance { stackTrace() - return Create(env.NewEnvironment(nil, nil, nil), ProgramErrorClass) + return Create(env.NewEnvironment(nil, nil, nil, nil), ProgramErrorClass) } func NewSimpleError(formatString, formatArguments ilos.Instance) ilos.Instance { - return Create(env.NewEnvironment(nil, nil, nil), + return Create(env.NewEnvironment(nil, nil, nil, nil), SimpleErrorClass, NewSymbol("FORMAT-STRING"), formatString, NewSymbol("FORMAT-ARGUMENTS"), formatArguments) } func NewControlError() ilos.Instance { - return Create(env.NewEnvironment(nil, nil, nil), ControlErrorClass) + return Create(env.NewEnvironment(nil, nil, nil, nil), ControlErrorClass) } diff --git a/runtime/ilos/instance/tag.go b/runtime/ilos/instance/tag.go index d3184df..914ea76 100644 --- a/runtime/ilos/instance/tag.go +++ b/runtime/ilos/instance/tag.go @@ -9,18 +9,23 @@ import ( "github.com/ta2gch/iris/runtime/ilos" ) -func NewBlockTag(tag, object ilos.Instance) ilos.Instance { - return Create(env.NewEnvironment(nil, nil, nil), +func NewBlockTag(tag, uid, object ilos.Instance) ilos.Instance { + return Create(env.NewEnvironment(nil, nil, nil, nil), BlockTagClass, - NewSymbol("TAG"), tag, - NewSymbol("OBJECT"), object) + NewSymbol("IRIS.TAG"), tag, + NewSymbol("IRIS.UID"), uid, + NewSymbol("IRIS.OBJECT"), object) } -func NewCatchTag(tag, object ilos.Instance) ilos.Instance { - return Create(env.NewEnvironment(nil, nil, nil), +func NewCatchTag(tag, uid, object ilos.Instance) ilos.Instance { + return Create(env.NewEnvironment(nil, nil, nil, nil), CatchTagClass, - NewSymbol("TAG"), tag, - NewSymbol("OBJECT"), object) + NewSymbol("IRIS.TAG"), tag, + NewSymbol("IRIS.UID"), uid, + NewSymbol("IRIS.OBJECT"), object) } -func NewTagbodyTag(tag ilos.Instance) ilos.Instance { - return Create(env.NewEnvironment(nil, nil, nil), TagbodyTagClass, NewSymbol("TAG"), tag) +func NewTagbodyTag(tag, uid ilos.Instance) ilos.Instance { + return Create(env.NewEnvironment(nil, nil, nil, nil), + TagbodyTagClass, + NewSymbol("IRIS.TAG"), tag, + NewSymbol("IRIS.UID"), uid) } diff --git a/runtime/non-local_exits.go b/runtime/non-local_exits.go index 23c5878..b55630c 100644 --- a/runtime/non-local_exits.go +++ b/runtime/non-local_exits.go @@ -41,13 +41,14 @@ is immediately considered invalid. func Block(e env.Environment, tag ilos.Instance, body ...ilos.Instance) (ilos.Instance, ilos.Instance) { var err ilos.Instance tag, err = Eval(e, tag) // Checked at the top of// This function + uid := genUID() if err != nil { return nil, err } if ilos.InstanceOf(class.Number, tag) || ilos.InstanceOf(class.Character, tag) { return nil, instance.NewDomainError(tag, class.Object) } - if !e.BlockTag.Define(tag, nil) { + if !e.BlockTag.Define(tag, uid) { return nil, instance.NewImmutableBinding() } var fail ilos.Instance @@ -56,9 +57,10 @@ func Block(e env.Environment, tag ilos.Instance, body ...ilos.Instance) (ilos.In sucess, fail = Eval(e, cadr) if fail != nil { if ilos.InstanceOf(class.BlockTag, fail) { - tag1, _ := fail.(instance.Instance).GetSlotValue(instance.NewSymbol("TAG"), class.Escape) // Checked at the head of// This condition - if tag == tag1 { - obj, _ := fail.(instance.Instance).GetSlotValue(instance.NewSymbol("OBJECT"), class.BlockTag) // Checked at the head of// This condition + tag1, _ := fail.(instance.Instance).GetSlotValue(instance.NewSymbol("IRIS.TAG"), class.Escape) // Checked at the head of// This condition + uid1, _ := fail.(instance.Instance).GetSlotValue(instance.NewSymbol("IRIS.UID"), class.Escape) + if tag == tag1 && uid == uid1 { + obj, _ := fail.(instance.Instance).GetSlotValue(instance.NewSymbol("IRIS.OBJECT"), class.BlockTag) // Checked at the head of// This condition return obj, nil } } @@ -81,22 +83,24 @@ func ReturnFrom(e env.Environment, tag, object ilos.Instance) (ilos.Instance, il if err != nil { return nil, err } - if _, ok := e.BlockTag.Get(tag); !ok { + uid, ok := e.BlockTag.Get(tag) + if !ok { return nil, instance.NewSimpleError(instance.NewString("%v is not defined as the tag"), tag) } - return nil, instance.NewBlockTag(tag, object) + return nil, instance.NewBlockTag(tag, uid, object) } func Catch(e env.Environment, tag ilos.Instance, body ...ilos.Instance) (ilos.Instance, ilos.Instance) { var err ilos.Instance tag, err = Eval(e, tag) + uid := genUID() if err != nil { return nil, err } if ilos.InstanceOf(class.Number, tag) || ilos.InstanceOf(class.Character, tag) { return nil, instance.NewDomainError(tag, class.Object) } - if !e.CatchTag.Define(tag, nil) { + if !e.CatchTag.Define(tag, uid) { return nil, instance.NewImmutableBinding() } var fail ilos.Instance @@ -105,9 +109,10 @@ func Catch(e env.Environment, tag ilos.Instance, body ...ilos.Instance) (ilos.In sucess, fail = Eval(e, cadr) if fail != nil { if ilos.InstanceOf(class.CatchTag, fail) { - tag1, _ := fail.(instance.Instance).GetSlotValue(instance.NewSymbol("TAG"), class.Escape) // Checked at the head of// This condition - if tag == tag1 { - obj, _ := fail.(instance.Instance).GetSlotValue(instance.NewSymbol("OBJECT"), class.CatchTag) // Checked at the head of// This condition + tag1, _ := fail.(instance.Instance).GetSlotValue(instance.NewSymbol("IRIS.TAG"), class.Escape) // Checked at the head of// This condition + uid1, _ := fail.(instance.Instance).GetSlotValue(instance.NewSymbol("IRIS.UID"), class.Escape) // Checked at the head of// This condition + if tag == tag1 && uid == uid1 { + obj, _ := fail.(instance.Instance).GetSlotValue(instance.NewSymbol("IRIS.OBJECT"), class.CatchTag) // Checked at the head of// This condition return obj, nil } } @@ -130,39 +135,40 @@ func Throw(e env.Environment, tag, object ilos.Instance) (ilos.Instance, ilos.In if err != nil { return nil, err } - if _, ok := e.CatchTag.Get(tag); !ok { + uid, ok := e.CatchTag.Get(tag) + if !ok { return nil, instance.NewSimpleError(instance.NewString("%v is not defined as the tag"), tag) } - return nil, instance.NewCatchTag(tag, object) + return nil, instance.NewCatchTag(tag, uid, object) } func Tagbody(e env.Environment, body ...ilos.Instance) (ilos.Instance, ilos.Instance) { - for idx, cadr := range body { - cddr := instance.GeneralVector(body[idx+1:]) + uid := genUID() + for _, cadr := range body { if !ilos.InstanceOf(class.Cons, cadr) { - if !e.TagbodyTag.Define(cadr, cddr) { + if !e.TagbodyTag.Define(cadr, uid) { // ref cddr return nil, instance.NewImmutableBinding() } } } - for _, cadr := range body { + for idx, cadr := range body { if ilos.InstanceOf(class.Cons, cadr) { _, fail := Eval(e, cadr) if fail != nil { TAG: if ilos.InstanceOf(class.TagbodyTag, fail) { - tag, _ := fail.(instance.Instance).GetSlotValue(instance.NewSymbol("TAG"), class.Escape) // Checked at the top of// This loop + tag1, _ := fail.(instance.Instance).GetSlotValue(instance.NewSymbol("IRIS.TAG"), class.Escape) // Checked at the top of// This loop + uid1, _ := fail.(instance.Instance).GetSlotValue(instance.NewSymbol("IRIS.UID"), class.Escape) // Checked at the top of// This loop found := false - for _, tag1 := range body { - if tag == tag1 { + for _, tag := range body { + if tag == tag1 && uid == uid1 { found = true break } } if found { - forms, _ := e.TagbodyTag.Get(tag) // Checked in the function, tagbodyGo - for _, form := range forms.(instance.GeneralVector) { + for _, form := range body[idx+1:] { if ilos.InstanceOf(class.Cons, form) { _, fail = Eval(e, form) if fail != nil { @@ -182,11 +188,11 @@ func Tagbody(e env.Environment, body ...ilos.Instance) (ilos.Instance, ilos.Inst } func Go(e env.Environment, tag ilos.Instance) (ilos.Instance, ilos.Instance) { - if _, ok := e.TagbodyTag.Get(tag); !ok { + uid, ok := e.TagbodyTag.Get(tag) + if !ok { return nil, instance.NewSimpleError(instance.NewString("%v is not defined as the tag"), tag) - } - return nil, instance.NewTagbodyTag(tag) + return nil, instance.NewTagbodyTag(tag, uid) } // UnwindProtect first evaluates form. Evaluation of the cleanup-forms always diff --git a/runtime/stream.go b/runtime/stream.go index 4b633c7..435f7cc 100644 --- a/runtime/stream.go +++ b/runtime/stream.go @@ -307,7 +307,7 @@ func StreamReadyP(e env.Environment, inputStream ilos.Instance) (ilos.Instance, func Format(e env.Environment, stream, formatString ilos.Instance, objs ...ilos.Instance) (ilos.Instance, ilos.Instance) { f := regexp.MustCompile("([^~])~A").ReplaceAllString(string(formatString.(instance.String)), "%1%v") - f = regexp.MustCompile(`\`).ReplaceAllString(string(formatString.(instance.String)), `\\`) + f = regexp.MustCompile(`\\`).ReplaceAllString(string(formatString.(instance.String)), `\\`) f = regexp.MustCompile("([^~])~%").ReplaceAllString(string(formatString.(instance.String)), "%1\n") if b, _ := OutputStreamp(e, stream); b == Nil { return nil, nil // throw Error diff --git a/runtime/util.go b/runtime/util.go index e0eb23f..09ed133 100644 --- a/runtime/util.go +++ b/runtime/util.go @@ -87,4 +87,10 @@ func ensure(c ilos.Class, i ...ilos.Instance) ilos.Instance { return nil } -var TopLevel = env.NewEnvironment(instance.NewStream(os.Stdin, nil), instance.NewStream(nil, os.Stdout), instance.NewStream(nil, os.Stderr)) +var TopLevel = env.NewEnvironment(instance.NewStream(os.Stdin, nil), instance.NewStream(nil, os.Stdout), instance.NewStream(nil, os.Stderr), nil) +var uidsrc = 0 + +func genUID() ilos.Instance { + uidsrc++ + return instance.NewInteger(uidsrc) +} From 630fb7476e098a5bf9954e96d68a3cf7b4aa7553 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Wed, 23 Aug 2017 20:23:58 +0900 Subject: [PATCH 210/228] Added REPL --- cmd/main.go | 24 +++ reader/parser/parser.go | 8 + runtime/class.go | 2 +- runtime/defining_classes.go | 2 +- runtime/defining_operators.go | 14 +- runtime/defining_operators_test.go | 13 +- runtime/generic_functions.go | 8 +- runtime/number_class.go | 4 +- runtime/runtime.go | 290 +++++++++++++++++++++++++++++ runtime/sequence_functions.go | 2 +- runtime/stream.go | 14 +- runtime/util.go | 33 ---- 12 files changed, 356 insertions(+), 58 deletions(-) create mode 100644 cmd/main.go create mode 100644 runtime/runtime.go diff --git a/cmd/main.go b/cmd/main.go new file mode 100644 index 0000000..f887f49 --- /dev/null +++ b/cmd/main.go @@ -0,0 +1,24 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package main + +import ( + "fmt" + + "github.com/ta2gch/iris/runtime" +) + +func main() { + env := runtime.New() + fmt.Print("> ") + for exp, err := runtime.Read(env); err == nil; exp, err = runtime.Read(env) { + ret, err := runtime.Eval(env, exp) + if err != nil { + fmt.Println(err) + } + fmt.Println(ret) + fmt.Print("> ") + } +} diff --git a/reader/parser/parser.go b/reader/parser/parser.go index 3a52cc7..a76461a 100644 --- a/reader/parser/parser.go +++ b/reader/parser/parser.go @@ -154,6 +154,14 @@ func Parse(t *tokenizer.Tokenizer) (ilos.Instance, ilos.Instance) { if err != nil { return nil, err } + /* + for tok[:2] != "#|" || tok[:1] != ";" { + tok, err = t.Next() + if err != nil { + return nil, err + } + } + */ if tok == "(" { cons, err := parseCons(t) if err != nil { diff --git a/runtime/class.go b/runtime/class.go index 7ab536b..30c36dc 100644 --- a/runtime/class.go +++ b/runtime/class.go @@ -29,7 +29,7 @@ func Subclassp(e env.Environment, class1, class2 ilos.Class) (ilos.Instance, ilo } func Class(e env.Environment, className ilos.Instance) (ilos.Class, ilos.Instance) { - if v, ok := TopLevel.Class.Get(className); ok { + if v, ok := e.Class[:1].Get(className); ok { return v.(ilos.Class), nil } return nil, instance.NewUndefinedClass(className) diff --git a/runtime/defining_classes.go b/runtime/defining_classes.go index 0e80d51..0338f0b 100644 --- a/runtime/defining_classes.go +++ b/runtime/defining_classes.go @@ -95,7 +95,7 @@ func Defclass(e env.Environment, className, scNames, slotSpecs ilos.Instance, cl } } classObject := instance.NewStandardClass(className, supers, slots, initforms, initargs, metaclass, abstractp) - TopLevel.Class.Define(className, classObject) + e.Class[:1].Define(className, classObject) for _, slotSpec := range slotSpecs.(instance.List).Slice() { if ilos.InstanceOf(class.Symbol, slotSpec) { continue diff --git a/runtime/defining_operators.go b/runtime/defining_operators.go index 076648d..4d21c87 100644 --- a/runtime/defining_operators.go +++ b/runtime/defining_operators.go @@ -24,14 +24,14 @@ func Defconstant(e env.Environment, name, form ilos.Instance) (ilos.Instance, il if err := ensure(class.Symbol, name); err != nil { return nil, err } - if _, ok := TopLevel.Constant.Get(name); ok { + if _, ok := e.Constant[:1].Get(name); ok { return nil, instance.NewImmutableBinding() } ret, err := Eval(e, form) if err != nil { return nil, err } - TopLevel.Constant.Define(name, ret) + e.Constant[:1].Define(name, ret) return name, nil } @@ -48,14 +48,14 @@ func Defglobal(e env.Environment, name, form ilos.Instance) (ilos.Instance, ilos if err := ensure(class.Symbol, name); err != nil { return nil, err } - if _, ok := TopLevel.Constant.Get(name); ok { + if _, ok := e.Constant[:1].Get(name); ok { return nil, instance.NewImmutableBinding() } ret, err := Eval(e, form) if err != nil { return nil, err } - TopLevel.Variable.Define(name, ret) + e.Variable[:1].Define(name, ret) return name, nil } @@ -67,14 +67,14 @@ func Defdynamic(e env.Environment, name, form ilos.Instance) (ilos.Instance, ilo if err := ensure(class.Symbol, name); err != nil { return nil, err } - if _, ok := TopLevel.Constant.Get(name); ok { + if _, ok := e.Constant[:1].Get(name); ok { return nil, instance.NewImmutableBinding() } ret, err := Eval(e, form) if err != nil { return nil, err } - TopLevel.DynamicVariable.Define(name, ret) + e.DynamicVariable[:1].Define(name, ret) return name, nil } @@ -96,6 +96,6 @@ func Defun(e env.Environment, functionName, lambdaList ilos.Instance, forms ...i if err != nil { return nil, err } - TopLevel.Function.Define(functionName, ret) + e.Function[:1].Define(functionName, ret) return functionName, nil } diff --git a/runtime/defining_operators_test.go b/runtime/defining_operators_test.go index 09366c3..804f048 100644 --- a/runtime/defining_operators_test.go +++ b/runtime/defining_operators_test.go @@ -117,10 +117,19 @@ func TestDefun(t *testing.T) { defspecial(Defconstant) defspecial(Quote) defspecial(Defun) + defspecial(If) + defun2("<", NumberLessThan) + defun2("+", Add) + defun2("-", Substruct) tests := []test{ { - exp: `(defun caar (x) (car (car x)))`, - want: `'caar`, + exp: `(defun fib (x) (if (< x 3) 1 (+ (fib (- x 1)) (fib (- x 2)))))`, + want: `'fib`, + wantErr: false, + }, + { + exp: `(fib 10)`, + want: `55`, wantErr: false, }, } diff --git a/runtime/generic_functions.go b/runtime/generic_functions.go index cd3ce3d..78f5376 100644 --- a/runtime/generic_functions.go +++ b/runtime/generic_functions.go @@ -42,7 +42,7 @@ func Defmethod(e env.Environment, arguments ...ilos.Instance) (ilos.Instance, il if ilos.InstanceOf(class.Symbol, pp) { classList = append(classList, class.Object) } else { - class, ok := TopLevel.Class.Get(pp.(instance.List).Nth(1)) + class, ok := e.Class[:1].Get(pp.(instance.List).Nth(1)) if !ok { return nil, instance.NewUndefinedClass(pp.(instance.List).Nth(1)) } @@ -53,7 +53,7 @@ func Defmethod(e env.Environment, arguments ...ilos.Instance) (ilos.Instance, il if err != nil { return nil, err } - gen, ok := TopLevel.Function.Get(name) + gen, ok := e.Function[:1].Get(name) if !ok { return nil, instance.NewUndefinedFunction(name) } @@ -72,7 +72,7 @@ func Defgeneric(e env.Environment, funcSpec, lambdaList ilos.Instance, optionsOr case instance.NewSymbol(":METHOD-COMBINATION"): methodCombination = optionOrMethodDesc.(instance.List).Nth(1) case instance.NewSymbol(":GENERIC-FUNCTION-CLASS"): - class, ok := TopLevel.Class.Get(optionOrMethodDesc.(instance.List).Nth(1)) + class, ok := e.Class[:1].Get(optionOrMethodDesc.(instance.List).Nth(1)) if !ok { return nil, instance.NewUndefinedClass(optionOrMethodDesc.(instance.List).Nth(1)) } @@ -81,7 +81,7 @@ func Defgeneric(e env.Environment, funcSpec, lambdaList ilos.Instance, optionsOr forms = append(forms, instance.NewCons(instance.NewSymbol("DEFMETHOD"), optionOrMethodDesc.(instance.List).NthCdr(1))) } } - TopLevel.Function.Define(funcSpec, instance.NewGenericFunction(funcSpec, lambdaList, methodCombination, genericFunctionClass)) + e.Function[:1].Define(funcSpec, instance.NewGenericFunction(funcSpec, lambdaList, methodCombination, genericFunctionClass)) Progn(e, forms...) return funcSpec, nil } diff --git a/runtime/number_class.go b/runtime/number_class.go index 234544f..ed026c5 100644 --- a/runtime/number_class.go +++ b/runtime/number_class.go @@ -125,8 +125,8 @@ func NumberLessThan(e env.Environment, x1, x2 ilos.Instance) (ilos.Instance, ilo return Not(e, ge) } -// NumberLessThanOrEqulal returns t if x1 is less than or = x2 -func NumberLessThanOrEqulal(e env.Environment, x1, x2 ilos.Instance) (ilos.Instance, ilos.Instance) { +// NumberLessThanOrEqual returns t if x1 is less than or = x2 +func NumberLessThanOrEqual(e env.Environment, x1, x2 ilos.Instance) (ilos.Instance, ilos.Instance) { gt, err := NumberGreaterThan(e, x1, x2) if err != nil { return nil, err diff --git a/runtime/runtime.go b/runtime/runtime.go new file mode 100644 index 0000000..63eaa2d --- /dev/null +++ b/runtime/runtime.go @@ -0,0 +1,290 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package runtime + +import ( + "math" + "os" + "reflect" + "regexp" + "runtime" + "strings" + + "github.com/ta2gch/iris/runtime/env" + "github.com/ta2gch/iris/runtime/ilos" + "github.com/ta2gch/iris/runtime/ilos/instance" +) + +func func2symbol(function interface{}) ilos.Instance { + name := runtime.FuncForPC(reflect.ValueOf(function).Pointer()).Name() + name = regexp.MustCompile(`.*\.`).ReplaceAllString(name, "") + name = regexp.MustCompile(`(.)([A-Z])`).ReplaceAllString(name, "$1-$2") + name = strings.ToUpper(name) + return instance.NewSymbol(name) +} + +var TopLevel = env.NewEnvironment(instance.NewStream(os.Stdin, nil), instance.NewStream(nil, os.Stdout), instance.NewStream(nil, os.Stderr), nil) + +func defspecial(function interface{}) { + TopLevel.Special.Define(func2symbol(function), instance.NewFunction(func2symbol(function), function)) +} + +func defmacro(function interface{}) { + TopLevel.Macro.Define(func2symbol(function), instance.NewFunction(func2symbol(function), function)) +} + +func defun(function interface{}) { + TopLevel.Function.Define(func2symbol(function), instance.NewFunction(func2symbol(function), function)) +} + +func defun2(name string, function interface{}) { + symbol := instance.NewSymbol(name) + TopLevel.Function.Define(symbol, instance.NewFunction(symbol, function)) +} +func defglobal(name string, value ilos.Instance) { + symbol := instance.NewSymbol(name) + TopLevel.Variable.Define(symbol, value) +} + +func New() env.Environment { + toplevel := env.NewEnvironment(instance.NewStream(os.Stdin, nil), instance.NewStream(nil, os.Stdout), instance.NewStream(nil, os.Stderr), nil) + defspecial := func(function interface{}) { + toplevel.Special.Define(func2symbol(function), instance.NewFunction(func2symbol(function), function)) + } + defspecial2 := func(name string, function interface{}) { + symbol := instance.NewSymbol(name) + toplevel.Special.Define(symbol, instance.NewFunction(func2symbol(function), function)) + } + defun := func(function interface{}) { + toplevel.Function.Define(func2symbol(function), instance.NewFunction(func2symbol(function), function)) + } + defun2 := func(name string, function interface{}) { + symbol := instance.NewSymbol(name) + toplevel.Function.Define(symbol, instance.NewFunction(symbol, function)) + } + defglobal := func(name string, value ilos.Instance) { + symbol := instance.NewSymbol(name) + toplevel.Variable.Define(symbol, value) + } + defglobal("*PI*", instance.Float(math.Pi)) + defglobal("MOST-POSITIVE-FLOAT", MostPositiveFloat) + defglobal("MOST-NEGATIVE-FLOAT", MostNegativeFloat) + defun2("-", Substruct) + defun2("+", Add) + defun2("*", Multiply) + defun2("<", NumberLessThan) + defun2("<=", NumberLessThanOrEqual) + defun2("=", NumberEqual) + defun2(">", NumberGreaterThan) + defun2(">=", NumberGreaterThanOrEqual) + defspecial(Quasiquote) + defun(Abs) + defspecial(And) + defun(Append) + defun(Apply) + defun(Aref) + defun(Assoc) + // TODO: defspecial(Assure) + defun(Atan) + defun(Atan2) + defun(Atanh) + defun2("BASIC-ARRAY*-P", BasicArrayStarP) + defun(BasicArrayP) + defun(BasicVectorP) + defspecial(Block) + defun(Car) + defspecial(Case) + defspecial(CaseUsing) + defspecial(Catch) + defun(Cdr) + defun(Ceiling) + defun(Cerror) + defun(CharIndex) + defun2("char/=", CharNotEqual) + defun2("Char<", CharLessThan) + defun2("Char<=", CharLessThanOrEqual) + defun2("Char=", CharEqual) + defun2("Char>", CharGreaterThan) + defun2("Char>=", CharGreaterThanOrEqual) + defun(Characterp) + defspecial(Class) + defun(ClassOf) + defun(Close) + // TODO defun(Coercion) + defspecial(Cond) + defun(ConditionContinuable) + defun(Cons) + defun(Consp) + defun(ContinueCondition) + // TODO defun(Convert) + defun(Cos) + defun(Cosh) + defun(Create) //TODO Change to generic function + defun(CreateArray) + defun(CreateList) + defun(CreateString) + defun(CreateStringInputStream) + defun(CreateStringOutputStream) + defun(CreateVector) + defspecial(Defclass) + defspecial(Defconstant) + defspecial(Defdynamic) + defspecial(Defgeneric) + defspecial(Defglobal) + defspecial(Defmacro) + defspecial(Defun) + defun(Div) + defspecial(Dynamic) + defspecial(DynamicLet) + defun(Elt) + defun(Eq) + defun(Eql) + defun(Equal) + defun(Error) + defun(ErrorOutput) + defun(Exp) + defun(Expt) + // TODO defun(FileLength) + // TODO defun(FilePosition) + // TODO defun(FinishOutput) + defspecial(Flet) + defun(Float) + defun(Floatp) + defun(Floor) + defspecial(For) + defun(Format) // TODO full syntax + // TODO other print function + defun(Funcall) + defspecial(Function) + defun(Functionp) + defun(Garef) + defun(Gcd) + defun2("GENERAL-ARRAY*-P", GeneralArrayStarP) + defun(GeneralVectorP) + // TODO defun(GenericFunctionP) + defun(Gensym) + // TODO defun(GetInternalRealTime) + // TODO defun(GetInternalRunTime) + defun(GetOutputStreamString) + // TODO defun(GetUniversalTime) + defspecial(Go) + // TODO defun(Identity) + defspecial(If) + // TODO defspecial(IgnoreErrors) + defun(InitializeObject) // TODO change generic function + defun(InputStreamP) + defun(Instancep) + // TODO defun(Integer) + defun(Integerp) + // TODO defun(InternalTimeUnitsPerSecond) + defun(Isqrt) + defspecial(Labels) + defspecial(Lambda) + defun(Lcm) + defun(Length) + defspecial(Let) + defspecial2("LET*", LetStar) + defun(List) + defun(Listp) + defun(Log) + defun(MapInto) + defun(Mapc) + defun(Mapcan) + defun(Mapcar) + defun(Mapcon) + defun(Mapl) + defun(Maplist) + defun(Max) + defun(Member) + defun(Min) + defun(Mod) + defglobal("NIL", Nil) + defun(Not) + defun(Nreverse) + defun(Null) + defun(Numberp) + defun(OpenInputFile) + defun(OpenIoFile) + defun(OpenOutputFile) + defun(OpenStreamP) + defspecial(Or) + defun(OutputStreamP) + defun(ParseNumber) + // TODO defun(PreviewChar) + // TODO defun(ProveFile) + defspecial(Progn) + defun(Property) + defspecial(Quasiquote) + defspecial(Quote) + defun(Quotient) + defun(Read) + // TODO defun(ReadByte) + defun(ReadChar) + defun(ReadLine) + defun(RemoveProperty) + defun(ReportCondition) + defspecial(ReturnFrom) + defun(Reverse) + defun(Round) + defun(SetAref) + defun2("(SETF AREF)", SetAref) + defun(SetCar) + defun2("(SETF CAR)", SetCar) + defun(SetCdr) + defun2("(SETF CDR)", SetCdr) + defun(SetDynamic) + defun2("(SETF DYNAMIC)", SetDynamic) + defun(SetElt) + defun2("(SETF ELT)", SetElt) + // TODO defun(SetFilePosition) + defun(SetGaref) + defun2("(SETF GAREF)", SetGaref) + defun(SetProperty) + defun2("(SETF PROPERTY)", SetProperty) + defun(Setf) + defun(Setq) + defun(SignalCondition) + // TODO defun(SimpleErrorFormatArguments) + // TODO defun(SimpleErrorFormatString) + defun(Sin) + defun(Sinh) + defun(Sqrt) + defun(StandardInput) + defun(StandardOutput) + defun(StreamReadyP) + defun(Streamp) + defun(StringAppend) + defun(StringIndex) + defun2("STRING/=", StringNotEqual) + defun2("STRING<", StringGreaterThan) + defun2("STRING<=", StringGreaterThan) + defun2("STRING=", StringEqual) + defun2("STRIN>", StringGreaterThan) + defun2("STRING>=", StringGreaterThanOrEqual) + defun(Stringp) + defun(Subclassp) + defun(Subseq) + defun(Symbolp) + defglobal("T", T) + defspecial(Tagbody) + defspecial(Tan) + defspecial(Tanh) + // TODO defspecial(The) + defspecial(Throw) + defun(Truncate) + // TODO defun(UndefinedEntityName) + // TODO defun(UndefinedEntityNamespace) + defspecial(UnwindProtect) + defun(Vector) + defspecial(While) + defspecial(WithErrorOutput) + defspecial(WithHandler) + defspecial(WithOpenInputFile) + defspecial(WithOpenOutputFile) + defspecial(WithStandardInput) + defspecial(WithStandardOutput) + // TODO defun(WriteByte) + return toplevel +} diff --git a/runtime/sequence_functions.go b/runtime/sequence_functions.go index e5a1fc3..0624e4d 100644 --- a/runtime/sequence_functions.go +++ b/runtime/sequence_functions.go @@ -175,7 +175,7 @@ func Subseq(e env.Environment, sequence, z1, z2 ilos.Instance) (ilos.Instance, i // // An error shall be signaled if any sequence is not a basic-vector or a list // (error-id. domain-error). -func mapInto(e env.Environment, destination, function ilos.Instance, sequences ...ilos.Instance) (ilos.Instance, ilos.Instance) { +func MapInto(e env.Environment, destination, function ilos.Instance, sequences ...ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.List, append(sequences, destination)...); err != nil { if err := ensure(class.BasicVector, append(sequences, destination)...); err != nil { return nil, err diff --git a/runtime/stream.go b/runtime/stream.go index 435f7cc..3d4a30f 100644 --- a/runtime/stream.go +++ b/runtime/stream.go @@ -31,14 +31,14 @@ func OpenStreamP(e env.Environment, obj ilos.Instance) (ilos.Instance, ilos.Inst return T, nil } -func InputStreamp(e env.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { +func InputStreamP(e env.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { if s, ok := obj.(instance.Stream); ok && s.Reader != nil { return T, nil } return Nil, nil } -func OutputStreamp(e env.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { +func OutputStreamP(e env.Environment, obj ilos.Instance) (ilos.Instance, ilos.Instance) { if s, ok := obj.(instance.Stream); ok && s.Writer != nil { return T, nil } @@ -213,7 +213,7 @@ func Read(e env.Environment, options ...ilos.Instance) (ilos.Instance, ilos.Inst if len(options) > 0 { s = options[0] } - if b, _ := InputStreamp(e, s); b == Nil { + if b, _ := InputStreamP(e, s); b == Nil { return nil, nil // throw Error } eosErrorP := true @@ -229,7 +229,7 @@ func Read(e env.Environment, options ...ilos.Instance) (ilos.Instance, ilos.Inst } } v, err := parser.Parse(tokenizer.New(s.(instance.Stream).Reader)) - if ilos.InstanceOf(class.EndOfStream, err) { + if err != nil && ilos.InstanceOf(class.EndOfStream, err) { if eosErrorP { return nil, err } @@ -243,7 +243,7 @@ func ReadChar(e env.Environment, options ...ilos.Instance) (ilos.Instance, ilos. if len(options) > 0 { s = options[0] } - if b, _ := InputStreamp(e, s); b == Nil { + if b, _ := InputStreamP(e, s); b == Nil { return nil, nil // throw Error } eosErrorP := true @@ -273,7 +273,7 @@ func ReadLine(e env.Environment, options ...ilos.Instance) (ilos.Instance, ilos. if len(options) > 0 { s = options[0] } - if b, _ := InputStreamp(e, s); b == Nil { + if b, _ := InputStreamP(e, s); b == Nil { return nil, nil // throw Error } eosErrorP := true @@ -309,7 +309,7 @@ func Format(e env.Environment, stream, formatString ilos.Instance, objs ...ilos. f := regexp.MustCompile("([^~])~A").ReplaceAllString(string(formatString.(instance.String)), "%1%v") f = regexp.MustCompile(`\\`).ReplaceAllString(string(formatString.(instance.String)), `\\`) f = regexp.MustCompile("([^~])~%").ReplaceAllString(string(formatString.(instance.String)), "%1\n") - if b, _ := OutputStreamp(e, stream); b == Nil { + if b, _ := OutputStreamP(e, stream); b == Nil { return nil, nil // throw Error } args := []interface{}{} diff --git a/runtime/util.go b/runtime/util.go index 09ed133..b2236bc 100644 --- a/runtime/util.go +++ b/runtime/util.go @@ -5,10 +5,6 @@ package runtime import ( - "os" - "reflect" - "regexp" - "runtime" "strings" "github.com/ta2gch/iris/runtime/env" @@ -50,34 +46,6 @@ func evalString(e env.Environment, s string) ilos.Instance { return ret } -func func2symbol(function interface{}) ilos.Instance { - name := runtime.FuncForPC(reflect.ValueOf(function).Pointer()).Name() - name = regexp.MustCompile(`.*\.`).ReplaceAllString(name, "") - name = regexp.MustCompile(`(.)([A-Z])`).ReplaceAllString(name, "$1-$2") - name = strings.ToUpper(name) - return instance.NewSymbol(name) -} - -func defspecial(function interface{}) { - TopLevel.Special.Define(func2symbol(function), instance.NewFunction(func2symbol(function), function)) -} - -func defmacro(function interface{}) { - TopLevel.Macro.Define(func2symbol(function), instance.NewFunction(func2symbol(function), function)) -} - -func defun(function interface{}) { - TopLevel.Function.Define(func2symbol(function), instance.NewFunction(func2symbol(function), function)) -} - -func defun2(name string, function interface{}) { - symbol := instance.NewSymbol(name) - TopLevel.Function.Define(symbol, instance.NewFunction(symbol, function)) -} -func defglobal(name string, value ilos.Instance) { - symbol := instance.NewSymbol(name) - TopLevel.Variable.Define(symbol, value) -} func ensure(c ilos.Class, i ...ilos.Instance) ilos.Instance { for _, o := range i { if !ilos.InstanceOf(c, o) { @@ -87,7 +55,6 @@ func ensure(c ilos.Class, i ...ilos.Instance) ilos.Instance { return nil } -var TopLevel = env.NewEnvironment(instance.NewStream(os.Stdin, nil), instance.NewStream(nil, os.Stdout), instance.NewStream(nil, os.Stderr), nil) var uidsrc = 0 func genUID() ilos.Instance { From ab9051544e93365873c1bb15bb195f0825958037 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Thu, 24 Aug 2017 00:31:40 +0900 Subject: [PATCH 211/228] Added online repl --- docs/_config.yml | 17 - docs/_includes/footer.html | 3 - docs/_includes/head.html | 11 - docs/_includes/header.html | 3 - docs/_layouts/default.html | 11 - docs/_layouts/page.html | 6 - docs/_layouts/post.html | 7 - docs/_pages/01_about.md | 33 - docs/_sass/_base.scss | 0 docs/_sass/_code.scss | 0 docs/css/main.scss | 1 - docs/index.html | 23 +- docs/jquery-3.2.1.js | 10253 +++++++++ docs/main.go | 32 + docs/main.js | 40225 +++++++++++++++++++++++++++++++++++ docs/main.js.map | 1 + 16 files changed, 50528 insertions(+), 98 deletions(-) delete mode 100644 docs/_config.yml delete mode 100644 docs/_includes/footer.html delete mode 100644 docs/_includes/head.html delete mode 100644 docs/_includes/header.html delete mode 100644 docs/_layouts/default.html delete mode 100644 docs/_layouts/page.html delete mode 100644 docs/_layouts/post.html delete mode 100644 docs/_pages/01_about.md delete mode 100644 docs/_sass/_base.scss delete mode 100644 docs/_sass/_code.scss delete mode 100644 docs/css/main.scss create mode 100644 docs/jquery-3.2.1.js create mode 100644 docs/main.go create mode 100644 docs/main.js create mode 100644 docs/main.js.map diff --git a/docs/_config.yml b/docs/_config.yml deleted file mode 100644 index ebcd1cd..0000000 --- a/docs/_config.yml +++ /dev/null @@ -1,17 +0,0 @@ -name: iris -email: ta2gch@moffice.space -description: iris is a interpreter of ISLisp. -baseurl: "iris" -url: "https://ta2gch.github.io" -twitter_username: ta2gch -github_username: ta2gch -# Build Settings -sass: - sass_dir: _sass -include: ['_pages'] -gems: - - jemoji - - jekyll-mentions - - jekyll-redirect-from - - jekyll-sitemap - - jekyll-feed \ No newline at end of file diff --git a/docs/_includes/footer.html b/docs/_includes/footer.html deleted file mode 100644 index 69ca609..0000000 --- a/docs/_includes/footer.html +++ /dev/null @@ -1,3 +0,0 @@ - \ No newline at end of file diff --git a/docs/_includes/head.html b/docs/_includes/head.html deleted file mode 100644 index 2cad684..0000000 --- a/docs/_includes/head.html +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - {% if page.title %}{{ page.title }}{% else %}{{ site.title }}{% endif %} - - - - {% feed_meta %} - \ No newline at end of file diff --git a/docs/_includes/header.html b/docs/_includes/header.html deleted file mode 100644 index 4b2cfd3..0000000 --- a/docs/_includes/header.html +++ /dev/null @@ -1,3 +0,0 @@ -
-

{{ site.title }}

-
\ No newline at end of file diff --git a/docs/_layouts/default.html b/docs/_layouts/default.html deleted file mode 100644 index 33ddc0d..0000000 --- a/docs/_layouts/default.html +++ /dev/null @@ -1,11 +0,0 @@ - - -{% include head.html %} - - {% include header.html %} -
- {{ content }} -
- {% include footer.html %} - - diff --git a/docs/_layouts/page.html b/docs/_layouts/page.html deleted file mode 100644 index 2982d8f..0000000 --- a/docs/_layouts/page.html +++ /dev/null @@ -1,6 +0,0 @@ ---- -layout: default ---- -

{{ page.title }}

- -{{ content }} diff --git a/docs/_layouts/post.html b/docs/_layouts/post.html deleted file mode 100644 index e57fec2..0000000 --- a/docs/_layouts/post.html +++ /dev/null @@ -1,7 +0,0 @@ ---- -layout: default ---- -

{{ page.title }}

- - -{{ content }} diff --git a/docs/_pages/01_about.md b/docs/_pages/01_about.md deleted file mode 100644 index 1e37b66..0000000 --- a/docs/_pages/01_about.md +++ /dev/null @@ -1,33 +0,0 @@ ---- -layout: page -title: About -permalink: /about/ ---- - -# iris - -Iris is a interpreter of ISLisp implemented with golang - -[![Build Status](https://travis-ci.org/ta2gch/iris.svg?branch=master)](https://travis-ci.org/ta2gch/iris) - -## Introduction - -ISLisp is a member of LISP family and standardized by ISO in 2007. -As you know, Common Lisp is standardized by ANSI in 1994. -Iris is a interpreter of ISLisp implemented with golang. - -## Development - -### Test - -Iris is tested on TravisCI with this command. - -``` -$ go test ./... -``` - -## License -This software is licensed under the Mozilla Public License v2.0 - -## Copyright -Copyright (c) 2017 TANIGUCHI Masaya \ No newline at end of file diff --git a/docs/_sass/_base.scss b/docs/_sass/_base.scss deleted file mode 100644 index e69de29..0000000 diff --git a/docs/_sass/_code.scss b/docs/_sass/_code.scss deleted file mode 100644 index e69de29..0000000 diff --git a/docs/css/main.scss b/docs/css/main.scss deleted file mode 100644 index 4b736a3..0000000 --- a/docs/css/main.scss +++ /dev/null @@ -1 +0,0 @@ -@import "base", "code" \ No newline at end of file diff --git a/docs/index.html b/docs/index.html index a7cc77d..c5358d7 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1,6 +1,17 @@ ---- -layout: default -title: Welcome ---- - -

iris

+ + + + + + + Document + + +
+
+ >
+ + + + + \ No newline at end of file diff --git a/docs/jquery-3.2.1.js b/docs/jquery-3.2.1.js new file mode 100644 index 0000000..d2d8ca4 --- /dev/null +++ b/docs/jquery-3.2.1.js @@ -0,0 +1,10253 @@ +/*! + * jQuery JavaScript Library v3.2.1 + * https://jquery.com/ + * + * Includes Sizzle.js + * https://sizzlejs.com/ + * + * Copyright JS Foundation and other contributors + * Released under the MIT license + * https://jquery.org/license + * + * Date: 2017-03-20T18:59Z + */ +( function( global, factory ) { + + "use strict"; + + if ( typeof module === "object" && typeof module.exports === "object" ) { + + // For CommonJS and CommonJS-like environments where a proper `window` + // is present, execute the factory and get jQuery. + // For environments that do not have a `window` with a `document` + // (such as Node.js), expose a factory as module.exports. + // This accentuates the need for the creation of a real `window`. + // e.g. var jQuery = require("jquery")(window); + // See ticket #14549 for more info. + module.exports = global.document ? + factory( global, true ) : + function( w ) { + if ( !w.document ) { + throw new Error( "jQuery requires a window with a document" ); + } + return factory( w ); + }; + } else { + factory( global ); + } + +// Pass this if window is not defined yet +} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) { + +// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1 +// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode +// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common +// enough that all such attempts are guarded in a try block. +"use strict"; + +var arr = []; + +var document = window.document; + +var getProto = Object.getPrototypeOf; + +var slice = arr.slice; + +var concat = arr.concat; + +var push = arr.push; + +var indexOf = arr.indexOf; + +var class2type = {}; + +var toString = class2type.toString; + +var hasOwn = class2type.hasOwnProperty; + +var fnToString = hasOwn.toString; + +var ObjectFunctionString = fnToString.call( Object ); + +var support = {}; + + + + function DOMEval( code, doc ) { + doc = doc || document; + + var script = doc.createElement( "script" ); + + script.text = code; + doc.head.appendChild( script ).parentNode.removeChild( script ); + } +/* global Symbol */ +// Defining this global in .eslintrc.json would create a danger of using the global +// unguarded in another place, it seems safer to define global only for this module + + + +var + version = "3.2.1", + + // Define a local copy of jQuery + jQuery = function( selector, context ) { + + // The jQuery object is actually just the init constructor 'enhanced' + // Need init if jQuery is called (just allow error to be thrown if not included) + return new jQuery.fn.init( selector, context ); + }, + + // Support: Android <=4.0 only + // Make sure we trim BOM and NBSP + rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, + + // Matches dashed string for camelizing + rmsPrefix = /^-ms-/, + rdashAlpha = /-([a-z])/g, + + // Used by jQuery.camelCase as callback to replace() + fcamelCase = function( all, letter ) { + return letter.toUpperCase(); + }; + +jQuery.fn = jQuery.prototype = { + + // The current version of jQuery being used + jquery: version, + + constructor: jQuery, + + // The default length of a jQuery object is 0 + length: 0, + + toArray: function() { + return slice.call( this ); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + + // Return all the elements in a clean array + if ( num == null ) { + return slice.call( this ); + } + + // Return just the one element from the set + return num < 0 ? this[ num + this.length ] : this[ num ]; + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems ) { + + // Build a new jQuery matched element set + var ret = jQuery.merge( this.constructor(), elems ); + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + each: function( callback ) { + return jQuery.each( this, callback ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map( this, function( elem, i ) { + return callback.call( elem, i, elem ); + } ) ); + }, + + slice: function() { + return this.pushStack( slice.apply( this, arguments ) ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + eq: function( i ) { + var len = this.length, + j = +i + ( i < 0 ? len : 0 ); + return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] ); + }, + + end: function() { + return this.prevObject || this.constructor(); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: push, + sort: arr.sort, + splice: arr.splice +}; + +jQuery.extend = jQuery.fn.extend = function() { + var options, name, src, copy, copyIsArray, clone, + target = arguments[ 0 ] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + + // Skip the boolean and the target + target = arguments[ i ] || {}; + i++; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !jQuery.isFunction( target ) ) { + target = {}; + } + + // Extend jQuery itself if only one argument is passed + if ( i === length ) { + target = this; + i--; + } + + for ( ; i < length; i++ ) { + + // Only deal with non-null/undefined values + if ( ( options = arguments[ i ] ) != null ) { + + // Extend the base object + for ( name in options ) { + src = target[ name ]; + copy = options[ name ]; + + // Prevent never-ending loop + if ( target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( jQuery.isPlainObject( copy ) || + ( copyIsArray = Array.isArray( copy ) ) ) ) { + + if ( copyIsArray ) { + copyIsArray = false; + clone = src && Array.isArray( src ) ? src : []; + + } else { + clone = src && jQuery.isPlainObject( src ) ? src : {}; + } + + // Never move original objects, clone them + target[ name ] = jQuery.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + +jQuery.extend( { + + // Unique for each copy of jQuery on the page + expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), + + // Assume jQuery is ready without the ready module + isReady: true, + + error: function( msg ) { + throw new Error( msg ); + }, + + noop: function() {}, + + isFunction: function( obj ) { + return jQuery.type( obj ) === "function"; + }, + + isWindow: function( obj ) { + return obj != null && obj === obj.window; + }, + + isNumeric: function( obj ) { + + // As of jQuery 3.0, isNumeric is limited to + // strings and numbers (primitives or objects) + // that can be coerced to finite numbers (gh-2662) + var type = jQuery.type( obj ); + return ( type === "number" || type === "string" ) && + + // parseFloat NaNs numeric-cast false positives ("") + // ...but misinterprets leading-number strings, particularly hex literals ("0x...") + // subtraction forces infinities to NaN + !isNaN( obj - parseFloat( obj ) ); + }, + + isPlainObject: function( obj ) { + var proto, Ctor; + + // Detect obvious negatives + // Use toString instead of jQuery.type to catch host objects + if ( !obj || toString.call( obj ) !== "[object Object]" ) { + return false; + } + + proto = getProto( obj ); + + // Objects with no prototype (e.g., `Object.create( null )`) are plain + if ( !proto ) { + return true; + } + + // Objects with prototype are plain iff they were constructed by a global Object function + Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor; + return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString; + }, + + isEmptyObject: function( obj ) { + + /* eslint-disable no-unused-vars */ + // See https://github.com/eslint/eslint/issues/6125 + var name; + + for ( name in obj ) { + return false; + } + return true; + }, + + type: function( obj ) { + if ( obj == null ) { + return obj + ""; + } + + // Support: Android <=2.3 only (functionish RegExp) + return typeof obj === "object" || typeof obj === "function" ? + class2type[ toString.call( obj ) ] || "object" : + typeof obj; + }, + + // Evaluates a script in a global context + globalEval: function( code ) { + DOMEval( code ); + }, + + // Convert dashed to camelCase; used by the css and data modules + // Support: IE <=9 - 11, Edge 12 - 13 + // Microsoft forgot to hump their vendor prefix (#9572) + camelCase: function( string ) { + return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); + }, + + each: function( obj, callback ) { + var length, i = 0; + + if ( isArrayLike( obj ) ) { + length = obj.length; + for ( ; i < length; i++ ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } else { + for ( i in obj ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } + + return obj; + }, + + // Support: Android <=4.0 only + trim: function( text ) { + return text == null ? + "" : + ( text + "" ).replace( rtrim, "" ); + }, + + // results is for internal usage only + makeArray: function( arr, results ) { + var ret = results || []; + + if ( arr != null ) { + if ( isArrayLike( Object( arr ) ) ) { + jQuery.merge( ret, + typeof arr === "string" ? + [ arr ] : arr + ); + } else { + push.call( ret, arr ); + } + } + + return ret; + }, + + inArray: function( elem, arr, i ) { + return arr == null ? -1 : indexOf.call( arr, elem, i ); + }, + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + merge: function( first, second ) { + var len = +second.length, + j = 0, + i = first.length; + + for ( ; j < len; j++ ) { + first[ i++ ] = second[ j ]; + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, invert ) { + var callbackInverse, + matches = [], + i = 0, + length = elems.length, + callbackExpect = !invert; + + // Go through the array, only saving the items + // that pass the validator function + for ( ; i < length; i++ ) { + callbackInverse = !callback( elems[ i ], i ); + if ( callbackInverse !== callbackExpect ) { + matches.push( elems[ i ] ); + } + } + + return matches; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var length, value, + i = 0, + ret = []; + + // Go through the array, translating each of the items to their new values + if ( isArrayLike( elems ) ) { + length = elems.length; + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + + // Go through every key on the object, + } else { + for ( i in elems ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + } + + // Flatten any nested arrays + return concat.apply( [], ret ); + }, + + // A global GUID counter for objects + guid: 1, + + // Bind a function to a context, optionally partially applying any + // arguments. + proxy: function( fn, context ) { + var tmp, args, proxy; + + if ( typeof context === "string" ) { + tmp = fn[ context ]; + context = fn; + fn = tmp; + } + + // Quick check to determine if target is callable, in the spec + // this throws a TypeError, but we will just return undefined. + if ( !jQuery.isFunction( fn ) ) { + return undefined; + } + + // Simulated bind + args = slice.call( arguments, 2 ); + proxy = function() { + return fn.apply( context || this, args.concat( slice.call( arguments ) ) ); + }; + + // Set the guid of unique handler to the same of original handler, so it can be removed + proxy.guid = fn.guid = fn.guid || jQuery.guid++; + + return proxy; + }, + + now: Date.now, + + // jQuery.support is not used in Core but other projects attach their + // properties to it so it needs to exist. + support: support +} ); + +if ( typeof Symbol === "function" ) { + jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ]; +} + +// Populate the class2type map +jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), +function( i, name ) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); +} ); + +function isArrayLike( obj ) { + + // Support: real iOS 8.2 only (not reproducible in simulator) + // `in` check used to prevent JIT error (gh-2145) + // hasOwn isn't used here due to false negatives + // regarding Nodelist length in IE + var length = !!obj && "length" in obj && obj.length, + type = jQuery.type( obj ); + + if ( type === "function" || jQuery.isWindow( obj ) ) { + return false; + } + + return type === "array" || length === 0 || + typeof length === "number" && length > 0 && ( length - 1 ) in obj; +} +var Sizzle = +/*! + * Sizzle CSS Selector Engine v2.3.3 + * https://sizzlejs.com/ + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license + * http://jquery.org/license + * + * Date: 2016-08-08 + */ +(function( window ) { + +var i, + support, + Expr, + getText, + isXML, + tokenize, + compile, + select, + outermostContext, + sortInput, + hasDuplicate, + + // Local document vars + setDocument, + document, + docElem, + documentIsHTML, + rbuggyQSA, + rbuggyMatches, + matches, + contains, + + // Instance-specific data + expando = "sizzle" + 1 * new Date(), + preferredDoc = window.document, + dirruns = 0, + done = 0, + classCache = createCache(), + tokenCache = createCache(), + compilerCache = createCache(), + sortOrder = function( a, b ) { + if ( a === b ) { + hasDuplicate = true; + } + return 0; + }, + + // Instance methods + hasOwn = ({}).hasOwnProperty, + arr = [], + pop = arr.pop, + push_native = arr.push, + push = arr.push, + slice = arr.slice, + // Use a stripped-down indexOf as it's faster than native + // https://jsperf.com/thor-indexof-vs-for/5 + indexOf = function( list, elem ) { + var i = 0, + len = list.length; + for ( ; i < len; i++ ) { + if ( list[i] === elem ) { + return i; + } + } + return -1; + }, + + booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped", + + // Regular expressions + + // http://www.w3.org/TR/css3-selectors/#whitespace + whitespace = "[\\x20\\t\\r\\n\\f]", + + // http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier + identifier = "(?:\\\\.|[\\w-]|[^\0-\\xa0])+", + + // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors + attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + + // Operator (capture 2) + "*([*^$|!~]?=)" + whitespace + + // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]" + "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace + + "*\\]", + + pseudos = ":(" + identifier + ")(?:\\((" + + // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: + // 1. quoted (capture 3; capture 4 or capture 5) + "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + + // 2. simple (capture 6) + "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + + // 3. anything else (capture 2) + ".*" + + ")\\)|)", + + // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter + rwhitespace = new RegExp( whitespace + "+", "g" ), + rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ), + + rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), + rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ), + + rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ), + + rpseudo = new RegExp( pseudos ), + ridentifier = new RegExp( "^" + identifier + "$" ), + + matchExpr = { + "ID": new RegExp( "^#(" + identifier + ")" ), + "CLASS": new RegExp( "^\\.(" + identifier + ")" ), + "TAG": new RegExp( "^(" + identifier + "|[*])" ), + "ATTR": new RegExp( "^" + attributes ), + "PSEUDO": new RegExp( "^" + pseudos ), + "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace + + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), + "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), + // For use in libraries implementing .is() + // We use this for POS matching in `select` + "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + + whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) + }, + + rinputs = /^(?:input|select|textarea|button)$/i, + rheader = /^h\d$/i, + + rnative = /^[^{]+\{\s*\[native \w/, + + // Easily-parseable/retrievable ID or TAG or CLASS selectors + rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, + + rsibling = /[+~]/, + + // CSS escapes + // http://www.w3.org/TR/CSS21/syndata.html#escaped-characters + runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ), + funescape = function( _, escaped, escapedWhitespace ) { + var high = "0x" + escaped - 0x10000; + // NaN means non-codepoint + // Support: Firefox<24 + // Workaround erroneous numeric interpretation of +"0x" + return high !== high || escapedWhitespace ? + escaped : + high < 0 ? + // BMP codepoint + String.fromCharCode( high + 0x10000 ) : + // Supplemental Plane codepoint (surrogate pair) + String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); + }, + + // CSS string/identifier serialization + // https://drafts.csswg.org/cssom/#common-serializing-idioms + rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g, + fcssescape = function( ch, asCodePoint ) { + if ( asCodePoint ) { + + // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER + if ( ch === "\0" ) { + return "\uFFFD"; + } + + // Control characters and (dependent upon position) numbers get escaped as code points + return ch.slice( 0, -1 ) + "\\" + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " "; + } + + // Other potentially-special ASCII characters get backslash-escaped + return "\\" + ch; + }, + + // Used for iframes + // See setDocument() + // Removing the function wrapper causes a "Permission Denied" + // error in IE + unloadHandler = function() { + setDocument(); + }, + + disabledAncestor = addCombinator( + function( elem ) { + return elem.disabled === true && ("form" in elem || "label" in elem); + }, + { dir: "parentNode", next: "legend" } + ); + +// Optimize for push.apply( _, NodeList ) +try { + push.apply( + (arr = slice.call( preferredDoc.childNodes )), + preferredDoc.childNodes + ); + // Support: Android<4.0 + // Detect silently failing push.apply + arr[ preferredDoc.childNodes.length ].nodeType; +} catch ( e ) { + push = { apply: arr.length ? + + // Leverage slice if possible + function( target, els ) { + push_native.apply( target, slice.call(els) ); + } : + + // Support: IE<9 + // Otherwise append directly + function( target, els ) { + var j = target.length, + i = 0; + // Can't trust NodeList.length + while ( (target[j++] = els[i++]) ) {} + target.length = j - 1; + } + }; +} + +function Sizzle( selector, context, results, seed ) { + var m, i, elem, nid, match, groups, newSelector, + newContext = context && context.ownerDocument, + + // nodeType defaults to 9, since context defaults to document + nodeType = context ? context.nodeType : 9; + + results = results || []; + + // Return early from calls with invalid selector or context + if ( typeof selector !== "string" || !selector || + nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) { + + return results; + } + + // Try to shortcut find operations (as opposed to filters) in HTML documents + if ( !seed ) { + + if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) { + setDocument( context ); + } + context = context || document; + + if ( documentIsHTML ) { + + // If the selector is sufficiently simple, try using a "get*By*" DOM method + // (excepting DocumentFragment context, where the methods don't exist) + if ( nodeType !== 11 && (match = rquickExpr.exec( selector )) ) { + + // ID selector + if ( (m = match[1]) ) { + + // Document context + if ( nodeType === 9 ) { + if ( (elem = context.getElementById( m )) ) { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( elem.id === m ) { + results.push( elem ); + return results; + } + } else { + return results; + } + + // Element context + } else { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( newContext && (elem = newContext.getElementById( m )) && + contains( context, elem ) && + elem.id === m ) { + + results.push( elem ); + return results; + } + } + + // Type selector + } else if ( match[2] ) { + push.apply( results, context.getElementsByTagName( selector ) ); + return results; + + // Class selector + } else if ( (m = match[3]) && support.getElementsByClassName && + context.getElementsByClassName ) { + + push.apply( results, context.getElementsByClassName( m ) ); + return results; + } + } + + // Take advantage of querySelectorAll + if ( support.qsa && + !compilerCache[ selector + " " ] && + (!rbuggyQSA || !rbuggyQSA.test( selector )) ) { + + if ( nodeType !== 1 ) { + newContext = context; + newSelector = selector; + + // qSA looks outside Element context, which is not what we want + // Thanks to Andrew Dupont for this workaround technique + // Support: IE <=8 + // Exclude object elements + } else if ( context.nodeName.toLowerCase() !== "object" ) { + + // Capture the context ID, setting it first if necessary + if ( (nid = context.getAttribute( "id" )) ) { + nid = nid.replace( rcssescape, fcssescape ); + } else { + context.setAttribute( "id", (nid = expando) ); + } + + // Prefix every selector in the list + groups = tokenize( selector ); + i = groups.length; + while ( i-- ) { + groups[i] = "#" + nid + " " + toSelector( groups[i] ); + } + newSelector = groups.join( "," ); + + // Expand context for sibling selectors + newContext = rsibling.test( selector ) && testContext( context.parentNode ) || + context; + } + + if ( newSelector ) { + try { + push.apply( results, + newContext.querySelectorAll( newSelector ) + ); + return results; + } catch ( qsaError ) { + } finally { + if ( nid === expando ) { + context.removeAttribute( "id" ); + } + } + } + } + } + } + + // All others + return select( selector.replace( rtrim, "$1" ), context, results, seed ); +} + +/** + * Create key-value caches of limited size + * @returns {function(string, object)} Returns the Object data after storing it on itself with + * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) + * deleting the oldest entry + */ +function createCache() { + var keys = []; + + function cache( key, value ) { + // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) + if ( keys.push( key + " " ) > Expr.cacheLength ) { + // Only keep the most recent entries + delete cache[ keys.shift() ]; + } + return (cache[ key + " " ] = value); + } + return cache; +} + +/** + * Mark a function for special use by Sizzle + * @param {Function} fn The function to mark + */ +function markFunction( fn ) { + fn[ expando ] = true; + return fn; +} + +/** + * Support testing using an element + * @param {Function} fn Passed the created element and returns a boolean result + */ +function assert( fn ) { + var el = document.createElement("fieldset"); + + try { + return !!fn( el ); + } catch (e) { + return false; + } finally { + // Remove from its parent by default + if ( el.parentNode ) { + el.parentNode.removeChild( el ); + } + // release memory in IE + el = null; + } +} + +/** + * Adds the same handler for all of the specified attrs + * @param {String} attrs Pipe-separated list of attributes + * @param {Function} handler The method that will be applied + */ +function addHandle( attrs, handler ) { + var arr = attrs.split("|"), + i = arr.length; + + while ( i-- ) { + Expr.attrHandle[ arr[i] ] = handler; + } +} + +/** + * Checks document order of two siblings + * @param {Element} a + * @param {Element} b + * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b + */ +function siblingCheck( a, b ) { + var cur = b && a, + diff = cur && a.nodeType === 1 && b.nodeType === 1 && + a.sourceIndex - b.sourceIndex; + + // Use IE sourceIndex if available on both nodes + if ( diff ) { + return diff; + } + + // Check if b follows a + if ( cur ) { + while ( (cur = cur.nextSibling) ) { + if ( cur === b ) { + return -1; + } + } + } + + return a ? 1 : -1; +} + +/** + * Returns a function to use in pseudos for input types + * @param {String} type + */ +function createInputPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for buttons + * @param {String} type + */ +function createButtonPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return (name === "input" || name === "button") && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for :enabled/:disabled + * @param {Boolean} disabled true for :disabled; false for :enabled + */ +function createDisabledPseudo( disabled ) { + + // Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable + return function( elem ) { + + // Only certain elements can match :enabled or :disabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled + if ( "form" in elem ) { + + // Check for inherited disabledness on relevant non-disabled elements: + // * listed form-associated elements in a disabled fieldset + // https://html.spec.whatwg.org/multipage/forms.html#category-listed + // https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled + // * option elements in a disabled optgroup + // https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled + // All such elements have a "form" property. + if ( elem.parentNode && elem.disabled === false ) { + + // Option elements defer to a parent optgroup if present + if ( "label" in elem ) { + if ( "label" in elem.parentNode ) { + return elem.parentNode.disabled === disabled; + } else { + return elem.disabled === disabled; + } + } + + // Support: IE 6 - 11 + // Use the isDisabled shortcut property to check for disabled fieldset ancestors + return elem.isDisabled === disabled || + + // Where there is no isDisabled, check manually + /* jshint -W018 */ + elem.isDisabled !== !disabled && + disabledAncestor( elem ) === disabled; + } + + return elem.disabled === disabled; + + // Try to winnow out elements that can't be disabled before trusting the disabled property. + // Some victims get caught in our net (label, legend, menu, track), but it shouldn't + // even exist on them, let alone have a boolean value. + } else if ( "label" in elem ) { + return elem.disabled === disabled; + } + + // Remaining elements are neither :enabled nor :disabled + return false; + }; +} + +/** + * Returns a function to use in pseudos for positionals + * @param {Function} fn + */ +function createPositionalPseudo( fn ) { + return markFunction(function( argument ) { + argument = +argument; + return markFunction(function( seed, matches ) { + var j, + matchIndexes = fn( [], seed.length, argument ), + i = matchIndexes.length; + + // Match elements found at the specified indexes + while ( i-- ) { + if ( seed[ (j = matchIndexes[i]) ] ) { + seed[j] = !(matches[j] = seed[j]); + } + } + }); + }); +} + +/** + * Checks a node for validity as a Sizzle context + * @param {Element|Object=} context + * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value + */ +function testContext( context ) { + return context && typeof context.getElementsByTagName !== "undefined" && context; +} + +// Expose support vars for convenience +support = Sizzle.support = {}; + +/** + * Detects XML nodes + * @param {Element|Object} elem An element or a document + * @returns {Boolean} True iff elem is a non-HTML XML node + */ +isXML = Sizzle.isXML = function( elem ) { + // documentElement is verified for cases where it doesn't yet exist + // (such as loading iframes in IE - #4833) + var documentElement = elem && (elem.ownerDocument || elem).documentElement; + return documentElement ? documentElement.nodeName !== "HTML" : false; +}; + +/** + * Sets document-related variables once based on the current document + * @param {Element|Object} [doc] An element or document object to use to set the document + * @returns {Object} Returns the current document + */ +setDocument = Sizzle.setDocument = function( node ) { + var hasCompare, subWindow, + doc = node ? node.ownerDocument || node : preferredDoc; + + // Return early if doc is invalid or already selected + if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) { + return document; + } + + // Update global variables + document = doc; + docElem = document.documentElement; + documentIsHTML = !isXML( document ); + + // Support: IE 9-11, Edge + // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936) + if ( preferredDoc !== document && + (subWindow = document.defaultView) && subWindow.top !== subWindow ) { + + // Support: IE 11, Edge + if ( subWindow.addEventListener ) { + subWindow.addEventListener( "unload", unloadHandler, false ); + + // Support: IE 9 - 10 only + } else if ( subWindow.attachEvent ) { + subWindow.attachEvent( "onunload", unloadHandler ); + } + } + + /* Attributes + ---------------------------------------------------------------------- */ + + // Support: IE<8 + // Verify that getAttribute really returns attributes and not properties + // (excepting IE8 booleans) + support.attributes = assert(function( el ) { + el.className = "i"; + return !el.getAttribute("className"); + }); + + /* getElement(s)By* + ---------------------------------------------------------------------- */ + + // Check if getElementsByTagName("*") returns only elements + support.getElementsByTagName = assert(function( el ) { + el.appendChild( document.createComment("") ); + return !el.getElementsByTagName("*").length; + }); + + // Support: IE<9 + support.getElementsByClassName = rnative.test( document.getElementsByClassName ); + + // Support: IE<10 + // Check if getElementById returns elements by name + // The broken getElementById methods don't pick up programmatically-set names, + // so use a roundabout getElementsByName test + support.getById = assert(function( el ) { + docElem.appendChild( el ).id = expando; + return !document.getElementsByName || !document.getElementsByName( expando ).length; + }); + + // ID filter and find + if ( support.getById ) { + Expr.filter["ID"] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + return elem.getAttribute("id") === attrId; + }; + }; + Expr.find["ID"] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var elem = context.getElementById( id ); + return elem ? [ elem ] : []; + } + }; + } else { + Expr.filter["ID"] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + var node = typeof elem.getAttributeNode !== "undefined" && + elem.getAttributeNode("id"); + return node && node.value === attrId; + }; + }; + + // Support: IE 6 - 7 only + // getElementById is not reliable as a find shortcut + Expr.find["ID"] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var node, i, elems, + elem = context.getElementById( id ); + + if ( elem ) { + + // Verify the id attribute + node = elem.getAttributeNode("id"); + if ( node && node.value === id ) { + return [ elem ]; + } + + // Fall back on getElementsByName + elems = context.getElementsByName( id ); + i = 0; + while ( (elem = elems[i++]) ) { + node = elem.getAttributeNode("id"); + if ( node && node.value === id ) { + return [ elem ]; + } + } + } + + return []; + } + }; + } + + // Tag + Expr.find["TAG"] = support.getElementsByTagName ? + function( tag, context ) { + if ( typeof context.getElementsByTagName !== "undefined" ) { + return context.getElementsByTagName( tag ); + + // DocumentFragment nodes don't have gEBTN + } else if ( support.qsa ) { + return context.querySelectorAll( tag ); + } + } : + + function( tag, context ) { + var elem, + tmp = [], + i = 0, + // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too + results = context.getElementsByTagName( tag ); + + // Filter out possible comments + if ( tag === "*" ) { + while ( (elem = results[i++]) ) { + if ( elem.nodeType === 1 ) { + tmp.push( elem ); + } + } + + return tmp; + } + return results; + }; + + // Class + Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) { + if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) { + return context.getElementsByClassName( className ); + } + }; + + /* QSA/matchesSelector + ---------------------------------------------------------------------- */ + + // QSA and matchesSelector support + + // matchesSelector(:active) reports false when true (IE9/Opera 11.5) + rbuggyMatches = []; + + // qSa(:focus) reports false when true (Chrome 21) + // We allow this because of a bug in IE8/9 that throws an error + // whenever `document.activeElement` is accessed on an iframe + // So, we allow :focus to pass through QSA all the time to avoid the IE error + // See https://bugs.jquery.com/ticket/13378 + rbuggyQSA = []; + + if ( (support.qsa = rnative.test( document.querySelectorAll )) ) { + // Build QSA regex + // Regex strategy adopted from Diego Perini + assert(function( el ) { + // Select is set to empty string on purpose + // This is to test IE's treatment of not explicitly + // setting a boolean content attribute, + // since its presence should be enough + // https://bugs.jquery.com/ticket/12359 + docElem.appendChild( el ).innerHTML = "" + + ""; + + // Support: IE8, Opera 11-12.16 + // Nothing should be selected when empty strings follow ^= or $= or *= + // The test attribute must be unknown in Opera but "safe" for WinRT + // https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section + if ( el.querySelectorAll("[msallowcapture^='']").length ) { + rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); + } + + // Support: IE8 + // Boolean attributes and "value" are not treated correctly + if ( !el.querySelectorAll("[selected]").length ) { + rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); + } + + // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+ + if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) { + rbuggyQSA.push("~="); + } + + // Webkit/Opera - :checked should return selected option elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + // IE8 throws error here and will not see later tests + if ( !el.querySelectorAll(":checked").length ) { + rbuggyQSA.push(":checked"); + } + + // Support: Safari 8+, iOS 8+ + // https://bugs.webkit.org/show_bug.cgi?id=136851 + // In-page `selector#id sibling-combinator selector` fails + if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) { + rbuggyQSA.push(".#.+[+~]"); + } + }); + + assert(function( el ) { + el.innerHTML = "" + + ""; + + // Support: Windows 8 Native Apps + // The type and name attributes are restricted during .innerHTML assignment + var input = document.createElement("input"); + input.setAttribute( "type", "hidden" ); + el.appendChild( input ).setAttribute( "name", "D" ); + + // Support: IE8 + // Enforce case-sensitivity of name attribute + if ( el.querySelectorAll("[name=d]").length ) { + rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" ); + } + + // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) + // IE8 throws error here and will not see later tests + if ( el.querySelectorAll(":enabled").length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Support: IE9-11+ + // IE's :disabled selector does not pick up the children of disabled fieldsets + docElem.appendChild( el ).disabled = true; + if ( el.querySelectorAll(":disabled").length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Opera 10-11 does not throw on post-comma invalid pseudos + el.querySelectorAll("*,:x"); + rbuggyQSA.push(",.*:"); + }); + } + + if ( (support.matchesSelector = rnative.test( (matches = docElem.matches || + docElem.webkitMatchesSelector || + docElem.mozMatchesSelector || + docElem.oMatchesSelector || + docElem.msMatchesSelector) )) ) { + + assert(function( el ) { + // Check to see if it's possible to do matchesSelector + // on a disconnected node (IE 9) + support.disconnectedMatch = matches.call( el, "*" ); + + // This should fail with an exception + // Gecko does not error, returns false instead + matches.call( el, "[s!='']:x" ); + rbuggyMatches.push( "!=", pseudos ); + }); + } + + rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") ); + rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") ); + + /* Contains + ---------------------------------------------------------------------- */ + hasCompare = rnative.test( docElem.compareDocumentPosition ); + + // Element contains another + // Purposefully self-exclusive + // As in, an element does not contain itself + contains = hasCompare || rnative.test( docElem.contains ) ? + function( a, b ) { + var adown = a.nodeType === 9 ? a.documentElement : a, + bup = b && b.parentNode; + return a === bup || !!( bup && bup.nodeType === 1 && ( + adown.contains ? + adown.contains( bup ) : + a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 + )); + } : + function( a, b ) { + if ( b ) { + while ( (b = b.parentNode) ) { + if ( b === a ) { + return true; + } + } + } + return false; + }; + + /* Sorting + ---------------------------------------------------------------------- */ + + // Document order sorting + sortOrder = hasCompare ? + function( a, b ) { + + // Flag for duplicate removal + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + // Sort on method existence if only one input has compareDocumentPosition + var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; + if ( compare ) { + return compare; + } + + // Calculate position if both inputs belong to the same document + compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ? + a.compareDocumentPosition( b ) : + + // Otherwise we know they are disconnected + 1; + + // Disconnected nodes + if ( compare & 1 || + (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) { + + // Choose the first element that is related to our preferred document + if ( a === document || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) { + return -1; + } + if ( b === document || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) { + return 1; + } + + // Maintain original order + return sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + } + + return compare & 4 ? -1 : 1; + } : + function( a, b ) { + // Exit early if the nodes are identical + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + var cur, + i = 0, + aup = a.parentNode, + bup = b.parentNode, + ap = [ a ], + bp = [ b ]; + + // Parentless nodes are either documents or disconnected + if ( !aup || !bup ) { + return a === document ? -1 : + b === document ? 1 : + aup ? -1 : + bup ? 1 : + sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + + // If the nodes are siblings, we can do a quick check + } else if ( aup === bup ) { + return siblingCheck( a, b ); + } + + // Otherwise we need full lists of their ancestors for comparison + cur = a; + while ( (cur = cur.parentNode) ) { + ap.unshift( cur ); + } + cur = b; + while ( (cur = cur.parentNode) ) { + bp.unshift( cur ); + } + + // Walk down the tree looking for a discrepancy + while ( ap[i] === bp[i] ) { + i++; + } + + return i ? + // Do a sibling check if the nodes have a common ancestor + siblingCheck( ap[i], bp[i] ) : + + // Otherwise nodes in our document sort first + ap[i] === preferredDoc ? -1 : + bp[i] === preferredDoc ? 1 : + 0; + }; + + return document; +}; + +Sizzle.matches = function( expr, elements ) { + return Sizzle( expr, null, null, elements ); +}; + +Sizzle.matchesSelector = function( elem, expr ) { + // Set document vars if needed + if ( ( elem.ownerDocument || elem ) !== document ) { + setDocument( elem ); + } + + // Make sure that attribute selectors are quoted + expr = expr.replace( rattributeQuotes, "='$1']" ); + + if ( support.matchesSelector && documentIsHTML && + !compilerCache[ expr + " " ] && + ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && + ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { + + try { + var ret = matches.call( elem, expr ); + + // IE 9's matchesSelector returns false on disconnected nodes + if ( ret || support.disconnectedMatch || + // As well, disconnected nodes are said to be in a document + // fragment in IE 9 + elem.document && elem.document.nodeType !== 11 ) { + return ret; + } + } catch (e) {} + } + + return Sizzle( expr, document, null, [ elem ] ).length > 0; +}; + +Sizzle.contains = function( context, elem ) { + // Set document vars if needed + if ( ( context.ownerDocument || context ) !== document ) { + setDocument( context ); + } + return contains( context, elem ); +}; + +Sizzle.attr = function( elem, name ) { + // Set document vars if needed + if ( ( elem.ownerDocument || elem ) !== document ) { + setDocument( elem ); + } + + var fn = Expr.attrHandle[ name.toLowerCase() ], + // Don't get fooled by Object.prototype properties (jQuery #13807) + val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? + fn( elem, name, !documentIsHTML ) : + undefined; + + return val !== undefined ? + val : + support.attributes || !documentIsHTML ? + elem.getAttribute( name ) : + (val = elem.getAttributeNode(name)) && val.specified ? + val.value : + null; +}; + +Sizzle.escape = function( sel ) { + return (sel + "").replace( rcssescape, fcssescape ); +}; + +Sizzle.error = function( msg ) { + throw new Error( "Syntax error, unrecognized expression: " + msg ); +}; + +/** + * Document sorting and removing duplicates + * @param {ArrayLike} results + */ +Sizzle.uniqueSort = function( results ) { + var elem, + duplicates = [], + j = 0, + i = 0; + + // Unless we *know* we can detect duplicates, assume their presence + hasDuplicate = !support.detectDuplicates; + sortInput = !support.sortStable && results.slice( 0 ); + results.sort( sortOrder ); + + if ( hasDuplicate ) { + while ( (elem = results[i++]) ) { + if ( elem === results[ i ] ) { + j = duplicates.push( i ); + } + } + while ( j-- ) { + results.splice( duplicates[ j ], 1 ); + } + } + + // Clear input after sorting to release objects + // See https://github.com/jquery/sizzle/pull/225 + sortInput = null; + + return results; +}; + +/** + * Utility function for retrieving the text value of an array of DOM nodes + * @param {Array|Element} elem + */ +getText = Sizzle.getText = function( elem ) { + var node, + ret = "", + i = 0, + nodeType = elem.nodeType; + + if ( !nodeType ) { + // If no nodeType, this is expected to be an array + while ( (node = elem[i++]) ) { + // Do not traverse comment nodes + ret += getText( node ); + } + } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { + // Use textContent for elements + // innerText usage removed for consistency of new lines (jQuery #11153) + if ( typeof elem.textContent === "string" ) { + return elem.textContent; + } else { + // Traverse its children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + ret += getText( elem ); + } + } + } else if ( nodeType === 3 || nodeType === 4 ) { + return elem.nodeValue; + } + // Do not include comment or processing instruction nodes + + return ret; +}; + +Expr = Sizzle.selectors = { + + // Can be adjusted by the user + cacheLength: 50, + + createPseudo: markFunction, + + match: matchExpr, + + attrHandle: {}, + + find: {}, + + relative: { + ">": { dir: "parentNode", first: true }, + " ": { dir: "parentNode" }, + "+": { dir: "previousSibling", first: true }, + "~": { dir: "previousSibling" } + }, + + preFilter: { + "ATTR": function( match ) { + match[1] = match[1].replace( runescape, funescape ); + + // Move the given value to match[3] whether quoted or unquoted + match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape ); + + if ( match[2] === "~=" ) { + match[3] = " " + match[3] + " "; + } + + return match.slice( 0, 4 ); + }, + + "CHILD": function( match ) { + /* matches from matchExpr["CHILD"] + 1 type (only|nth|...) + 2 what (child|of-type) + 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) + 4 xn-component of xn+y argument ([+-]?\d*n|) + 5 sign of xn-component + 6 x of xn-component + 7 sign of y-component + 8 y of y-component + */ + match[1] = match[1].toLowerCase(); + + if ( match[1].slice( 0, 3 ) === "nth" ) { + // nth-* requires argument + if ( !match[3] ) { + Sizzle.error( match[0] ); + } + + // numeric x and y parameters for Expr.filter.CHILD + // remember that false/true cast respectively to 0/1 + match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) ); + match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" ); + + // other types prohibit arguments + } else if ( match[3] ) { + Sizzle.error( match[0] ); + } + + return match; + }, + + "PSEUDO": function( match ) { + var excess, + unquoted = !match[6] && match[2]; + + if ( matchExpr["CHILD"].test( match[0] ) ) { + return null; + } + + // Accept quoted arguments as-is + if ( match[3] ) { + match[2] = match[4] || match[5] || ""; + + // Strip excess characters from unquoted arguments + } else if ( unquoted && rpseudo.test( unquoted ) && + // Get excess from tokenize (recursively) + (excess = tokenize( unquoted, true )) && + // advance to the next closing parenthesis + (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) { + + // excess is a negative index + match[0] = match[0].slice( 0, excess ); + match[2] = unquoted.slice( 0, excess ); + } + + // Return only captures needed by the pseudo filter method (type and argument) + return match.slice( 0, 3 ); + } + }, + + filter: { + + "TAG": function( nodeNameSelector ) { + var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); + return nodeNameSelector === "*" ? + function() { return true; } : + function( elem ) { + return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; + }; + }, + + "CLASS": function( className ) { + var pattern = classCache[ className + " " ]; + + return pattern || + (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) && + classCache( className, function( elem ) { + return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== "undefined" && elem.getAttribute("class") || "" ); + }); + }, + + "ATTR": function( name, operator, check ) { + return function( elem ) { + var result = Sizzle.attr( elem, name ); + + if ( result == null ) { + return operator === "!="; + } + if ( !operator ) { + return true; + } + + result += ""; + + return operator === "=" ? result === check : + operator === "!=" ? result !== check : + operator === "^=" ? check && result.indexOf( check ) === 0 : + operator === "*=" ? check && result.indexOf( check ) > -1 : + operator === "$=" ? check && result.slice( -check.length ) === check : + operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 : + operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : + false; + }; + }, + + "CHILD": function( type, what, argument, first, last ) { + var simple = type.slice( 0, 3 ) !== "nth", + forward = type.slice( -4 ) !== "last", + ofType = what === "of-type"; + + return first === 1 && last === 0 ? + + // Shortcut for :nth-*(n) + function( elem ) { + return !!elem.parentNode; + } : + + function( elem, context, xml ) { + var cache, uniqueCache, outerCache, node, nodeIndex, start, + dir = simple !== forward ? "nextSibling" : "previousSibling", + parent = elem.parentNode, + name = ofType && elem.nodeName.toLowerCase(), + useCache = !xml && !ofType, + diff = false; + + if ( parent ) { + + // :(first|last|only)-(child|of-type) + if ( simple ) { + while ( dir ) { + node = elem; + while ( (node = node[ dir ]) ) { + if ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) { + + return false; + } + } + // Reverse direction for :only-* (if we haven't yet done so) + start = dir = type === "only" && !start && "nextSibling"; + } + return true; + } + + start = [ forward ? parent.firstChild : parent.lastChild ]; + + // non-xml :nth-child(...) stores cache data on `parent` + if ( forward && useCache ) { + + // Seek `elem` from a previously-cached index + + // ...in a gzip-friendly way + node = parent; + outerCache = node[ expando ] || (node[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + (outerCache[ node.uniqueID ] = {}); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex && cache[ 2 ]; + node = nodeIndex && parent.childNodes[ nodeIndex ]; + + while ( (node = ++nodeIndex && node && node[ dir ] || + + // Fallback to seeking `elem` from the start + (diff = nodeIndex = 0) || start.pop()) ) { + + // When found, cache indexes on `parent` and break + if ( node.nodeType === 1 && ++diff && node === elem ) { + uniqueCache[ type ] = [ dirruns, nodeIndex, diff ]; + break; + } + } + + } else { + // Use previously-cached element index if available + if ( useCache ) { + // ...in a gzip-friendly way + node = elem; + outerCache = node[ expando ] || (node[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + (outerCache[ node.uniqueID ] = {}); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex; + } + + // xml :nth-child(...) + // or :nth-last-child(...) or :nth(-last)?-of-type(...) + if ( diff === false ) { + // Use the same loop as above to seek `elem` from the start + while ( (node = ++nodeIndex && node && node[ dir ] || + (diff = nodeIndex = 0) || start.pop()) ) { + + if ( ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) && + ++diff ) { + + // Cache the index of each encountered element + if ( useCache ) { + outerCache = node[ expando ] || (node[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + (outerCache[ node.uniqueID ] = {}); + + uniqueCache[ type ] = [ dirruns, diff ]; + } + + if ( node === elem ) { + break; + } + } + } + } + } + + // Incorporate the offset, then check against cycle size + diff -= last; + return diff === first || ( diff % first === 0 && diff / first >= 0 ); + } + }; + }, + + "PSEUDO": function( pseudo, argument ) { + // pseudo-class names are case-insensitive + // http://www.w3.org/TR/selectors/#pseudo-classes + // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters + // Remember that setFilters inherits from pseudos + var args, + fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || + Sizzle.error( "unsupported pseudo: " + pseudo ); + + // The user may use createPseudo to indicate that + // arguments are needed to create the filter function + // just as Sizzle does + if ( fn[ expando ] ) { + return fn( argument ); + } + + // But maintain support for old signatures + if ( fn.length > 1 ) { + args = [ pseudo, pseudo, "", argument ]; + return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? + markFunction(function( seed, matches ) { + var idx, + matched = fn( seed, argument ), + i = matched.length; + while ( i-- ) { + idx = indexOf( seed, matched[i] ); + seed[ idx ] = !( matches[ idx ] = matched[i] ); + } + }) : + function( elem ) { + return fn( elem, 0, args ); + }; + } + + return fn; + } + }, + + pseudos: { + // Potentially complex pseudos + "not": markFunction(function( selector ) { + // Trim the selector passed to compile + // to avoid treating leading and trailing + // spaces as combinators + var input = [], + results = [], + matcher = compile( selector.replace( rtrim, "$1" ) ); + + return matcher[ expando ] ? + markFunction(function( seed, matches, context, xml ) { + var elem, + unmatched = matcher( seed, null, xml, [] ), + i = seed.length; + + // Match elements unmatched by `matcher` + while ( i-- ) { + if ( (elem = unmatched[i]) ) { + seed[i] = !(matches[i] = elem); + } + } + }) : + function( elem, context, xml ) { + input[0] = elem; + matcher( input, null, xml, results ); + // Don't keep the element (issue #299) + input[0] = null; + return !results.pop(); + }; + }), + + "has": markFunction(function( selector ) { + return function( elem ) { + return Sizzle( selector, elem ).length > 0; + }; + }), + + "contains": markFunction(function( text ) { + text = text.replace( runescape, funescape ); + return function( elem ) { + return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1; + }; + }), + + // "Whether an element is represented by a :lang() selector + // is based solely on the element's language value + // being equal to the identifier C, + // or beginning with the identifier C immediately followed by "-". + // The matching of C against the element's language value is performed case-insensitively. + // The identifier C does not have to be a valid language name." + // http://www.w3.org/TR/selectors/#lang-pseudo + "lang": markFunction( function( lang ) { + // lang value must be a valid identifier + if ( !ridentifier.test(lang || "") ) { + Sizzle.error( "unsupported lang: " + lang ); + } + lang = lang.replace( runescape, funescape ).toLowerCase(); + return function( elem ) { + var elemLang; + do { + if ( (elemLang = documentIsHTML ? + elem.lang : + elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) { + + elemLang = elemLang.toLowerCase(); + return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; + } + } while ( (elem = elem.parentNode) && elem.nodeType === 1 ); + return false; + }; + }), + + // Miscellaneous + "target": function( elem ) { + var hash = window.location && window.location.hash; + return hash && hash.slice( 1 ) === elem.id; + }, + + "root": function( elem ) { + return elem === docElem; + }, + + "focus": function( elem ) { + return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex); + }, + + // Boolean properties + "enabled": createDisabledPseudo( false ), + "disabled": createDisabledPseudo( true ), + + "checked": function( elem ) { + // In CSS3, :checked should return both checked and selected elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + var nodeName = elem.nodeName.toLowerCase(); + return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected); + }, + + "selected": function( elem ) { + // Accessing this property makes selected-by-default + // options in Safari work properly + if ( elem.parentNode ) { + elem.parentNode.selectedIndex; + } + + return elem.selected === true; + }, + + // Contents + "empty": function( elem ) { + // http://www.w3.org/TR/selectors/#empty-pseudo + // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), + // but not by others (comment: 8; processing instruction: 7; etc.) + // nodeType < 6 works because attributes (2) do not appear as children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + if ( elem.nodeType < 6 ) { + return false; + } + } + return true; + }, + + "parent": function( elem ) { + return !Expr.pseudos["empty"]( elem ); + }, + + // Element/input types + "header": function( elem ) { + return rheader.test( elem.nodeName ); + }, + + "input": function( elem ) { + return rinputs.test( elem.nodeName ); + }, + + "button": function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === "button" || name === "button"; + }, + + "text": function( elem ) { + var attr; + return elem.nodeName.toLowerCase() === "input" && + elem.type === "text" && + + // Support: IE<8 + // New HTML5 attribute values (e.g., "search") appear with elem.type === "text" + ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" ); + }, + + // Position-in-collection + "first": createPositionalPseudo(function() { + return [ 0 ]; + }), + + "last": createPositionalPseudo(function( matchIndexes, length ) { + return [ length - 1 ]; + }), + + "eq": createPositionalPseudo(function( matchIndexes, length, argument ) { + return [ argument < 0 ? argument + length : argument ]; + }), + + "even": createPositionalPseudo(function( matchIndexes, length ) { + var i = 0; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "odd": createPositionalPseudo(function( matchIndexes, length ) { + var i = 1; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "lt": createPositionalPseudo(function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; --i >= 0; ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "gt": createPositionalPseudo(function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; ++i < length; ) { + matchIndexes.push( i ); + } + return matchIndexes; + }) + } +}; + +Expr.pseudos["nth"] = Expr.pseudos["eq"]; + +// Add button/input type pseudos +for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { + Expr.pseudos[ i ] = createInputPseudo( i ); +} +for ( i in { submit: true, reset: true } ) { + Expr.pseudos[ i ] = createButtonPseudo( i ); +} + +// Easy API for creating new setFilters +function setFilters() {} +setFilters.prototype = Expr.filters = Expr.pseudos; +Expr.setFilters = new setFilters(); + +tokenize = Sizzle.tokenize = function( selector, parseOnly ) { + var matched, match, tokens, type, + soFar, groups, preFilters, + cached = tokenCache[ selector + " " ]; + + if ( cached ) { + return parseOnly ? 0 : cached.slice( 0 ); + } + + soFar = selector; + groups = []; + preFilters = Expr.preFilter; + + while ( soFar ) { + + // Comma and first run + if ( !matched || (match = rcomma.exec( soFar )) ) { + if ( match ) { + // Don't consume trailing commas as valid + soFar = soFar.slice( match[0].length ) || soFar; + } + groups.push( (tokens = []) ); + } + + matched = false; + + // Combinators + if ( (match = rcombinators.exec( soFar )) ) { + matched = match.shift(); + tokens.push({ + value: matched, + // Cast descendant combinators to space + type: match[0].replace( rtrim, " " ) + }); + soFar = soFar.slice( matched.length ); + } + + // Filters + for ( type in Expr.filter ) { + if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] || + (match = preFilters[ type ]( match ))) ) { + matched = match.shift(); + tokens.push({ + value: matched, + type: type, + matches: match + }); + soFar = soFar.slice( matched.length ); + } + } + + if ( !matched ) { + break; + } + } + + // Return the length of the invalid excess + // if we're just parsing + // Otherwise, throw an error or return tokens + return parseOnly ? + soFar.length : + soFar ? + Sizzle.error( selector ) : + // Cache the tokens + tokenCache( selector, groups ).slice( 0 ); +}; + +function toSelector( tokens ) { + var i = 0, + len = tokens.length, + selector = ""; + for ( ; i < len; i++ ) { + selector += tokens[i].value; + } + return selector; +} + +function addCombinator( matcher, combinator, base ) { + var dir = combinator.dir, + skip = combinator.next, + key = skip || dir, + checkNonElements = base && key === "parentNode", + doneName = done++; + + return combinator.first ? + // Check against closest ancestor/preceding element + function( elem, context, xml ) { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + return matcher( elem, context, xml ); + } + } + return false; + } : + + // Check against all ancestor/preceding elements + function( elem, context, xml ) { + var oldCache, uniqueCache, outerCache, + newCache = [ dirruns, doneName ]; + + // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching + if ( xml ) { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + if ( matcher( elem, context, xml ) ) { + return true; + } + } + } + } else { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + outerCache = elem[ expando ] || (elem[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ elem.uniqueID ] || (outerCache[ elem.uniqueID ] = {}); + + if ( skip && skip === elem.nodeName.toLowerCase() ) { + elem = elem[ dir ] || elem; + } else if ( (oldCache = uniqueCache[ key ]) && + oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) { + + // Assign to newCache so results back-propagate to previous elements + return (newCache[ 2 ] = oldCache[ 2 ]); + } else { + // Reuse newcache so results back-propagate to previous elements + uniqueCache[ key ] = newCache; + + // A match means we're done; a fail means we have to keep checking + if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) { + return true; + } + } + } + } + } + return false; + }; +} + +function elementMatcher( matchers ) { + return matchers.length > 1 ? + function( elem, context, xml ) { + var i = matchers.length; + while ( i-- ) { + if ( !matchers[i]( elem, context, xml ) ) { + return false; + } + } + return true; + } : + matchers[0]; +} + +function multipleContexts( selector, contexts, results ) { + var i = 0, + len = contexts.length; + for ( ; i < len; i++ ) { + Sizzle( selector, contexts[i], results ); + } + return results; +} + +function condense( unmatched, map, filter, context, xml ) { + var elem, + newUnmatched = [], + i = 0, + len = unmatched.length, + mapped = map != null; + + for ( ; i < len; i++ ) { + if ( (elem = unmatched[i]) ) { + if ( !filter || filter( elem, context, xml ) ) { + newUnmatched.push( elem ); + if ( mapped ) { + map.push( i ); + } + } + } + } + + return newUnmatched; +} + +function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { + if ( postFilter && !postFilter[ expando ] ) { + postFilter = setMatcher( postFilter ); + } + if ( postFinder && !postFinder[ expando ] ) { + postFinder = setMatcher( postFinder, postSelector ); + } + return markFunction(function( seed, results, context, xml ) { + var temp, i, elem, + preMap = [], + postMap = [], + preexisting = results.length, + + // Get initial elements from seed or context + elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ), + + // Prefilter to get matcher input, preserving a map for seed-results synchronization + matcherIn = preFilter && ( seed || !selector ) ? + condense( elems, preMap, preFilter, context, xml ) : + elems, + + matcherOut = matcher ? + // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, + postFinder || ( seed ? preFilter : preexisting || postFilter ) ? + + // ...intermediate processing is necessary + [] : + + // ...otherwise use results directly + results : + matcherIn; + + // Find primary matches + if ( matcher ) { + matcher( matcherIn, matcherOut, context, xml ); + } + + // Apply postFilter + if ( postFilter ) { + temp = condense( matcherOut, postMap ); + postFilter( temp, [], context, xml ); + + // Un-match failing elements by moving them back to matcherIn + i = temp.length; + while ( i-- ) { + if ( (elem = temp[i]) ) { + matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem); + } + } + } + + if ( seed ) { + if ( postFinder || preFilter ) { + if ( postFinder ) { + // Get the final matcherOut by condensing this intermediate into postFinder contexts + temp = []; + i = matcherOut.length; + while ( i-- ) { + if ( (elem = matcherOut[i]) ) { + // Restore matcherIn since elem is not yet a final match + temp.push( (matcherIn[i] = elem) ); + } + } + postFinder( null, (matcherOut = []), temp, xml ); + } + + // Move matched elements from seed to results to keep them synchronized + i = matcherOut.length; + while ( i-- ) { + if ( (elem = matcherOut[i]) && + (temp = postFinder ? indexOf( seed, elem ) : preMap[i]) > -1 ) { + + seed[temp] = !(results[temp] = elem); + } + } + } + + // Add elements to results, through postFinder if defined + } else { + matcherOut = condense( + matcherOut === results ? + matcherOut.splice( preexisting, matcherOut.length ) : + matcherOut + ); + if ( postFinder ) { + postFinder( null, results, matcherOut, xml ); + } else { + push.apply( results, matcherOut ); + } + } + }); +} + +function matcherFromTokens( tokens ) { + var checkContext, matcher, j, + len = tokens.length, + leadingRelative = Expr.relative[ tokens[0].type ], + implicitRelative = leadingRelative || Expr.relative[" "], + i = leadingRelative ? 1 : 0, + + // The foundational matcher ensures that elements are reachable from top-level context(s) + matchContext = addCombinator( function( elem ) { + return elem === checkContext; + }, implicitRelative, true ), + matchAnyContext = addCombinator( function( elem ) { + return indexOf( checkContext, elem ) > -1; + }, implicitRelative, true ), + matchers = [ function( elem, context, xml ) { + var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( + (checkContext = context).nodeType ? + matchContext( elem, context, xml ) : + matchAnyContext( elem, context, xml ) ); + // Avoid hanging onto element (issue #299) + checkContext = null; + return ret; + } ]; + + for ( ; i < len; i++ ) { + if ( (matcher = Expr.relative[ tokens[i].type ]) ) { + matchers = [ addCombinator(elementMatcher( matchers ), matcher) ]; + } else { + matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches ); + + // Return special upon seeing a positional matcher + if ( matcher[ expando ] ) { + // Find the next relative operator (if any) for proper handling + j = ++i; + for ( ; j < len; j++ ) { + if ( Expr.relative[ tokens[j].type ] ) { + break; + } + } + return setMatcher( + i > 1 && elementMatcher( matchers ), + i > 1 && toSelector( + // If the preceding token was a descendant combinator, insert an implicit any-element `*` + tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" }) + ).replace( rtrim, "$1" ), + matcher, + i < j && matcherFromTokens( tokens.slice( i, j ) ), + j < len && matcherFromTokens( (tokens = tokens.slice( j )) ), + j < len && toSelector( tokens ) + ); + } + matchers.push( matcher ); + } + } + + return elementMatcher( matchers ); +} + +function matcherFromGroupMatchers( elementMatchers, setMatchers ) { + var bySet = setMatchers.length > 0, + byElement = elementMatchers.length > 0, + superMatcher = function( seed, context, xml, results, outermost ) { + var elem, j, matcher, + matchedCount = 0, + i = "0", + unmatched = seed && [], + setMatched = [], + contextBackup = outermostContext, + // We must always have either seed elements or outermost context + elems = seed || byElement && Expr.find["TAG"]( "*", outermost ), + // Use integer dirruns iff this is the outermost matcher + dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1), + len = elems.length; + + if ( outermost ) { + outermostContext = context === document || context || outermost; + } + + // Add elements passing elementMatchers directly to results + // Support: IE<9, Safari + // Tolerate NodeList properties (IE: "length"; Safari: ) matching elements by id + for ( ; i !== len && (elem = elems[i]) != null; i++ ) { + if ( byElement && elem ) { + j = 0; + if ( !context && elem.ownerDocument !== document ) { + setDocument( elem ); + xml = !documentIsHTML; + } + while ( (matcher = elementMatchers[j++]) ) { + if ( matcher( elem, context || document, xml) ) { + results.push( elem ); + break; + } + } + if ( outermost ) { + dirruns = dirrunsUnique; + } + } + + // Track unmatched elements for set filters + if ( bySet ) { + // They will have gone through all possible matchers + if ( (elem = !matcher && elem) ) { + matchedCount--; + } + + // Lengthen the array for every element, matched or not + if ( seed ) { + unmatched.push( elem ); + } + } + } + + // `i` is now the count of elements visited above, and adding it to `matchedCount` + // makes the latter nonnegative. + matchedCount += i; + + // Apply set filters to unmatched elements + // NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount` + // equals `i`), unless we didn't visit _any_ elements in the above loop because we have + // no element matchers and no seed. + // Incrementing an initially-string "0" `i` allows `i` to remain a string only in that + // case, which will result in a "00" `matchedCount` that differs from `i` but is also + // numerically zero. + if ( bySet && i !== matchedCount ) { + j = 0; + while ( (matcher = setMatchers[j++]) ) { + matcher( unmatched, setMatched, context, xml ); + } + + if ( seed ) { + // Reintegrate element matches to eliminate the need for sorting + if ( matchedCount > 0 ) { + while ( i-- ) { + if ( !(unmatched[i] || setMatched[i]) ) { + setMatched[i] = pop.call( results ); + } + } + } + + // Discard index placeholder values to get only actual matches + setMatched = condense( setMatched ); + } + + // Add matches to results + push.apply( results, setMatched ); + + // Seedless set matches succeeding multiple successful matchers stipulate sorting + if ( outermost && !seed && setMatched.length > 0 && + ( matchedCount + setMatchers.length ) > 1 ) { + + Sizzle.uniqueSort( results ); + } + } + + // Override manipulation of globals by nested matchers + if ( outermost ) { + dirruns = dirrunsUnique; + outermostContext = contextBackup; + } + + return unmatched; + }; + + return bySet ? + markFunction( superMatcher ) : + superMatcher; +} + +compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { + var i, + setMatchers = [], + elementMatchers = [], + cached = compilerCache[ selector + " " ]; + + if ( !cached ) { + // Generate a function of recursive functions that can be used to check each element + if ( !match ) { + match = tokenize( selector ); + } + i = match.length; + while ( i-- ) { + cached = matcherFromTokens( match[i] ); + if ( cached[ expando ] ) { + setMatchers.push( cached ); + } else { + elementMatchers.push( cached ); + } + } + + // Cache the compiled function + cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) ); + + // Save selector and tokenization + cached.selector = selector; + } + return cached; +}; + +/** + * A low-level selection function that works with Sizzle's compiled + * selector functions + * @param {String|Function} selector A selector or a pre-compiled + * selector function built with Sizzle.compile + * @param {Element} context + * @param {Array} [results] + * @param {Array} [seed] A set of elements to match against + */ +select = Sizzle.select = function( selector, context, results, seed ) { + var i, tokens, token, type, find, + compiled = typeof selector === "function" && selector, + match = !seed && tokenize( (selector = compiled.selector || selector) ); + + results = results || []; + + // Try to minimize operations if there is only one selector in the list and no seed + // (the latter of which guarantees us context) + if ( match.length === 1 ) { + + // Reduce context if the leading compound selector is an ID + tokens = match[0] = match[0].slice( 0 ); + if ( tokens.length > 2 && (token = tokens[0]).type === "ID" && + context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[1].type ] ) { + + context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0]; + if ( !context ) { + return results; + + // Precompiled matchers will still verify ancestry, so step up a level + } else if ( compiled ) { + context = context.parentNode; + } + + selector = selector.slice( tokens.shift().value.length ); + } + + // Fetch a seed set for right-to-left matching + i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length; + while ( i-- ) { + token = tokens[i]; + + // Abort if we hit a combinator + if ( Expr.relative[ (type = token.type) ] ) { + break; + } + if ( (find = Expr.find[ type ]) ) { + // Search, expanding context for leading sibling combinators + if ( (seed = find( + token.matches[0].replace( runescape, funescape ), + rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context + )) ) { + + // If seed is empty or no tokens remain, we can return early + tokens.splice( i, 1 ); + selector = seed.length && toSelector( tokens ); + if ( !selector ) { + push.apply( results, seed ); + return results; + } + + break; + } + } + } + } + + // Compile and execute a filtering function if one is not provided + // Provide `match` to avoid retokenization if we modified the selector above + ( compiled || compile( selector, match ) )( + seed, + context, + !documentIsHTML, + results, + !context || rsibling.test( selector ) && testContext( context.parentNode ) || context + ); + return results; +}; + +// One-time assignments + +// Sort stability +support.sortStable = expando.split("").sort( sortOrder ).join("") === expando; + +// Support: Chrome 14-35+ +// Always assume duplicates if they aren't passed to the comparison function +support.detectDuplicates = !!hasDuplicate; + +// Initialize against the default document +setDocument(); + +// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27) +// Detached nodes confoundingly follow *each other* +support.sortDetached = assert(function( el ) { + // Should return 1, but returns 4 (following) + return el.compareDocumentPosition( document.createElement("fieldset") ) & 1; +}); + +// Support: IE<8 +// Prevent attribute/property "interpolation" +// https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx +if ( !assert(function( el ) { + el.innerHTML = ""; + return el.firstChild.getAttribute("href") === "#" ; +}) ) { + addHandle( "type|href|height|width", function( elem, name, isXML ) { + if ( !isXML ) { + return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 ); + } + }); +} + +// Support: IE<9 +// Use defaultValue in place of getAttribute("value") +if ( !support.attributes || !assert(function( el ) { + el.innerHTML = ""; + el.firstChild.setAttribute( "value", "" ); + return el.firstChild.getAttribute( "value" ) === ""; +}) ) { + addHandle( "value", function( elem, name, isXML ) { + if ( !isXML && elem.nodeName.toLowerCase() === "input" ) { + return elem.defaultValue; + } + }); +} + +// Support: IE<9 +// Use getAttributeNode to fetch booleans when getAttribute lies +if ( !assert(function( el ) { + return el.getAttribute("disabled") == null; +}) ) { + addHandle( booleans, function( elem, name, isXML ) { + var val; + if ( !isXML ) { + return elem[ name ] === true ? name.toLowerCase() : + (val = elem.getAttributeNode( name )) && val.specified ? + val.value : + null; + } + }); +} + +return Sizzle; + +})( window ); + + + +jQuery.find = Sizzle; +jQuery.expr = Sizzle.selectors; + +// Deprecated +jQuery.expr[ ":" ] = jQuery.expr.pseudos; +jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort; +jQuery.text = Sizzle.getText; +jQuery.isXMLDoc = Sizzle.isXML; +jQuery.contains = Sizzle.contains; +jQuery.escapeSelector = Sizzle.escape; + + + + +var dir = function( elem, dir, until ) { + var matched = [], + truncate = until !== undefined; + + while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) { + if ( elem.nodeType === 1 ) { + if ( truncate && jQuery( elem ).is( until ) ) { + break; + } + matched.push( elem ); + } + } + return matched; +}; + + +var siblings = function( n, elem ) { + var matched = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + matched.push( n ); + } + } + + return matched; +}; + + +var rneedsContext = jQuery.expr.match.needsContext; + + + +function nodeName( elem, name ) { + + return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); + +}; +var rsingleTag = ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i ); + + + +var risSimple = /^.[^:#\[\.,]*$/; + +// Implement the identical functionality for filter and not +function winnow( elements, qualifier, not ) { + if ( jQuery.isFunction( qualifier ) ) { + return jQuery.grep( elements, function( elem, i ) { + return !!qualifier.call( elem, i, elem ) !== not; + } ); + } + + // Single element + if ( qualifier.nodeType ) { + return jQuery.grep( elements, function( elem ) { + return ( elem === qualifier ) !== not; + } ); + } + + // Arraylike of elements (jQuery, arguments, Array) + if ( typeof qualifier !== "string" ) { + return jQuery.grep( elements, function( elem ) { + return ( indexOf.call( qualifier, elem ) > -1 ) !== not; + } ); + } + + // Simple selector that can be filtered directly, removing non-Elements + if ( risSimple.test( qualifier ) ) { + return jQuery.filter( qualifier, elements, not ); + } + + // Complex selector, compare the two sets, removing non-Elements + qualifier = jQuery.filter( qualifier, elements ); + return jQuery.grep( elements, function( elem ) { + return ( indexOf.call( qualifier, elem ) > -1 ) !== not && elem.nodeType === 1; + } ); +} + +jQuery.filter = function( expr, elems, not ) { + var elem = elems[ 0 ]; + + if ( not ) { + expr = ":not(" + expr + ")"; + } + + if ( elems.length === 1 && elem.nodeType === 1 ) { + return jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : []; + } + + return jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { + return elem.nodeType === 1; + } ) ); +}; + +jQuery.fn.extend( { + find: function( selector ) { + var i, ret, + len = this.length, + self = this; + + if ( typeof selector !== "string" ) { + return this.pushStack( jQuery( selector ).filter( function() { + for ( i = 0; i < len; i++ ) { + if ( jQuery.contains( self[ i ], this ) ) { + return true; + } + } + } ) ); + } + + ret = this.pushStack( [] ); + + for ( i = 0; i < len; i++ ) { + jQuery.find( selector, self[ i ], ret ); + } + + return len > 1 ? jQuery.uniqueSort( ret ) : ret; + }, + filter: function( selector ) { + return this.pushStack( winnow( this, selector || [], false ) ); + }, + not: function( selector ) { + return this.pushStack( winnow( this, selector || [], true ) ); + }, + is: function( selector ) { + return !!winnow( + this, + + // If this is a positional/relative selector, check membership in the returned set + // so $("p:first").is("p:last") won't return true for a doc with two "p". + typeof selector === "string" && rneedsContext.test( selector ) ? + jQuery( selector ) : + selector || [], + false + ).length; + } +} ); + + +// Initialize a jQuery object + + +// A central reference to the root jQuery(document) +var rootjQuery, + + // A simple way to check for HTML strings + // Prioritize #id over to avoid XSS via location.hash (#9521) + // Strict HTML recognition (#11290: must start with <) + // Shortcut simple #id case for speed + rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/, + + init = jQuery.fn.init = function( selector, context, root ) { + var match, elem; + + // HANDLE: $(""), $(null), $(undefined), $(false) + if ( !selector ) { + return this; + } + + // Method init() accepts an alternate rootjQuery + // so migrate can support jQuery.sub (gh-2101) + root = root || rootjQuery; + + // Handle HTML strings + if ( typeof selector === "string" ) { + if ( selector[ 0 ] === "<" && + selector[ selector.length - 1 ] === ">" && + selector.length >= 3 ) { + + // Assume that strings that start and end with <> are HTML and skip the regex check + match = [ null, selector, null ]; + + } else { + match = rquickExpr.exec( selector ); + } + + // Match html or make sure no context is specified for #id + if ( match && ( match[ 1 ] || !context ) ) { + + // HANDLE: $(html) -> $(array) + if ( match[ 1 ] ) { + context = context instanceof jQuery ? context[ 0 ] : context; + + // Option to run scripts is true for back-compat + // Intentionally let the error be thrown if parseHTML is not present + jQuery.merge( this, jQuery.parseHTML( + match[ 1 ], + context && context.nodeType ? context.ownerDocument || context : document, + true + ) ); + + // HANDLE: $(html, props) + if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) { + for ( match in context ) { + + // Properties of context are called as methods if possible + if ( jQuery.isFunction( this[ match ] ) ) { + this[ match ]( context[ match ] ); + + // ...and otherwise set as attributes + } else { + this.attr( match, context[ match ] ); + } + } + } + + return this; + + // HANDLE: $(#id) + } else { + elem = document.getElementById( match[ 2 ] ); + + if ( elem ) { + + // Inject the element directly into the jQuery object + this[ 0 ] = elem; + this.length = 1; + } + return this; + } + + // HANDLE: $(expr, $(...)) + } else if ( !context || context.jquery ) { + return ( context || root ).find( selector ); + + // HANDLE: $(expr, context) + // (which is just equivalent to: $(context).find(expr) + } else { + return this.constructor( context ).find( selector ); + } + + // HANDLE: $(DOMElement) + } else if ( selector.nodeType ) { + this[ 0 ] = selector; + this.length = 1; + return this; + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( jQuery.isFunction( selector ) ) { + return root.ready !== undefined ? + root.ready( selector ) : + + // Execute immediately if ready is not present + selector( jQuery ); + } + + return jQuery.makeArray( selector, this ); + }; + +// Give the init function the jQuery prototype for later instantiation +init.prototype = jQuery.fn; + +// Initialize central reference +rootjQuery = jQuery( document ); + + +var rparentsprev = /^(?:parents|prev(?:Until|All))/, + + // Methods guaranteed to produce a unique set when starting from a unique set + guaranteedUnique = { + children: true, + contents: true, + next: true, + prev: true + }; + +jQuery.fn.extend( { + has: function( target ) { + var targets = jQuery( target, this ), + l = targets.length; + + return this.filter( function() { + var i = 0; + for ( ; i < l; i++ ) { + if ( jQuery.contains( this, targets[ i ] ) ) { + return true; + } + } + } ); + }, + + closest: function( selectors, context ) { + var cur, + i = 0, + l = this.length, + matched = [], + targets = typeof selectors !== "string" && jQuery( selectors ); + + // Positional selectors never match, since there's no _selection_ context + if ( !rneedsContext.test( selectors ) ) { + for ( ; i < l; i++ ) { + for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) { + + // Always skip document fragments + if ( cur.nodeType < 11 && ( targets ? + targets.index( cur ) > -1 : + + // Don't pass non-elements to Sizzle + cur.nodeType === 1 && + jQuery.find.matchesSelector( cur, selectors ) ) ) { + + matched.push( cur ); + break; + } + } + } + } + + return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched ); + }, + + // Determine the position of an element within the set + index: function( elem ) { + + // No argument, return index in parent + if ( !elem ) { + return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1; + } + + // Index in selector + if ( typeof elem === "string" ) { + return indexOf.call( jQuery( elem ), this[ 0 ] ); + } + + // Locate the position of the desired element + return indexOf.call( this, + + // If it receives a jQuery object, the first element is used + elem.jquery ? elem[ 0 ] : elem + ); + }, + + add: function( selector, context ) { + return this.pushStack( + jQuery.uniqueSort( + jQuery.merge( this.get(), jQuery( selector, context ) ) + ) + ); + }, + + addBack: function( selector ) { + return this.add( selector == null ? + this.prevObject : this.prevObject.filter( selector ) + ); + } +} ); + +function sibling( cur, dir ) { + while ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {} + return cur; +} + +jQuery.each( { + parent: function( elem ) { + var parent = elem.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + parents: function( elem ) { + return dir( elem, "parentNode" ); + }, + parentsUntil: function( elem, i, until ) { + return dir( elem, "parentNode", until ); + }, + next: function( elem ) { + return sibling( elem, "nextSibling" ); + }, + prev: function( elem ) { + return sibling( elem, "previousSibling" ); + }, + nextAll: function( elem ) { + return dir( elem, "nextSibling" ); + }, + prevAll: function( elem ) { + return dir( elem, "previousSibling" ); + }, + nextUntil: function( elem, i, until ) { + return dir( elem, "nextSibling", until ); + }, + prevUntil: function( elem, i, until ) { + return dir( elem, "previousSibling", until ); + }, + siblings: function( elem ) { + return siblings( ( elem.parentNode || {} ).firstChild, elem ); + }, + children: function( elem ) { + return siblings( elem.firstChild ); + }, + contents: function( elem ) { + if ( nodeName( elem, "iframe" ) ) { + return elem.contentDocument; + } + + // Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only + // Treat the template element as a regular one in browsers that + // don't support it. + if ( nodeName( elem, "template" ) ) { + elem = elem.content || elem; + } + + return jQuery.merge( [], elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var matched = jQuery.map( this, fn, until ); + + if ( name.slice( -5 ) !== "Until" ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + matched = jQuery.filter( selector, matched ); + } + + if ( this.length > 1 ) { + + // Remove duplicates + if ( !guaranteedUnique[ name ] ) { + jQuery.uniqueSort( matched ); + } + + // Reverse order for parents* and prev-derivatives + if ( rparentsprev.test( name ) ) { + matched.reverse(); + } + } + + return this.pushStack( matched ); + }; +} ); +var rnothtmlwhite = ( /[^\x20\t\r\n\f]+/g ); + + + +// Convert String-formatted options into Object-formatted ones +function createOptions( options ) { + var object = {}; + jQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) { + object[ flag ] = true; + } ); + return object; +} + +/* + * Create a callback list using the following parameters: + * + * options: an optional list of space-separated options that will change how + * the callback list behaves or a more traditional option object + * + * By default a callback list will act like an event callback list and can be + * "fired" multiple times. + * + * Possible options: + * + * once: will ensure the callback list can only be fired once (like a Deferred) + * + * memory: will keep track of previous values and will call any callback added + * after the list has been fired right away with the latest "memorized" + * values (like a Deferred) + * + * unique: will ensure a callback can only be added once (no duplicate in the list) + * + * stopOnFalse: interrupt callings when a callback returns false + * + */ +jQuery.Callbacks = function( options ) { + + // Convert options from String-formatted to Object-formatted if needed + // (we check in cache first) + options = typeof options === "string" ? + createOptions( options ) : + jQuery.extend( {}, options ); + + var // Flag to know if list is currently firing + firing, + + // Last fire value for non-forgettable lists + memory, + + // Flag to know if list was already fired + fired, + + // Flag to prevent firing + locked, + + // Actual callback list + list = [], + + // Queue of execution data for repeatable lists + queue = [], + + // Index of currently firing callback (modified by add/remove as needed) + firingIndex = -1, + + // Fire callbacks + fire = function() { + + // Enforce single-firing + locked = locked || options.once; + + // Execute callbacks for all pending executions, + // respecting firingIndex overrides and runtime changes + fired = firing = true; + for ( ; queue.length; firingIndex = -1 ) { + memory = queue.shift(); + while ( ++firingIndex < list.length ) { + + // Run callback and check for early termination + if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false && + options.stopOnFalse ) { + + // Jump to end and forget the data so .add doesn't re-fire + firingIndex = list.length; + memory = false; + } + } + } + + // Forget the data if we're done with it + if ( !options.memory ) { + memory = false; + } + + firing = false; + + // Clean up if we're done firing for good + if ( locked ) { + + // Keep an empty list if we have data for future add calls + if ( memory ) { + list = []; + + // Otherwise, this object is spent + } else { + list = ""; + } + } + }, + + // Actual Callbacks object + self = { + + // Add a callback or a collection of callbacks to the list + add: function() { + if ( list ) { + + // If we have memory from a past run, we should fire after adding + if ( memory && !firing ) { + firingIndex = list.length - 1; + queue.push( memory ); + } + + ( function add( args ) { + jQuery.each( args, function( _, arg ) { + if ( jQuery.isFunction( arg ) ) { + if ( !options.unique || !self.has( arg ) ) { + list.push( arg ); + } + } else if ( arg && arg.length && jQuery.type( arg ) !== "string" ) { + + // Inspect recursively + add( arg ); + } + } ); + } )( arguments ); + + if ( memory && !firing ) { + fire(); + } + } + return this; + }, + + // Remove a callback from the list + remove: function() { + jQuery.each( arguments, function( _, arg ) { + var index; + while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { + list.splice( index, 1 ); + + // Handle firing indexes + if ( index <= firingIndex ) { + firingIndex--; + } + } + } ); + return this; + }, + + // Check if a given callback is in the list. + // If no argument is given, return whether or not list has callbacks attached. + has: function( fn ) { + return fn ? + jQuery.inArray( fn, list ) > -1 : + list.length > 0; + }, + + // Remove all callbacks from the list + empty: function() { + if ( list ) { + list = []; + } + return this; + }, + + // Disable .fire and .add + // Abort any current/pending executions + // Clear all callbacks and values + disable: function() { + locked = queue = []; + list = memory = ""; + return this; + }, + disabled: function() { + return !list; + }, + + // Disable .fire + // Also disable .add unless we have memory (since it would have no effect) + // Abort any pending executions + lock: function() { + locked = queue = []; + if ( !memory && !firing ) { + list = memory = ""; + } + return this; + }, + locked: function() { + return !!locked; + }, + + // Call all callbacks with the given context and arguments + fireWith: function( context, args ) { + if ( !locked ) { + args = args || []; + args = [ context, args.slice ? args.slice() : args ]; + queue.push( args ); + if ( !firing ) { + fire(); + } + } + return this; + }, + + // Call all the callbacks with the given arguments + fire: function() { + self.fireWith( this, arguments ); + return this; + }, + + // To know if the callbacks have already been called at least once + fired: function() { + return !!fired; + } + }; + + return self; +}; + + +function Identity( v ) { + return v; +} +function Thrower( ex ) { + throw ex; +} + +function adoptValue( value, resolve, reject, noValue ) { + var method; + + try { + + // Check for promise aspect first to privilege synchronous behavior + if ( value && jQuery.isFunction( ( method = value.promise ) ) ) { + method.call( value ).done( resolve ).fail( reject ); + + // Other thenables + } else if ( value && jQuery.isFunction( ( method = value.then ) ) ) { + method.call( value, resolve, reject ); + + // Other non-thenables + } else { + + // Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer: + // * false: [ value ].slice( 0 ) => resolve( value ) + // * true: [ value ].slice( 1 ) => resolve() + resolve.apply( undefined, [ value ].slice( noValue ) ); + } + + // For Promises/A+, convert exceptions into rejections + // Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in + // Deferred#then to conditionally suppress rejection. + } catch ( value ) { + + // Support: Android 4.0 only + // Strict mode functions invoked without .call/.apply get global-object context + reject.apply( undefined, [ value ] ); + } +} + +jQuery.extend( { + + Deferred: function( func ) { + var tuples = [ + + // action, add listener, callbacks, + // ... .then handlers, argument index, [final state] + [ "notify", "progress", jQuery.Callbacks( "memory" ), + jQuery.Callbacks( "memory" ), 2 ], + [ "resolve", "done", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 0, "resolved" ], + [ "reject", "fail", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 1, "rejected" ] + ], + state = "pending", + promise = { + state: function() { + return state; + }, + always: function() { + deferred.done( arguments ).fail( arguments ); + return this; + }, + "catch": function( fn ) { + return promise.then( null, fn ); + }, + + // Keep pipe for back-compat + pipe: function( /* fnDone, fnFail, fnProgress */ ) { + var fns = arguments; + + return jQuery.Deferred( function( newDefer ) { + jQuery.each( tuples, function( i, tuple ) { + + // Map tuples (progress, done, fail) to arguments (done, fail, progress) + var fn = jQuery.isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ]; + + // deferred.progress(function() { bind to newDefer or newDefer.notify }) + // deferred.done(function() { bind to newDefer or newDefer.resolve }) + // deferred.fail(function() { bind to newDefer or newDefer.reject }) + deferred[ tuple[ 1 ] ]( function() { + var returned = fn && fn.apply( this, arguments ); + if ( returned && jQuery.isFunction( returned.promise ) ) { + returned.promise() + .progress( newDefer.notify ) + .done( newDefer.resolve ) + .fail( newDefer.reject ); + } else { + newDefer[ tuple[ 0 ] + "With" ]( + this, + fn ? [ returned ] : arguments + ); + } + } ); + } ); + fns = null; + } ).promise(); + }, + then: function( onFulfilled, onRejected, onProgress ) { + var maxDepth = 0; + function resolve( depth, deferred, handler, special ) { + return function() { + var that = this, + args = arguments, + mightThrow = function() { + var returned, then; + + // Support: Promises/A+ section 2.3.3.3.3 + // https://promisesaplus.com/#point-59 + // Ignore double-resolution attempts + if ( depth < maxDepth ) { + return; + } + + returned = handler.apply( that, args ); + + // Support: Promises/A+ section 2.3.1 + // https://promisesaplus.com/#point-48 + if ( returned === deferred.promise() ) { + throw new TypeError( "Thenable self-resolution" ); + } + + // Support: Promises/A+ sections 2.3.3.1, 3.5 + // https://promisesaplus.com/#point-54 + // https://promisesaplus.com/#point-75 + // Retrieve `then` only once + then = returned && + + // Support: Promises/A+ section 2.3.4 + // https://promisesaplus.com/#point-64 + // Only check objects and functions for thenability + ( typeof returned === "object" || + typeof returned === "function" ) && + returned.then; + + // Handle a returned thenable + if ( jQuery.isFunction( then ) ) { + + // Special processors (notify) just wait for resolution + if ( special ) { + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ) + ); + + // Normal processors (resolve) also hook into progress + } else { + + // ...and disregard older resolution values + maxDepth++; + + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ), + resolve( maxDepth, deferred, Identity, + deferred.notifyWith ) + ); + } + + // Handle all other returned values + } else { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Identity ) { + that = undefined; + args = [ returned ]; + } + + // Process the value(s) + // Default process is resolve + ( special || deferred.resolveWith )( that, args ); + } + }, + + // Only normal processors (resolve) catch and reject exceptions + process = special ? + mightThrow : + function() { + try { + mightThrow(); + } catch ( e ) { + + if ( jQuery.Deferred.exceptionHook ) { + jQuery.Deferred.exceptionHook( e, + process.stackTrace ); + } + + // Support: Promises/A+ section 2.3.3.3.4.1 + // https://promisesaplus.com/#point-61 + // Ignore post-resolution exceptions + if ( depth + 1 >= maxDepth ) { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Thrower ) { + that = undefined; + args = [ e ]; + } + + deferred.rejectWith( that, args ); + } + } + }; + + // Support: Promises/A+ section 2.3.3.3.1 + // https://promisesaplus.com/#point-57 + // Re-resolve promises immediately to dodge false rejection from + // subsequent errors + if ( depth ) { + process(); + } else { + + // Call an optional hook to record the stack, in case of exception + // since it's otherwise lost when execution goes async + if ( jQuery.Deferred.getStackHook ) { + process.stackTrace = jQuery.Deferred.getStackHook(); + } + window.setTimeout( process ); + } + }; + } + + return jQuery.Deferred( function( newDefer ) { + + // progress_handlers.add( ... ) + tuples[ 0 ][ 3 ].add( + resolve( + 0, + newDefer, + jQuery.isFunction( onProgress ) ? + onProgress : + Identity, + newDefer.notifyWith + ) + ); + + // fulfilled_handlers.add( ... ) + tuples[ 1 ][ 3 ].add( + resolve( + 0, + newDefer, + jQuery.isFunction( onFulfilled ) ? + onFulfilled : + Identity + ) + ); + + // rejected_handlers.add( ... ) + tuples[ 2 ][ 3 ].add( + resolve( + 0, + newDefer, + jQuery.isFunction( onRejected ) ? + onRejected : + Thrower + ) + ); + } ).promise(); + }, + + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + return obj != null ? jQuery.extend( obj, promise ) : promise; + } + }, + deferred = {}; + + // Add list-specific methods + jQuery.each( tuples, function( i, tuple ) { + var list = tuple[ 2 ], + stateString = tuple[ 5 ]; + + // promise.progress = list.add + // promise.done = list.add + // promise.fail = list.add + promise[ tuple[ 1 ] ] = list.add; + + // Handle state + if ( stateString ) { + list.add( + function() { + + // state = "resolved" (i.e., fulfilled) + // state = "rejected" + state = stateString; + }, + + // rejected_callbacks.disable + // fulfilled_callbacks.disable + tuples[ 3 - i ][ 2 ].disable, + + // progress_callbacks.lock + tuples[ 0 ][ 2 ].lock + ); + } + + // progress_handlers.fire + // fulfilled_handlers.fire + // rejected_handlers.fire + list.add( tuple[ 3 ].fire ); + + // deferred.notify = function() { deferred.notifyWith(...) } + // deferred.resolve = function() { deferred.resolveWith(...) } + // deferred.reject = function() { deferred.rejectWith(...) } + deferred[ tuple[ 0 ] ] = function() { + deferred[ tuple[ 0 ] + "With" ]( this === deferred ? undefined : this, arguments ); + return this; + }; + + // deferred.notifyWith = list.fireWith + // deferred.resolveWith = list.fireWith + // deferred.rejectWith = list.fireWith + deferred[ tuple[ 0 ] + "With" ] = list.fireWith; + } ); + + // Make the deferred a promise + promise.promise( deferred ); + + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + + // All done! + return deferred; + }, + + // Deferred helper + when: function( singleValue ) { + var + + // count of uncompleted subordinates + remaining = arguments.length, + + // count of unprocessed arguments + i = remaining, + + // subordinate fulfillment data + resolveContexts = Array( i ), + resolveValues = slice.call( arguments ), + + // the master Deferred + master = jQuery.Deferred(), + + // subordinate callback factory + updateFunc = function( i ) { + return function( value ) { + resolveContexts[ i ] = this; + resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; + if ( !( --remaining ) ) { + master.resolveWith( resolveContexts, resolveValues ); + } + }; + }; + + // Single- and empty arguments are adopted like Promise.resolve + if ( remaining <= 1 ) { + adoptValue( singleValue, master.done( updateFunc( i ) ).resolve, master.reject, + !remaining ); + + // Use .then() to unwrap secondary thenables (cf. gh-3000) + if ( master.state() === "pending" || + jQuery.isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) { + + return master.then(); + } + } + + // Multiple arguments are aggregated like Promise.all array elements + while ( i-- ) { + adoptValue( resolveValues[ i ], updateFunc( i ), master.reject ); + } + + return master.promise(); + } +} ); + + +// These usually indicate a programmer mistake during development, +// warn about them ASAP rather than swallowing them by default. +var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/; + +jQuery.Deferred.exceptionHook = function( error, stack ) { + + // Support: IE 8 - 9 only + // Console exists when dev tools are open, which can happen at any time + if ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) { + window.console.warn( "jQuery.Deferred exception: " + error.message, error.stack, stack ); + } +}; + + + + +jQuery.readyException = function( error ) { + window.setTimeout( function() { + throw error; + } ); +}; + + + + +// The deferred used on DOM ready +var readyList = jQuery.Deferred(); + +jQuery.fn.ready = function( fn ) { + + readyList + .then( fn ) + + // Wrap jQuery.readyException in a function so that the lookup + // happens at the time of error handling instead of callback + // registration. + .catch( function( error ) { + jQuery.readyException( error ); + } ); + + return this; +}; + +jQuery.extend( { + + // Is the DOM ready to be used? Set to true once it occurs. + isReady: false, + + // A counter to track how many items to wait for before + // the ready event fires. See #6781 + readyWait: 1, + + // Handle when the DOM is ready + ready: function( wait ) { + + // Abort if there are pending holds or we're already ready + if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { + return; + } + + // Remember that the DOM is ready + jQuery.isReady = true; + + // If a normal DOM Ready event fired, decrement, and wait if need be + if ( wait !== true && --jQuery.readyWait > 0 ) { + return; + } + + // If there are functions bound, to execute + readyList.resolveWith( document, [ jQuery ] ); + } +} ); + +jQuery.ready.then = readyList.then; + +// The ready event handler and self cleanup method +function completed() { + document.removeEventListener( "DOMContentLoaded", completed ); + window.removeEventListener( "load", completed ); + jQuery.ready(); +} + +// Catch cases where $(document).ready() is called +// after the browser event has already occurred. +// Support: IE <=9 - 10 only +// Older IE sometimes signals "interactive" too soon +if ( document.readyState === "complete" || + ( document.readyState !== "loading" && !document.documentElement.doScroll ) ) { + + // Handle it asynchronously to allow scripts the opportunity to delay ready + window.setTimeout( jQuery.ready ); + +} else { + + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", completed ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", completed ); +} + + + + +// Multifunctional method to get and set values of a collection +// The value/s can optionally be executed if it's a function +var access = function( elems, fn, key, value, chainable, emptyGet, raw ) { + var i = 0, + len = elems.length, + bulk = key == null; + + // Sets many values + if ( jQuery.type( key ) === "object" ) { + chainable = true; + for ( i in key ) { + access( elems, fn, i, key[ i ], true, emptyGet, raw ); + } + + // Sets one value + } else if ( value !== undefined ) { + chainable = true; + + if ( !jQuery.isFunction( value ) ) { + raw = true; + } + + if ( bulk ) { + + // Bulk operations run against the entire set + if ( raw ) { + fn.call( elems, value ); + fn = null; + + // ...except when executing function values + } else { + bulk = fn; + fn = function( elem, key, value ) { + return bulk.call( jQuery( elem ), value ); + }; + } + } + + if ( fn ) { + for ( ; i < len; i++ ) { + fn( + elems[ i ], key, raw ? + value : + value.call( elems[ i ], i, fn( elems[ i ], key ) ) + ); + } + } + } + + if ( chainable ) { + return elems; + } + + // Gets + if ( bulk ) { + return fn.call( elems ); + } + + return len ? fn( elems[ 0 ], key ) : emptyGet; +}; +var acceptData = function( owner ) { + + // Accepts only: + // - Node + // - Node.ELEMENT_NODE + // - Node.DOCUMENT_NODE + // - Object + // - Any + return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType ); +}; + + + + +function Data() { + this.expando = jQuery.expando + Data.uid++; +} + +Data.uid = 1; + +Data.prototype = { + + cache: function( owner ) { + + // Check if the owner object already has a cache + var value = owner[ this.expando ]; + + // If not, create one + if ( !value ) { + value = {}; + + // We can accept data for non-element nodes in modern browsers, + // but we should not, see #8335. + // Always return an empty object. + if ( acceptData( owner ) ) { + + // If it is a node unlikely to be stringify-ed or looped over + // use plain assignment + if ( owner.nodeType ) { + owner[ this.expando ] = value; + + // Otherwise secure it in a non-enumerable property + // configurable must be true to allow the property to be + // deleted when data is removed + } else { + Object.defineProperty( owner, this.expando, { + value: value, + configurable: true + } ); + } + } + } + + return value; + }, + set: function( owner, data, value ) { + var prop, + cache = this.cache( owner ); + + // Handle: [ owner, key, value ] args + // Always use camelCase key (gh-2257) + if ( typeof data === "string" ) { + cache[ jQuery.camelCase( data ) ] = value; + + // Handle: [ owner, { properties } ] args + } else { + + // Copy the properties one-by-one to the cache object + for ( prop in data ) { + cache[ jQuery.camelCase( prop ) ] = data[ prop ]; + } + } + return cache; + }, + get: function( owner, key ) { + return key === undefined ? + this.cache( owner ) : + + // Always use camelCase key (gh-2257) + owner[ this.expando ] && owner[ this.expando ][ jQuery.camelCase( key ) ]; + }, + access: function( owner, key, value ) { + + // In cases where either: + // + // 1. No key was specified + // 2. A string key was specified, but no value provided + // + // Take the "read" path and allow the get method to determine + // which value to return, respectively either: + // + // 1. The entire cache object + // 2. The data stored at the key + // + if ( key === undefined || + ( ( key && typeof key === "string" ) && value === undefined ) ) { + + return this.get( owner, key ); + } + + // When the key is not a string, or both a key and value + // are specified, set or extend (existing objects) with either: + // + // 1. An object of properties + // 2. A key and value + // + this.set( owner, key, value ); + + // Since the "set" path can have two possible entry points + // return the expected data based on which path was taken[*] + return value !== undefined ? value : key; + }, + remove: function( owner, key ) { + var i, + cache = owner[ this.expando ]; + + if ( cache === undefined ) { + return; + } + + if ( key !== undefined ) { + + // Support array or space separated string of keys + if ( Array.isArray( key ) ) { + + // If key is an array of keys... + // We always set camelCase keys, so remove that. + key = key.map( jQuery.camelCase ); + } else { + key = jQuery.camelCase( key ); + + // If a key with the spaces exists, use it. + // Otherwise, create an array by matching non-whitespace + key = key in cache ? + [ key ] : + ( key.match( rnothtmlwhite ) || [] ); + } + + i = key.length; + + while ( i-- ) { + delete cache[ key[ i ] ]; + } + } + + // Remove the expando if there's no more data + if ( key === undefined || jQuery.isEmptyObject( cache ) ) { + + // Support: Chrome <=35 - 45 + // Webkit & Blink performance suffers when deleting properties + // from DOM nodes, so set to undefined instead + // https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted) + if ( owner.nodeType ) { + owner[ this.expando ] = undefined; + } else { + delete owner[ this.expando ]; + } + } + }, + hasData: function( owner ) { + var cache = owner[ this.expando ]; + return cache !== undefined && !jQuery.isEmptyObject( cache ); + } +}; +var dataPriv = new Data(); + +var dataUser = new Data(); + + + +// Implementation Summary +// +// 1. Enforce API surface and semantic compatibility with 1.9.x branch +// 2. Improve the module's maintainability by reducing the storage +// paths to a single mechanism. +// 3. Use the same single mechanism to support "private" and "user" data. +// 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData) +// 5. Avoid exposing implementation details on user objects (eg. expando properties) +// 6. Provide a clear path for implementation upgrade to WeakMap in 2014 + +var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, + rmultiDash = /[A-Z]/g; + +function getData( data ) { + if ( data === "true" ) { + return true; + } + + if ( data === "false" ) { + return false; + } + + if ( data === "null" ) { + return null; + } + + // Only convert to a number if it doesn't change the string + if ( data === +data + "" ) { + return +data; + } + + if ( rbrace.test( data ) ) { + return JSON.parse( data ); + } + + return data; +} + +function dataAttr( elem, key, data ) { + var name; + + // If nothing was found internally, try to fetch any + // data from the HTML5 data-* attribute + if ( data === undefined && elem.nodeType === 1 ) { + name = "data-" + key.replace( rmultiDash, "-$&" ).toLowerCase(); + data = elem.getAttribute( name ); + + if ( typeof data === "string" ) { + try { + data = getData( data ); + } catch ( e ) {} + + // Make sure we set the data so it isn't changed later + dataUser.set( elem, key, data ); + } else { + data = undefined; + } + } + return data; +} + +jQuery.extend( { + hasData: function( elem ) { + return dataUser.hasData( elem ) || dataPriv.hasData( elem ); + }, + + data: function( elem, name, data ) { + return dataUser.access( elem, name, data ); + }, + + removeData: function( elem, name ) { + dataUser.remove( elem, name ); + }, + + // TODO: Now that all calls to _data and _removeData have been replaced + // with direct calls to dataPriv methods, these can be deprecated. + _data: function( elem, name, data ) { + return dataPriv.access( elem, name, data ); + }, + + _removeData: function( elem, name ) { + dataPriv.remove( elem, name ); + } +} ); + +jQuery.fn.extend( { + data: function( key, value ) { + var i, name, data, + elem = this[ 0 ], + attrs = elem && elem.attributes; + + // Gets all values + if ( key === undefined ) { + if ( this.length ) { + data = dataUser.get( elem ); + + if ( elem.nodeType === 1 && !dataPriv.get( elem, "hasDataAttrs" ) ) { + i = attrs.length; + while ( i-- ) { + + // Support: IE 11 only + // The attrs elements can be null (#14894) + if ( attrs[ i ] ) { + name = attrs[ i ].name; + if ( name.indexOf( "data-" ) === 0 ) { + name = jQuery.camelCase( name.slice( 5 ) ); + dataAttr( elem, name, data[ name ] ); + } + } + } + dataPriv.set( elem, "hasDataAttrs", true ); + } + } + + return data; + } + + // Sets multiple values + if ( typeof key === "object" ) { + return this.each( function() { + dataUser.set( this, key ); + } ); + } + + return access( this, function( value ) { + var data; + + // The calling jQuery object (element matches) is not empty + // (and therefore has an element appears at this[ 0 ]) and the + // `value` parameter was not undefined. An empty jQuery object + // will result in `undefined` for elem = this[ 0 ] which will + // throw an exception if an attempt to read a data cache is made. + if ( elem && value === undefined ) { + + // Attempt to get data from the cache + // The key will always be camelCased in Data + data = dataUser.get( elem, key ); + if ( data !== undefined ) { + return data; + } + + // Attempt to "discover" the data in + // HTML5 custom data-* attrs + data = dataAttr( elem, key ); + if ( data !== undefined ) { + return data; + } + + // We tried really hard, but the data doesn't exist. + return; + } + + // Set the data... + this.each( function() { + + // We always store the camelCased key + dataUser.set( this, key, value ); + } ); + }, null, value, arguments.length > 1, null, true ); + }, + + removeData: function( key ) { + return this.each( function() { + dataUser.remove( this, key ); + } ); + } +} ); + + +jQuery.extend( { + queue: function( elem, type, data ) { + var queue; + + if ( elem ) { + type = ( type || "fx" ) + "queue"; + queue = dataPriv.get( elem, type ); + + // Speed up dequeue by getting out quickly if this is just a lookup + if ( data ) { + if ( !queue || Array.isArray( data ) ) { + queue = dataPriv.access( elem, type, jQuery.makeArray( data ) ); + } else { + queue.push( data ); + } + } + return queue || []; + } + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), + startLength = queue.length, + fn = queue.shift(), + hooks = jQuery._queueHooks( elem, type ), + next = function() { + jQuery.dequeue( elem, type ); + }; + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + startLength--; + } + + if ( fn ) { + + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift( "inprogress" ); + } + + // Clear up the last queue stop function + delete hooks.stop; + fn.call( elem, next, hooks ); + } + + if ( !startLength && hooks ) { + hooks.empty.fire(); + } + }, + + // Not public - generate a queueHooks object, or return the current one + _queueHooks: function( elem, type ) { + var key = type + "queueHooks"; + return dataPriv.get( elem, key ) || dataPriv.access( elem, key, { + empty: jQuery.Callbacks( "once memory" ).add( function() { + dataPriv.remove( elem, [ type + "queue", key ] ); + } ) + } ); + } +} ); + +jQuery.fn.extend( { + queue: function( type, data ) { + var setter = 2; + + if ( typeof type !== "string" ) { + data = type; + type = "fx"; + setter--; + } + + if ( arguments.length < setter ) { + return jQuery.queue( this[ 0 ], type ); + } + + return data === undefined ? + this : + this.each( function() { + var queue = jQuery.queue( this, type, data ); + + // Ensure a hooks for this queue + jQuery._queueHooks( this, type ); + + if ( type === "fx" && queue[ 0 ] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + } ); + }, + dequeue: function( type ) { + return this.each( function() { + jQuery.dequeue( this, type ); + } ); + }, + clearQueue: function( type ) { + return this.queue( type || "fx", [] ); + }, + + // Get a promise resolved when queues of a certain type + // are emptied (fx is the type by default) + promise: function( type, obj ) { + var tmp, + count = 1, + defer = jQuery.Deferred(), + elements = this, + i = this.length, + resolve = function() { + if ( !( --count ) ) { + defer.resolveWith( elements, [ elements ] ); + } + }; + + if ( typeof type !== "string" ) { + obj = type; + type = undefined; + } + type = type || "fx"; + + while ( i-- ) { + tmp = dataPriv.get( elements[ i ], type + "queueHooks" ); + if ( tmp && tmp.empty ) { + count++; + tmp.empty.add( resolve ); + } + } + resolve(); + return defer.promise( obj ); + } +} ); +var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source; + +var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ); + + +var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; + +var isHiddenWithinTree = function( elem, el ) { + + // isHiddenWithinTree might be called from jQuery#filter function; + // in that case, element will be second argument + elem = el || elem; + + // Inline style trumps all + return elem.style.display === "none" || + elem.style.display === "" && + + // Otherwise, check computed style + // Support: Firefox <=43 - 45 + // Disconnected elements can have computed display: none, so first confirm that elem is + // in the document. + jQuery.contains( elem.ownerDocument, elem ) && + + jQuery.css( elem, "display" ) === "none"; + }; + +var swap = function( elem, options, callback, args ) { + var ret, name, + old = {}; + + // Remember the old values, and insert the new ones + for ( name in options ) { + old[ name ] = elem.style[ name ]; + elem.style[ name ] = options[ name ]; + } + + ret = callback.apply( elem, args || [] ); + + // Revert the old values + for ( name in options ) { + elem.style[ name ] = old[ name ]; + } + + return ret; +}; + + + + +function adjustCSS( elem, prop, valueParts, tween ) { + var adjusted, + scale = 1, + maxIterations = 20, + currentValue = tween ? + function() { + return tween.cur(); + } : + function() { + return jQuery.css( elem, prop, "" ); + }, + initial = currentValue(), + unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ), + + // Starting value computation is required for potential unit mismatches + initialInUnit = ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) && + rcssNum.exec( jQuery.css( elem, prop ) ); + + if ( initialInUnit && initialInUnit[ 3 ] !== unit ) { + + // Trust units reported by jQuery.css + unit = unit || initialInUnit[ 3 ]; + + // Make sure we update the tween properties later on + valueParts = valueParts || []; + + // Iteratively approximate from a nonzero starting point + initialInUnit = +initial || 1; + + do { + + // If previous iteration zeroed out, double until we get *something*. + // Use string for doubling so we don't accidentally see scale as unchanged below + scale = scale || ".5"; + + // Adjust and apply + initialInUnit = initialInUnit / scale; + jQuery.style( elem, prop, initialInUnit + unit ); + + // Update scale, tolerating zero or NaN from tween.cur() + // Break the loop if scale is unchanged or perfect, or if we've just had enough. + } while ( + scale !== ( scale = currentValue() / initial ) && scale !== 1 && --maxIterations + ); + } + + if ( valueParts ) { + initialInUnit = +initialInUnit || +initial || 0; + + // Apply relative offset (+=/-=) if specified + adjusted = valueParts[ 1 ] ? + initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] : + +valueParts[ 2 ]; + if ( tween ) { + tween.unit = unit; + tween.start = initialInUnit; + tween.end = adjusted; + } + } + return adjusted; +} + + +var defaultDisplayMap = {}; + +function getDefaultDisplay( elem ) { + var temp, + doc = elem.ownerDocument, + nodeName = elem.nodeName, + display = defaultDisplayMap[ nodeName ]; + + if ( display ) { + return display; + } + + temp = doc.body.appendChild( doc.createElement( nodeName ) ); + display = jQuery.css( temp, "display" ); + + temp.parentNode.removeChild( temp ); + + if ( display === "none" ) { + display = "block"; + } + defaultDisplayMap[ nodeName ] = display; + + return display; +} + +function showHide( elements, show ) { + var display, elem, + values = [], + index = 0, + length = elements.length; + + // Determine new display value for elements that need to change + for ( ; index < length; index++ ) { + elem = elements[ index ]; + if ( !elem.style ) { + continue; + } + + display = elem.style.display; + if ( show ) { + + // Since we force visibility upon cascade-hidden elements, an immediate (and slow) + // check is required in this first loop unless we have a nonempty display value (either + // inline or about-to-be-restored) + if ( display === "none" ) { + values[ index ] = dataPriv.get( elem, "display" ) || null; + if ( !values[ index ] ) { + elem.style.display = ""; + } + } + if ( elem.style.display === "" && isHiddenWithinTree( elem ) ) { + values[ index ] = getDefaultDisplay( elem ); + } + } else { + if ( display !== "none" ) { + values[ index ] = "none"; + + // Remember what we're overwriting + dataPriv.set( elem, "display", display ); + } + } + } + + // Set the display of the elements in a second loop to avoid constant reflow + for ( index = 0; index < length; index++ ) { + if ( values[ index ] != null ) { + elements[ index ].style.display = values[ index ]; + } + } + + return elements; +} + +jQuery.fn.extend( { + show: function() { + return showHide( this, true ); + }, + hide: function() { + return showHide( this ); + }, + toggle: function( state ) { + if ( typeof state === "boolean" ) { + return state ? this.show() : this.hide(); + } + + return this.each( function() { + if ( isHiddenWithinTree( this ) ) { + jQuery( this ).show(); + } else { + jQuery( this ).hide(); + } + } ); + } +} ); +var rcheckableType = ( /^(?:checkbox|radio)$/i ); + +var rtagName = ( /<([a-z][^\/\0>\x20\t\r\n\f]+)/i ); + +var rscriptType = ( /^$|\/(?:java|ecma)script/i ); + + + +// We have to close these tags to support XHTML (#13200) +var wrapMap = { + + // Support: IE <=9 only + option: [ 1, "" ], + + // XHTML parsers do not magically insert elements in the + // same way that tag soup parsers do. So we cannot shorten + // this by omitting or other required elements. + thead: [ 1, "", "
" ], + col: [ 2, "", "
" ], + tr: [ 2, "", "
" ], + td: [ 3, "", "
" ], + + _default: [ 0, "", "" ] +}; + +// Support: IE <=9 only +wrapMap.optgroup = wrapMap.option; + +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + + +function getAll( context, tag ) { + + // Support: IE <=9 - 11 only + // Use typeof to avoid zero-argument method invocation on host objects (#15151) + var ret; + + if ( typeof context.getElementsByTagName !== "undefined" ) { + ret = context.getElementsByTagName( tag || "*" ); + + } else if ( typeof context.querySelectorAll !== "undefined" ) { + ret = context.querySelectorAll( tag || "*" ); + + } else { + ret = []; + } + + if ( tag === undefined || tag && nodeName( context, tag ) ) { + return jQuery.merge( [ context ], ret ); + } + + return ret; +} + + +// Mark scripts as having already been evaluated +function setGlobalEval( elems, refElements ) { + var i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + dataPriv.set( + elems[ i ], + "globalEval", + !refElements || dataPriv.get( refElements[ i ], "globalEval" ) + ); + } +} + + +var rhtml = /<|&#?\w+;/; + +function buildFragment( elems, context, scripts, selection, ignored ) { + var elem, tmp, tag, wrap, contains, j, + fragment = context.createDocumentFragment(), + nodes = [], + i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + elem = elems[ i ]; + + if ( elem || elem === 0 ) { + + // Add nodes directly + if ( jQuery.type( elem ) === "object" ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); + + // Convert non-html into a text node + } else if ( !rhtml.test( elem ) ) { + nodes.push( context.createTextNode( elem ) ); + + // Convert html into DOM nodes + } else { + tmp = tmp || fragment.appendChild( context.createElement( "div" ) ); + + // Deserialize a standard representation + tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase(); + wrap = wrapMap[ tag ] || wrapMap._default; + tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ]; + + // Descend through wrappers to the right content + j = wrap[ 0 ]; + while ( j-- ) { + tmp = tmp.lastChild; + } + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, tmp.childNodes ); + + // Remember the top-level container + tmp = fragment.firstChild; + + // Ensure the created nodes are orphaned (#12392) + tmp.textContent = ""; + } + } + } + + // Remove wrapper from fragment + fragment.textContent = ""; + + i = 0; + while ( ( elem = nodes[ i++ ] ) ) { + + // Skip elements already in the context collection (trac-4087) + if ( selection && jQuery.inArray( elem, selection ) > -1 ) { + if ( ignored ) { + ignored.push( elem ); + } + continue; + } + + contains = jQuery.contains( elem.ownerDocument, elem ); + + // Append to fragment + tmp = getAll( fragment.appendChild( elem ), "script" ); + + // Preserve script evaluation history + if ( contains ) { + setGlobalEval( tmp ); + } + + // Capture executables + if ( scripts ) { + j = 0; + while ( ( elem = tmp[ j++ ] ) ) { + if ( rscriptType.test( elem.type || "" ) ) { + scripts.push( elem ); + } + } + } + } + + return fragment; +} + + +( function() { + var fragment = document.createDocumentFragment(), + div = fragment.appendChild( document.createElement( "div" ) ), + input = document.createElement( "input" ); + + // Support: Android 4.0 - 4.3 only + // Check state lost if the name is set (#11217) + // Support: Windows Web Apps (WWA) + // `name` and `type` must use .setAttribute for WWA (#14901) + input.setAttribute( "type", "radio" ); + input.setAttribute( "checked", "checked" ); + input.setAttribute( "name", "t" ); + + div.appendChild( input ); + + // Support: Android <=4.1 only + // Older WebKit doesn't clone checked state correctly in fragments + support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; + + // Support: IE <=11 only + // Make sure textarea (and checkbox) defaultValue is properly cloned + div.innerHTML = ""; + support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; +} )(); +var documentElement = document.documentElement; + + + +var + rkeyEvent = /^key/, + rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/, + rtypenamespace = /^([^.]*)(?:\.(.+)|)/; + +function returnTrue() { + return true; +} + +function returnFalse() { + return false; +} + +// Support: IE <=9 only +// See #13393 for more info +function safeActiveElement() { + try { + return document.activeElement; + } catch ( err ) { } +} + +function on( elem, types, selector, data, fn, one ) { + var origFn, type; + + // Types can be a map of types/handlers + if ( typeof types === "object" ) { + + // ( types-Object, selector, data ) + if ( typeof selector !== "string" ) { + + // ( types-Object, data ) + data = data || selector; + selector = undefined; + } + for ( type in types ) { + on( elem, type, selector, data, types[ type ], one ); + } + return elem; + } + + if ( data == null && fn == null ) { + + // ( types, fn ) + fn = selector; + data = selector = undefined; + } else if ( fn == null ) { + if ( typeof selector === "string" ) { + + // ( types, selector, fn ) + fn = data; + data = undefined; + } else { + + // ( types, data, fn ) + fn = data; + data = selector; + selector = undefined; + } + } + if ( fn === false ) { + fn = returnFalse; + } else if ( !fn ) { + return elem; + } + + if ( one === 1 ) { + origFn = fn; + fn = function( event ) { + + // Can use an empty set, since event contains the info + jQuery().off( event ); + return origFn.apply( this, arguments ); + }; + + // Use same guid so caller can remove using origFn + fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); + } + return elem.each( function() { + jQuery.event.add( this, types, fn, data, selector ); + } ); +} + +/* + * Helper functions for managing events -- not part of the public interface. + * Props to Dean Edwards' addEvent library for many of the ideas. + */ +jQuery.event = { + + global: {}, + + add: function( elem, types, handler, data, selector ) { + + var handleObjIn, eventHandle, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.get( elem ); + + // Don't attach events to noData or text/comment nodes (but allow plain objects) + if ( !elemData ) { + return; + } + + // Caller can pass in an object of custom data in lieu of the handler + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + selector = handleObjIn.selector; + } + + // Ensure that invalid selectors throw exceptions at attach time + // Evaluate against documentElement in case elem is a non-element node (e.g., document) + if ( selector ) { + jQuery.find.matchesSelector( documentElement, selector ); + } + + // Make sure that the handler has a unique ID, used to find/remove it later + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure and main handler, if this is the first + if ( !( events = elemData.events ) ) { + events = elemData.events = {}; + } + if ( !( eventHandle = elemData.handle ) ) { + eventHandle = elemData.handle = function( e ) { + + // Discard the second event of a jQuery.event.trigger() and + // when an event is called after a page has unloaded + return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ? + jQuery.event.dispatch.apply( elem, arguments ) : undefined; + }; + } + + // Handle multiple events separated by a space + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // There *must* be a type, no attaching namespace-only handlers + if ( !type ) { + continue; + } + + // If event changes its type, use the special event handlers for the changed type + special = jQuery.event.special[ type ] || {}; + + // If selector defined, determine special event api type, otherwise given type + type = ( selector ? special.delegateType : special.bindType ) || type; + + // Update special based on newly reset type + special = jQuery.event.special[ type ] || {}; + + // handleObj is passed to all event handlers + handleObj = jQuery.extend( { + type: type, + origType: origType, + data: data, + handler: handler, + guid: handler.guid, + selector: selector, + needsContext: selector && jQuery.expr.match.needsContext.test( selector ), + namespace: namespaces.join( "." ) + }, handleObjIn ); + + // Init the event handler queue if we're the first + if ( !( handlers = events[ type ] ) ) { + handlers = events[ type ] = []; + handlers.delegateCount = 0; + + // Only use addEventListener if the special events handler returns false + if ( !special.setup || + special.setup.call( elem, data, namespaces, eventHandle ) === false ) { + + if ( elem.addEventListener ) { + elem.addEventListener( type, eventHandle ); + } + } + } + + if ( special.add ) { + special.add.call( elem, handleObj ); + + if ( !handleObj.handler.guid ) { + handleObj.handler.guid = handler.guid; + } + } + + // Add to the element's handler list, delegates in front + if ( selector ) { + handlers.splice( handlers.delegateCount++, 0, handleObj ); + } else { + handlers.push( handleObj ); + } + + // Keep track of which events have ever been used, for event optimization + jQuery.event.global[ type ] = true; + } + + }, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, selector, mappedTypes ) { + + var j, origCount, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.hasData( elem ) && dataPriv.get( elem ); + + if ( !elemData || !( events = elemData.events ) ) { + return; + } + + // Once for each type.namespace in types; type may be omitted + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // Unbind all events (on this namespace, if provided) for the element + if ( !type ) { + for ( type in events ) { + jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); + } + continue; + } + + special = jQuery.event.special[ type ] || {}; + type = ( selector ? special.delegateType : special.bindType ) || type; + handlers = events[ type ] || []; + tmp = tmp[ 2 ] && + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ); + + // Remove matching events + origCount = j = handlers.length; + while ( j-- ) { + handleObj = handlers[ j ]; + + if ( ( mappedTypes || origType === handleObj.origType ) && + ( !handler || handler.guid === handleObj.guid ) && + ( !tmp || tmp.test( handleObj.namespace ) ) && + ( !selector || selector === handleObj.selector || + selector === "**" && handleObj.selector ) ) { + handlers.splice( j, 1 ); + + if ( handleObj.selector ) { + handlers.delegateCount--; + } + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + } + + // Remove generic event handler if we removed something and no more handlers exist + // (avoids potential for endless recursion during removal of special event handlers) + if ( origCount && !handlers.length ) { + if ( !special.teardown || + special.teardown.call( elem, namespaces, elemData.handle ) === false ) { + + jQuery.removeEvent( elem, type, elemData.handle ); + } + + delete events[ type ]; + } + } + + // Remove data and the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + dataPriv.remove( elem, "handle events" ); + } + }, + + dispatch: function( nativeEvent ) { + + // Make a writable jQuery.Event from the native event object + var event = jQuery.event.fix( nativeEvent ); + + var i, j, ret, matched, handleObj, handlerQueue, + args = new Array( arguments.length ), + handlers = ( dataPriv.get( this, "events" ) || {} )[ event.type ] || [], + special = jQuery.event.special[ event.type ] || {}; + + // Use the fix-ed jQuery.Event rather than the (read-only) native event + args[ 0 ] = event; + + for ( i = 1; i < arguments.length; i++ ) { + args[ i ] = arguments[ i ]; + } + + event.delegateTarget = this; + + // Call the preDispatch hook for the mapped type, and let it bail if desired + if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { + return; + } + + // Determine handlers + handlerQueue = jQuery.event.handlers.call( this, event, handlers ); + + // Run delegates first; they may want to stop propagation beneath us + i = 0; + while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) { + event.currentTarget = matched.elem; + + j = 0; + while ( ( handleObj = matched.handlers[ j++ ] ) && + !event.isImmediatePropagationStopped() ) { + + // Triggered event must either 1) have no namespace, or 2) have namespace(s) + // a subset or equal to those in the bound event (both can have no namespace). + if ( !event.rnamespace || event.rnamespace.test( handleObj.namespace ) ) { + + event.handleObj = handleObj; + event.data = handleObj.data; + + ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle || + handleObj.handler ).apply( matched.elem, args ); + + if ( ret !== undefined ) { + if ( ( event.result = ret ) === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + } + } + } + + // Call the postDispatch hook for the mapped type + if ( special.postDispatch ) { + special.postDispatch.call( this, event ); + } + + return event.result; + }, + + handlers: function( event, handlers ) { + var i, handleObj, sel, matchedHandlers, matchedSelectors, + handlerQueue = [], + delegateCount = handlers.delegateCount, + cur = event.target; + + // Find delegate handlers + if ( delegateCount && + + // Support: IE <=9 + // Black-hole SVG instance trees (trac-13180) + cur.nodeType && + + // Support: Firefox <=42 + // Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861) + // https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click + // Support: IE 11 only + // ...but not arrow key "clicks" of radio inputs, which can have `button` -1 (gh-2343) + !( event.type === "click" && event.button >= 1 ) ) { + + for ( ; cur !== this; cur = cur.parentNode || this ) { + + // Don't check non-elements (#13208) + // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) + if ( cur.nodeType === 1 && !( event.type === "click" && cur.disabled === true ) ) { + matchedHandlers = []; + matchedSelectors = {}; + for ( i = 0; i < delegateCount; i++ ) { + handleObj = handlers[ i ]; + + // Don't conflict with Object.prototype properties (#13203) + sel = handleObj.selector + " "; + + if ( matchedSelectors[ sel ] === undefined ) { + matchedSelectors[ sel ] = handleObj.needsContext ? + jQuery( sel, this ).index( cur ) > -1 : + jQuery.find( sel, this, null, [ cur ] ).length; + } + if ( matchedSelectors[ sel ] ) { + matchedHandlers.push( handleObj ); + } + } + if ( matchedHandlers.length ) { + handlerQueue.push( { elem: cur, handlers: matchedHandlers } ); + } + } + } + } + + // Add the remaining (directly-bound) handlers + cur = this; + if ( delegateCount < handlers.length ) { + handlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } ); + } + + return handlerQueue; + }, + + addProp: function( name, hook ) { + Object.defineProperty( jQuery.Event.prototype, name, { + enumerable: true, + configurable: true, + + get: jQuery.isFunction( hook ) ? + function() { + if ( this.originalEvent ) { + return hook( this.originalEvent ); + } + } : + function() { + if ( this.originalEvent ) { + return this.originalEvent[ name ]; + } + }, + + set: function( value ) { + Object.defineProperty( this, name, { + enumerable: true, + configurable: true, + writable: true, + value: value + } ); + } + } ); + }, + + fix: function( originalEvent ) { + return originalEvent[ jQuery.expando ] ? + originalEvent : + new jQuery.Event( originalEvent ); + }, + + special: { + load: { + + // Prevent triggered image.load events from bubbling to window.load + noBubble: true + }, + focus: { + + // Fire native event if possible so blur/focus sequence is correct + trigger: function() { + if ( this !== safeActiveElement() && this.focus ) { + this.focus(); + return false; + } + }, + delegateType: "focusin" + }, + blur: { + trigger: function() { + if ( this === safeActiveElement() && this.blur ) { + this.blur(); + return false; + } + }, + delegateType: "focusout" + }, + click: { + + // For checkbox, fire native event so checked state will be right + trigger: function() { + if ( this.type === "checkbox" && this.click && nodeName( this, "input" ) ) { + this.click(); + return false; + } + }, + + // For cross-browser consistency, don't fire native .click() on links + _default: function( event ) { + return nodeName( event.target, "a" ); + } + }, + + beforeunload: { + postDispatch: function( event ) { + + // Support: Firefox 20+ + // Firefox doesn't alert if the returnValue field is not set. + if ( event.result !== undefined && event.originalEvent ) { + event.originalEvent.returnValue = event.result; + } + } + } + } +}; + +jQuery.removeEvent = function( elem, type, handle ) { + + // This "if" is needed for plain objects + if ( elem.removeEventListener ) { + elem.removeEventListener( type, handle ); + } +}; + +jQuery.Event = function( src, props ) { + + // Allow instantiation without the 'new' keyword + if ( !( this instanceof jQuery.Event ) ) { + return new jQuery.Event( src, props ); + } + + // Event object + if ( src && src.type ) { + this.originalEvent = src; + this.type = src.type; + + // Events bubbling up the document may have been marked as prevented + // by a handler lower down the tree; reflect the correct value. + this.isDefaultPrevented = src.defaultPrevented || + src.defaultPrevented === undefined && + + // Support: Android <=2.3 only + src.returnValue === false ? + returnTrue : + returnFalse; + + // Create target properties + // Support: Safari <=6 - 7 only + // Target should not be a text node (#504, #13143) + this.target = ( src.target && src.target.nodeType === 3 ) ? + src.target.parentNode : + src.target; + + this.currentTarget = src.currentTarget; + this.relatedTarget = src.relatedTarget; + + // Event type + } else { + this.type = src; + } + + // Put explicitly provided properties onto the event object + if ( props ) { + jQuery.extend( this, props ); + } + + // Create a timestamp if incoming event doesn't have one + this.timeStamp = src && src.timeStamp || jQuery.now(); + + // Mark it as fixed + this[ jQuery.expando ] = true; +}; + +// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding +// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html +jQuery.Event.prototype = { + constructor: jQuery.Event, + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse, + isSimulated: false, + + preventDefault: function() { + var e = this.originalEvent; + + this.isDefaultPrevented = returnTrue; + + if ( e && !this.isSimulated ) { + e.preventDefault(); + } + }, + stopPropagation: function() { + var e = this.originalEvent; + + this.isPropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopPropagation(); + } + }, + stopImmediatePropagation: function() { + var e = this.originalEvent; + + this.isImmediatePropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopImmediatePropagation(); + } + + this.stopPropagation(); + } +}; + +// Includes all common event props including KeyEvent and MouseEvent specific props +jQuery.each( { + altKey: true, + bubbles: true, + cancelable: true, + changedTouches: true, + ctrlKey: true, + detail: true, + eventPhase: true, + metaKey: true, + pageX: true, + pageY: true, + shiftKey: true, + view: true, + "char": true, + charCode: true, + key: true, + keyCode: true, + button: true, + buttons: true, + clientX: true, + clientY: true, + offsetX: true, + offsetY: true, + pointerId: true, + pointerType: true, + screenX: true, + screenY: true, + targetTouches: true, + toElement: true, + touches: true, + + which: function( event ) { + var button = event.button; + + // Add which for key events + if ( event.which == null && rkeyEvent.test( event.type ) ) { + return event.charCode != null ? event.charCode : event.keyCode; + } + + // Add which for click: 1 === left; 2 === middle; 3 === right + if ( !event.which && button !== undefined && rmouseEvent.test( event.type ) ) { + if ( button & 1 ) { + return 1; + } + + if ( button & 2 ) { + return 3; + } + + if ( button & 4 ) { + return 2; + } + + return 0; + } + + return event.which; + } +}, jQuery.event.addProp ); + +// Create mouseenter/leave events using mouseover/out and event-time checks +// so that event delegation works in jQuery. +// Do the same for pointerenter/pointerleave and pointerover/pointerout +// +// Support: Safari 7 only +// Safari sends mouseenter too often; see: +// https://bugs.chromium.org/p/chromium/issues/detail?id=470258 +// for the description of the bug (it existed in older Chrome versions as well). +jQuery.each( { + mouseenter: "mouseover", + mouseleave: "mouseout", + pointerenter: "pointerover", + pointerleave: "pointerout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + delegateType: fix, + bindType: fix, + + handle: function( event ) { + var ret, + target = this, + related = event.relatedTarget, + handleObj = event.handleObj; + + // For mouseenter/leave call the handler if related is outside the target. + // NB: No relatedTarget if the mouse left/entered the browser window + if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) { + event.type = handleObj.origType; + ret = handleObj.handler.apply( this, arguments ); + event.type = fix; + } + return ret; + } + }; +} ); + +jQuery.fn.extend( { + + on: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn ); + }, + one: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn, 1 ); + }, + off: function( types, selector, fn ) { + var handleObj, type; + if ( types && types.preventDefault && types.handleObj ) { + + // ( event ) dispatched jQuery.Event + handleObj = types.handleObj; + jQuery( types.delegateTarget ).off( + handleObj.namespace ? + handleObj.origType + "." + handleObj.namespace : + handleObj.origType, + handleObj.selector, + handleObj.handler + ); + return this; + } + if ( typeof types === "object" ) { + + // ( types-object [, selector] ) + for ( type in types ) { + this.off( type, selector, types[ type ] ); + } + return this; + } + if ( selector === false || typeof selector === "function" ) { + + // ( types [, fn] ) + fn = selector; + selector = undefined; + } + if ( fn === false ) { + fn = returnFalse; + } + return this.each( function() { + jQuery.event.remove( this, types, fn, selector ); + } ); + } +} ); + + +var + + /* eslint-disable max-len */ + + // See https://github.com/eslint/eslint/issues/3229 + rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\/\0>\x20\t\r\n\f]*)[^>]*)\/>/gi, + + /* eslint-enable */ + + // Support: IE <=10 - 11, Edge 12 - 13 + // In IE/Edge using regex groups here causes severe slowdowns. + // See https://connect.microsoft.com/IE/feedback/details/1736512/ + rnoInnerhtml = /\s*$/g; + +// Prefer a tbody over its parent table for containing new rows +function manipulationTarget( elem, content ) { + if ( nodeName( elem, "table" ) && + nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ) { + + return jQuery( ">tbody", elem )[ 0 ] || elem; + } + + return elem; +} + +// Replace/restore the type attribute of script elements for safe DOM manipulation +function disableScript( elem ) { + elem.type = ( elem.getAttribute( "type" ) !== null ) + "/" + elem.type; + return elem; +} +function restoreScript( elem ) { + var match = rscriptTypeMasked.exec( elem.type ); + + if ( match ) { + elem.type = match[ 1 ]; + } else { + elem.removeAttribute( "type" ); + } + + return elem; +} + +function cloneCopyEvent( src, dest ) { + var i, l, type, pdataOld, pdataCur, udataOld, udataCur, events; + + if ( dest.nodeType !== 1 ) { + return; + } + + // 1. Copy private data: events, handlers, etc. + if ( dataPriv.hasData( src ) ) { + pdataOld = dataPriv.access( src ); + pdataCur = dataPriv.set( dest, pdataOld ); + events = pdataOld.events; + + if ( events ) { + delete pdataCur.handle; + pdataCur.events = {}; + + for ( type in events ) { + for ( i = 0, l = events[ type ].length; i < l; i++ ) { + jQuery.event.add( dest, type, events[ type ][ i ] ); + } + } + } + } + + // 2. Copy user data + if ( dataUser.hasData( src ) ) { + udataOld = dataUser.access( src ); + udataCur = jQuery.extend( {}, udataOld ); + + dataUser.set( dest, udataCur ); + } +} + +// Fix IE bugs, see support tests +function fixInput( src, dest ) { + var nodeName = dest.nodeName.toLowerCase(); + + // Fails to persist the checked state of a cloned checkbox or radio button. + if ( nodeName === "input" && rcheckableType.test( src.type ) ) { + dest.checked = src.checked; + + // Fails to return the selected option to the default selected state when cloning options + } else if ( nodeName === "input" || nodeName === "textarea" ) { + dest.defaultValue = src.defaultValue; + } +} + +function domManip( collection, args, callback, ignored ) { + + // Flatten any nested arrays + args = concat.apply( [], args ); + + var fragment, first, scripts, hasScripts, node, doc, + i = 0, + l = collection.length, + iNoClone = l - 1, + value = args[ 0 ], + isFunction = jQuery.isFunction( value ); + + // We can't cloneNode fragments that contain checked, in WebKit + if ( isFunction || + ( l > 1 && typeof value === "string" && + !support.checkClone && rchecked.test( value ) ) ) { + return collection.each( function( index ) { + var self = collection.eq( index ); + if ( isFunction ) { + args[ 0 ] = value.call( this, index, self.html() ); + } + domManip( self, args, callback, ignored ); + } ); + } + + if ( l ) { + fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored ); + first = fragment.firstChild; + + if ( fragment.childNodes.length === 1 ) { + fragment = first; + } + + // Require either new content or an interest in ignored elements to invoke the callback + if ( first || ignored ) { + scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); + hasScripts = scripts.length; + + // Use the original fragment for the last item + // instead of the first because it can end up + // being emptied incorrectly in certain situations (#8070). + for ( ; i < l; i++ ) { + node = fragment; + + if ( i !== iNoClone ) { + node = jQuery.clone( node, true, true ); + + // Keep references to cloned scripts for later restoration + if ( hasScripts ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( scripts, getAll( node, "script" ) ); + } + } + + callback.call( collection[ i ], node, i ); + } + + if ( hasScripts ) { + doc = scripts[ scripts.length - 1 ].ownerDocument; + + // Reenable scripts + jQuery.map( scripts, restoreScript ); + + // Evaluate executable scripts on first document insertion + for ( i = 0; i < hasScripts; i++ ) { + node = scripts[ i ]; + if ( rscriptType.test( node.type || "" ) && + !dataPriv.access( node, "globalEval" ) && + jQuery.contains( doc, node ) ) { + + if ( node.src ) { + + // Optional AJAX dependency, but won't run scripts if not present + if ( jQuery._evalUrl ) { + jQuery._evalUrl( node.src ); + } + } else { + DOMEval( node.textContent.replace( rcleanScript, "" ), doc ); + } + } + } + } + } + } + + return collection; +} + +function remove( elem, selector, keepData ) { + var node, + nodes = selector ? jQuery.filter( selector, elem ) : elem, + i = 0; + + for ( ; ( node = nodes[ i ] ) != null; i++ ) { + if ( !keepData && node.nodeType === 1 ) { + jQuery.cleanData( getAll( node ) ); + } + + if ( node.parentNode ) { + if ( keepData && jQuery.contains( node.ownerDocument, node ) ) { + setGlobalEval( getAll( node, "script" ) ); + } + node.parentNode.removeChild( node ); + } + } + + return elem; +} + +jQuery.extend( { + htmlPrefilter: function( html ) { + return html.replace( rxhtmlTag, "<$1>" ); + }, + + clone: function( elem, dataAndEvents, deepDataAndEvents ) { + var i, l, srcElements, destElements, + clone = elem.cloneNode( true ), + inPage = jQuery.contains( elem.ownerDocument, elem ); + + // Fix IE cloning issues + if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) && + !jQuery.isXMLDoc( elem ) ) { + + // We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2 + destElements = getAll( clone ); + srcElements = getAll( elem ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + fixInput( srcElements[ i ], destElements[ i ] ); + } + } + + // Copy the events from the original to the clone + if ( dataAndEvents ) { + if ( deepDataAndEvents ) { + srcElements = srcElements || getAll( elem ); + destElements = destElements || getAll( clone ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + cloneCopyEvent( srcElements[ i ], destElements[ i ] ); + } + } else { + cloneCopyEvent( elem, clone ); + } + } + + // Preserve script evaluation history + destElements = getAll( clone, "script" ); + if ( destElements.length > 0 ) { + setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); + } + + // Return the cloned set + return clone; + }, + + cleanData: function( elems ) { + var data, elem, type, + special = jQuery.event.special, + i = 0; + + for ( ; ( elem = elems[ i ] ) !== undefined; i++ ) { + if ( acceptData( elem ) ) { + if ( ( data = elem[ dataPriv.expando ] ) ) { + if ( data.events ) { + for ( type in data.events ) { + if ( special[ type ] ) { + jQuery.event.remove( elem, type ); + + // This is a shortcut to avoid jQuery.event.remove's overhead + } else { + jQuery.removeEvent( elem, type, data.handle ); + } + } + } + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataPriv.expando ] = undefined; + } + if ( elem[ dataUser.expando ] ) { + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataUser.expando ] = undefined; + } + } + } + } +} ); + +jQuery.fn.extend( { + detach: function( selector ) { + return remove( this, selector, true ); + }, + + remove: function( selector ) { + return remove( this, selector ); + }, + + text: function( value ) { + return access( this, function( value ) { + return value === undefined ? + jQuery.text( this ) : + this.empty().each( function() { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + this.textContent = value; + } + } ); + }, null, value, arguments.length ); + }, + + append: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.appendChild( elem ); + } + } ); + }, + + prepend: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.insertBefore( elem, target.firstChild ); + } + } ); + }, + + before: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this ); + } + } ); + }, + + after: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this.nextSibling ); + } + } ); + }, + + empty: function() { + var elem, + i = 0; + + for ( ; ( elem = this[ i ] ) != null; i++ ) { + if ( elem.nodeType === 1 ) { + + // Prevent memory leaks + jQuery.cleanData( getAll( elem, false ) ); + + // Remove any remaining nodes + elem.textContent = ""; + } + } + + return this; + }, + + clone: function( dataAndEvents, deepDataAndEvents ) { + dataAndEvents = dataAndEvents == null ? false : dataAndEvents; + deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; + + return this.map( function() { + return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); + } ); + }, + + html: function( value ) { + return access( this, function( value ) { + var elem = this[ 0 ] || {}, + i = 0, + l = this.length; + + if ( value === undefined && elem.nodeType === 1 ) { + return elem.innerHTML; + } + + // See if we can take a shortcut and just use innerHTML + if ( typeof value === "string" && !rnoInnerhtml.test( value ) && + !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) { + + value = jQuery.htmlPrefilter( value ); + + try { + for ( ; i < l; i++ ) { + elem = this[ i ] || {}; + + // Remove element nodes and prevent memory leaks + if ( elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem, false ) ); + elem.innerHTML = value; + } + } + + elem = 0; + + // If using innerHTML throws an exception, use the fallback method + } catch ( e ) {} + } + + if ( elem ) { + this.empty().append( value ); + } + }, null, value, arguments.length ); + }, + + replaceWith: function() { + var ignored = []; + + // Make the changes, replacing each non-ignored context element with the new content + return domManip( this, arguments, function( elem ) { + var parent = this.parentNode; + + if ( jQuery.inArray( this, ignored ) < 0 ) { + jQuery.cleanData( getAll( this ) ); + if ( parent ) { + parent.replaceChild( elem, this ); + } + } + + // Force callback invocation + }, ignored ); + } +} ); + +jQuery.each( { + appendTo: "append", + prependTo: "prepend", + insertBefore: "before", + insertAfter: "after", + replaceAll: "replaceWith" +}, function( name, original ) { + jQuery.fn[ name ] = function( selector ) { + var elems, + ret = [], + insert = jQuery( selector ), + last = insert.length - 1, + i = 0; + + for ( ; i <= last; i++ ) { + elems = i === last ? this : this.clone( true ); + jQuery( insert[ i ] )[ original ]( elems ); + + // Support: Android <=4.0 only, PhantomJS 1 only + // .get() because push.apply(_, arraylike) throws on ancient WebKit + push.apply( ret, elems.get() ); + } + + return this.pushStack( ret ); + }; +} ); +var rmargin = ( /^margin/ ); + +var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" ); + +var getStyles = function( elem ) { + + // Support: IE <=11 only, Firefox <=30 (#15098, #14150) + // IE throws on elements created in popups + // FF meanwhile throws on frame elements through "defaultView.getComputedStyle" + var view = elem.ownerDocument.defaultView; + + if ( !view || !view.opener ) { + view = window; + } + + return view.getComputedStyle( elem ); + }; + + + +( function() { + + // Executing both pixelPosition & boxSizingReliable tests require only one layout + // so they're executed at the same time to save the second computation. + function computeStyleTests() { + + // This is a singleton, we need to execute it only once + if ( !div ) { + return; + } + + div.style.cssText = + "box-sizing:border-box;" + + "position:relative;display:block;" + + "margin:auto;border:1px;padding:1px;" + + "top:1%;width:50%"; + div.innerHTML = ""; + documentElement.appendChild( container ); + + var divStyle = window.getComputedStyle( div ); + pixelPositionVal = divStyle.top !== "1%"; + + // Support: Android 4.0 - 4.3 only, Firefox <=3 - 44 + reliableMarginLeftVal = divStyle.marginLeft === "2px"; + boxSizingReliableVal = divStyle.width === "4px"; + + // Support: Android 4.0 - 4.3 only + // Some styles come back with percentage values, even though they shouldn't + div.style.marginRight = "50%"; + pixelMarginRightVal = divStyle.marginRight === "4px"; + + documentElement.removeChild( container ); + + // Nullify the div so it wouldn't be stored in the memory and + // it will also be a sign that checks already performed + div = null; + } + + var pixelPositionVal, boxSizingReliableVal, pixelMarginRightVal, reliableMarginLeftVal, + container = document.createElement( "div" ), + div = document.createElement( "div" ); + + // Finish early in limited (non-browser) environments + if ( !div.style ) { + return; + } + + // Support: IE <=9 - 11 only + // Style of cloned element affects source element cloned (#8908) + div.style.backgroundClip = "content-box"; + div.cloneNode( true ).style.backgroundClip = ""; + support.clearCloneStyle = div.style.backgroundClip === "content-box"; + + container.style.cssText = "border:0;width:8px;height:0;top:0;left:-9999px;" + + "padding:0;margin-top:1px;position:absolute"; + container.appendChild( div ); + + jQuery.extend( support, { + pixelPosition: function() { + computeStyleTests(); + return pixelPositionVal; + }, + boxSizingReliable: function() { + computeStyleTests(); + return boxSizingReliableVal; + }, + pixelMarginRight: function() { + computeStyleTests(); + return pixelMarginRightVal; + }, + reliableMarginLeft: function() { + computeStyleTests(); + return reliableMarginLeftVal; + } + } ); +} )(); + + +function curCSS( elem, name, computed ) { + var width, minWidth, maxWidth, ret, + + // Support: Firefox 51+ + // Retrieving style before computed somehow + // fixes an issue with getting wrong values + // on detached elements + style = elem.style; + + computed = computed || getStyles( elem ); + + // getPropertyValue is needed for: + // .css('filter') (IE 9 only, #12537) + // .css('--customProperty) (#3144) + if ( computed ) { + ret = computed.getPropertyValue( name ) || computed[ name ]; + + if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) { + ret = jQuery.style( elem, name ); + } + + // A tribute to the "awesome hack by Dean Edwards" + // Android Browser returns percentage for some values, + // but width seems to be reliably pixels. + // This is against the CSSOM draft spec: + // https://drafts.csswg.org/cssom/#resolved-values + if ( !support.pixelMarginRight() && rnumnonpx.test( ret ) && rmargin.test( name ) ) { + + // Remember the original values + width = style.width; + minWidth = style.minWidth; + maxWidth = style.maxWidth; + + // Put in the new values to get a computed value out + style.minWidth = style.maxWidth = style.width = ret; + ret = computed.width; + + // Revert the changed values + style.width = width; + style.minWidth = minWidth; + style.maxWidth = maxWidth; + } + } + + return ret !== undefined ? + + // Support: IE <=9 - 11 only + // IE returns zIndex value as an integer. + ret + "" : + ret; +} + + +function addGetHookIf( conditionFn, hookFn ) { + + // Define the hook, we'll check on the first run if it's really needed. + return { + get: function() { + if ( conditionFn() ) { + + // Hook not needed (or it's not possible to use it due + // to missing dependency), remove it. + delete this.get; + return; + } + + // Hook needed; redefine it so that the support test is not executed again. + return ( this.get = hookFn ).apply( this, arguments ); + } + }; +} + + +var + + // Swappable if display is none or starts with table + // except "table", "table-cell", or "table-caption" + // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display + rdisplayswap = /^(none|table(?!-c[ea]).+)/, + rcustomProp = /^--/, + cssShow = { position: "absolute", visibility: "hidden", display: "block" }, + cssNormalTransform = { + letterSpacing: "0", + fontWeight: "400" + }, + + cssPrefixes = [ "Webkit", "Moz", "ms" ], + emptyStyle = document.createElement( "div" ).style; + +// Return a css property mapped to a potentially vendor prefixed property +function vendorPropName( name ) { + + // Shortcut for names that are not vendor prefixed + if ( name in emptyStyle ) { + return name; + } + + // Check for vendor prefixed names + var capName = name[ 0 ].toUpperCase() + name.slice( 1 ), + i = cssPrefixes.length; + + while ( i-- ) { + name = cssPrefixes[ i ] + capName; + if ( name in emptyStyle ) { + return name; + } + } +} + +// Return a property mapped along what jQuery.cssProps suggests or to +// a vendor prefixed property. +function finalPropName( name ) { + var ret = jQuery.cssProps[ name ]; + if ( !ret ) { + ret = jQuery.cssProps[ name ] = vendorPropName( name ) || name; + } + return ret; +} + +function setPositiveNumber( elem, value, subtract ) { + + // Any relative (+/-) values have already been + // normalized at this point + var matches = rcssNum.exec( value ); + return matches ? + + // Guard against undefined "subtract", e.g., when used as in cssHooks + Math.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || "px" ) : + value; +} + +function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) { + var i, + val = 0; + + // If we already have the right measurement, avoid augmentation + if ( extra === ( isBorderBox ? "border" : "content" ) ) { + i = 4; + + // Otherwise initialize for horizontal or vertical properties + } else { + i = name === "width" ? 1 : 0; + } + + for ( ; i < 4; i += 2 ) { + + // Both box models exclude margin, so add it if we want it + if ( extra === "margin" ) { + val += jQuery.css( elem, extra + cssExpand[ i ], true, styles ); + } + + if ( isBorderBox ) { + + // border-box includes padding, so remove it if we want content + if ( extra === "content" ) { + val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + } + + // At this point, extra isn't border nor margin, so remove border + if ( extra !== "margin" ) { + val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + } else { + + // At this point, extra isn't content, so add padding + val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + + // At this point, extra isn't content nor padding, so add border + if ( extra !== "padding" ) { + val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + } + } + + return val; +} + +function getWidthOrHeight( elem, name, extra ) { + + // Start with computed style + var valueIsBorderBox, + styles = getStyles( elem ), + val = curCSS( elem, name, styles ), + isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; + + // Computed unit is not pixels. Stop here and return. + if ( rnumnonpx.test( val ) ) { + return val; + } + + // Check for style in case a browser which returns unreliable values + // for getComputedStyle silently falls back to the reliable elem.style + valueIsBorderBox = isBorderBox && + ( support.boxSizingReliable() || val === elem.style[ name ] ); + + // Fall back to offsetWidth/Height when value is "auto" + // This happens for inline elements with no explicit setting (gh-3571) + if ( val === "auto" ) { + val = elem[ "offset" + name[ 0 ].toUpperCase() + name.slice( 1 ) ]; + } + + // Normalize "", auto, and prepare for extra + val = parseFloat( val ) || 0; + + // Use the active box-sizing model to add/subtract irrelevant styles + return ( val + + augmentWidthOrHeight( + elem, + name, + extra || ( isBorderBox ? "border" : "content" ), + valueIsBorderBox, + styles + ) + ) + "px"; +} + +jQuery.extend( { + + // Add in style property hooks for overriding the default + // behavior of getting and setting a style property + cssHooks: { + opacity: { + get: function( elem, computed ) { + if ( computed ) { + + // We should always get a number back from opacity + var ret = curCSS( elem, "opacity" ); + return ret === "" ? "1" : ret; + } + } + } + }, + + // Don't automatically add "px" to these possibly-unitless properties + cssNumber: { + "animationIterationCount": true, + "columnCount": true, + "fillOpacity": true, + "flexGrow": true, + "flexShrink": true, + "fontWeight": true, + "lineHeight": true, + "opacity": true, + "order": true, + "orphans": true, + "widows": true, + "zIndex": true, + "zoom": true + }, + + // Add in properties whose names you wish to fix before + // setting or getting the value + cssProps: { + "float": "cssFloat" + }, + + // Get and set the style property on a DOM Node + style: function( elem, name, value, extra ) { + + // Don't set styles on text and comment nodes + if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { + return; + } + + // Make sure that we're working with the right name + var ret, type, hooks, + origName = jQuery.camelCase( name ), + isCustomProp = rcustomProp.test( name ), + style = elem.style; + + // Make sure that we're working with the right name. We don't + // want to query the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } + + // Gets hook for the prefixed version, then unprefixed version + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // Check if we're setting a value + if ( value !== undefined ) { + type = typeof value; + + // Convert "+=" or "-=" to relative numbers (#7345) + if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) { + value = adjustCSS( elem, name, ret ); + + // Fixes bug #9237 + type = "number"; + } + + // Make sure that null and NaN values aren't set (#7116) + if ( value == null || value !== value ) { + return; + } + + // If a number was passed in, add the unit (except for certain CSS properties) + if ( type === "number" ) { + value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" ); + } + + // background-* props affect original clone's values + if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) { + style[ name ] = "inherit"; + } + + // If a hook was provided, use that value, otherwise just set the specified value + if ( !hooks || !( "set" in hooks ) || + ( value = hooks.set( elem, value, extra ) ) !== undefined ) { + + if ( isCustomProp ) { + style.setProperty( name, value ); + } else { + style[ name ] = value; + } + } + + } else { + + // If a hook was provided get the non-computed value from there + if ( hooks && "get" in hooks && + ( ret = hooks.get( elem, false, extra ) ) !== undefined ) { + + return ret; + } + + // Otherwise just get the value from the style object + return style[ name ]; + } + }, + + css: function( elem, name, extra, styles ) { + var val, num, hooks, + origName = jQuery.camelCase( name ), + isCustomProp = rcustomProp.test( name ); + + // Make sure that we're working with the right name. We don't + // want to modify the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } + + // Try prefixed name followed by the unprefixed name + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // If a hook was provided get the computed value from there + if ( hooks && "get" in hooks ) { + val = hooks.get( elem, true, extra ); + } + + // Otherwise, if a way to get the computed value exists, use that + if ( val === undefined ) { + val = curCSS( elem, name, styles ); + } + + // Convert "normal" to computed value + if ( val === "normal" && name in cssNormalTransform ) { + val = cssNormalTransform[ name ]; + } + + // Make numeric if forced or a qualifier was provided and val looks numeric + if ( extra === "" || extra ) { + num = parseFloat( val ); + return extra === true || isFinite( num ) ? num || 0 : val; + } + + return val; + } +} ); + +jQuery.each( [ "height", "width" ], function( i, name ) { + jQuery.cssHooks[ name ] = { + get: function( elem, computed, extra ) { + if ( computed ) { + + // Certain elements can have dimension info if we invisibly show them + // but it must have a current display style that would benefit + return rdisplayswap.test( jQuery.css( elem, "display" ) ) && + + // Support: Safari 8+ + // Table columns in Safari have non-zero offsetWidth & zero + // getBoundingClientRect().width unless display is changed. + // Support: IE <=11 only + // Running getBoundingClientRect on a disconnected node + // in IE throws an error. + ( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ? + swap( elem, cssShow, function() { + return getWidthOrHeight( elem, name, extra ); + } ) : + getWidthOrHeight( elem, name, extra ); + } + }, + + set: function( elem, value, extra ) { + var matches, + styles = extra && getStyles( elem ), + subtract = extra && augmentWidthOrHeight( + elem, + name, + extra, + jQuery.css( elem, "boxSizing", false, styles ) === "border-box", + styles + ); + + // Convert to pixels if value adjustment is needed + if ( subtract && ( matches = rcssNum.exec( value ) ) && + ( matches[ 3 ] || "px" ) !== "px" ) { + + elem.style[ name ] = value; + value = jQuery.css( elem, name ); + } + + return setPositiveNumber( elem, value, subtract ); + } + }; +} ); + +jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft, + function( elem, computed ) { + if ( computed ) { + return ( parseFloat( curCSS( elem, "marginLeft" ) ) || + elem.getBoundingClientRect().left - + swap( elem, { marginLeft: 0 }, function() { + return elem.getBoundingClientRect().left; + } ) + ) + "px"; + } + } +); + +// These hooks are used by animate to expand properties +jQuery.each( { + margin: "", + padding: "", + border: "Width" +}, function( prefix, suffix ) { + jQuery.cssHooks[ prefix + suffix ] = { + expand: function( value ) { + var i = 0, + expanded = {}, + + // Assumes a single number if not a string + parts = typeof value === "string" ? value.split( " " ) : [ value ]; + + for ( ; i < 4; i++ ) { + expanded[ prefix + cssExpand[ i ] + suffix ] = + parts[ i ] || parts[ i - 2 ] || parts[ 0 ]; + } + + return expanded; + } + }; + + if ( !rmargin.test( prefix ) ) { + jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber; + } +} ); + +jQuery.fn.extend( { + css: function( name, value ) { + return access( this, function( elem, name, value ) { + var styles, len, + map = {}, + i = 0; + + if ( Array.isArray( name ) ) { + styles = getStyles( elem ); + len = name.length; + + for ( ; i < len; i++ ) { + map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles ); + } + + return map; + } + + return value !== undefined ? + jQuery.style( elem, name, value ) : + jQuery.css( elem, name ); + }, name, value, arguments.length > 1 ); + } +} ); + + +function Tween( elem, options, prop, end, easing ) { + return new Tween.prototype.init( elem, options, prop, end, easing ); +} +jQuery.Tween = Tween; + +Tween.prototype = { + constructor: Tween, + init: function( elem, options, prop, end, easing, unit ) { + this.elem = elem; + this.prop = prop; + this.easing = easing || jQuery.easing._default; + this.options = options; + this.start = this.now = this.cur(); + this.end = end; + this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" ); + }, + cur: function() { + var hooks = Tween.propHooks[ this.prop ]; + + return hooks && hooks.get ? + hooks.get( this ) : + Tween.propHooks._default.get( this ); + }, + run: function( percent ) { + var eased, + hooks = Tween.propHooks[ this.prop ]; + + if ( this.options.duration ) { + this.pos = eased = jQuery.easing[ this.easing ]( + percent, this.options.duration * percent, 0, 1, this.options.duration + ); + } else { + this.pos = eased = percent; + } + this.now = ( this.end - this.start ) * eased + this.start; + + if ( this.options.step ) { + this.options.step.call( this.elem, this.now, this ); + } + + if ( hooks && hooks.set ) { + hooks.set( this ); + } else { + Tween.propHooks._default.set( this ); + } + return this; + } +}; + +Tween.prototype.init.prototype = Tween.prototype; + +Tween.propHooks = { + _default: { + get: function( tween ) { + var result; + + // Use a property on the element directly when it is not a DOM element, + // or when there is no matching style property that exists. + if ( tween.elem.nodeType !== 1 || + tween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) { + return tween.elem[ tween.prop ]; + } + + // Passing an empty string as a 3rd parameter to .css will automatically + // attempt a parseFloat and fallback to a string if the parse fails. + // Simple values such as "10px" are parsed to Float; + // complex values such as "rotate(1rad)" are returned as-is. + result = jQuery.css( tween.elem, tween.prop, "" ); + + // Empty strings, null, undefined and "auto" are converted to 0. + return !result || result === "auto" ? 0 : result; + }, + set: function( tween ) { + + // Use step hook for back compat. + // Use cssHook if its there. + // Use .style if available and use plain properties where available. + if ( jQuery.fx.step[ tween.prop ] ) { + jQuery.fx.step[ tween.prop ]( tween ); + } else if ( tween.elem.nodeType === 1 && + ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || + jQuery.cssHooks[ tween.prop ] ) ) { + jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); + } else { + tween.elem[ tween.prop ] = tween.now; + } + } + } +}; + +// Support: IE <=9 only +// Panic based approach to setting things on disconnected nodes +Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = { + set: function( tween ) { + if ( tween.elem.nodeType && tween.elem.parentNode ) { + tween.elem[ tween.prop ] = tween.now; + } + } +}; + +jQuery.easing = { + linear: function( p ) { + return p; + }, + swing: function( p ) { + return 0.5 - Math.cos( p * Math.PI ) / 2; + }, + _default: "swing" +}; + +jQuery.fx = Tween.prototype.init; + +// Back compat <1.8 extension point +jQuery.fx.step = {}; + + + + +var + fxNow, inProgress, + rfxtypes = /^(?:toggle|show|hide)$/, + rrun = /queueHooks$/; + +function schedule() { + if ( inProgress ) { + if ( document.hidden === false && window.requestAnimationFrame ) { + window.requestAnimationFrame( schedule ); + } else { + window.setTimeout( schedule, jQuery.fx.interval ); + } + + jQuery.fx.tick(); + } +} + +// Animations created synchronously will run synchronously +function createFxNow() { + window.setTimeout( function() { + fxNow = undefined; + } ); + return ( fxNow = jQuery.now() ); +} + +// Generate parameters to create a standard animation +function genFx( type, includeWidth ) { + var which, + i = 0, + attrs = { height: type }; + + // If we include width, step value is 1 to do all cssExpand values, + // otherwise step value is 2 to skip over Left and Right + includeWidth = includeWidth ? 1 : 0; + for ( ; i < 4; i += 2 - includeWidth ) { + which = cssExpand[ i ]; + attrs[ "margin" + which ] = attrs[ "padding" + which ] = type; + } + + if ( includeWidth ) { + attrs.opacity = attrs.width = type; + } + + return attrs; +} + +function createTween( value, prop, animation ) { + var tween, + collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ "*" ] ), + index = 0, + length = collection.length; + for ( ; index < length; index++ ) { + if ( ( tween = collection[ index ].call( animation, prop, value ) ) ) { + + // We're done with this property + return tween; + } + } +} + +function defaultPrefilter( elem, props, opts ) { + var prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display, + isBox = "width" in props || "height" in props, + anim = this, + orig = {}, + style = elem.style, + hidden = elem.nodeType && isHiddenWithinTree( elem ), + dataShow = dataPriv.get( elem, "fxshow" ); + + // Queue-skipping animations hijack the fx hooks + if ( !opts.queue ) { + hooks = jQuery._queueHooks( elem, "fx" ); + if ( hooks.unqueued == null ) { + hooks.unqueued = 0; + oldfire = hooks.empty.fire; + hooks.empty.fire = function() { + if ( !hooks.unqueued ) { + oldfire(); + } + }; + } + hooks.unqueued++; + + anim.always( function() { + + // Ensure the complete handler is called before this completes + anim.always( function() { + hooks.unqueued--; + if ( !jQuery.queue( elem, "fx" ).length ) { + hooks.empty.fire(); + } + } ); + } ); + } + + // Detect show/hide animations + for ( prop in props ) { + value = props[ prop ]; + if ( rfxtypes.test( value ) ) { + delete props[ prop ]; + toggle = toggle || value === "toggle"; + if ( value === ( hidden ? "hide" : "show" ) ) { + + // Pretend to be hidden if this is a "show" and + // there is still data from a stopped show/hide + if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) { + hidden = true; + + // Ignore all other no-op show/hide data + } else { + continue; + } + } + orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop ); + } + } + + // Bail out if this is a no-op like .hide().hide() + propTween = !jQuery.isEmptyObject( props ); + if ( !propTween && jQuery.isEmptyObject( orig ) ) { + return; + } + + // Restrict "overflow" and "display" styles during box animations + if ( isBox && elem.nodeType === 1 ) { + + // Support: IE <=9 - 11, Edge 12 - 13 + // Record all 3 overflow attributes because IE does not infer the shorthand + // from identically-valued overflowX and overflowY + opts.overflow = [ style.overflow, style.overflowX, style.overflowY ]; + + // Identify a display type, preferring old show/hide data over the CSS cascade + restoreDisplay = dataShow && dataShow.display; + if ( restoreDisplay == null ) { + restoreDisplay = dataPriv.get( elem, "display" ); + } + display = jQuery.css( elem, "display" ); + if ( display === "none" ) { + if ( restoreDisplay ) { + display = restoreDisplay; + } else { + + // Get nonempty value(s) by temporarily forcing visibility + showHide( [ elem ], true ); + restoreDisplay = elem.style.display || restoreDisplay; + display = jQuery.css( elem, "display" ); + showHide( [ elem ] ); + } + } + + // Animate inline elements as inline-block + if ( display === "inline" || display === "inline-block" && restoreDisplay != null ) { + if ( jQuery.css( elem, "float" ) === "none" ) { + + // Restore the original display value at the end of pure show/hide animations + if ( !propTween ) { + anim.done( function() { + style.display = restoreDisplay; + } ); + if ( restoreDisplay == null ) { + display = style.display; + restoreDisplay = display === "none" ? "" : display; + } + } + style.display = "inline-block"; + } + } + } + + if ( opts.overflow ) { + style.overflow = "hidden"; + anim.always( function() { + style.overflow = opts.overflow[ 0 ]; + style.overflowX = opts.overflow[ 1 ]; + style.overflowY = opts.overflow[ 2 ]; + } ); + } + + // Implement show/hide animations + propTween = false; + for ( prop in orig ) { + + // General show/hide setup for this element animation + if ( !propTween ) { + if ( dataShow ) { + if ( "hidden" in dataShow ) { + hidden = dataShow.hidden; + } + } else { + dataShow = dataPriv.access( elem, "fxshow", { display: restoreDisplay } ); + } + + // Store hidden/visible for toggle so `.stop().toggle()` "reverses" + if ( toggle ) { + dataShow.hidden = !hidden; + } + + // Show elements before animating them + if ( hidden ) { + showHide( [ elem ], true ); + } + + /* eslint-disable no-loop-func */ + + anim.done( function() { + + /* eslint-enable no-loop-func */ + + // The final step of a "hide" animation is actually hiding the element + if ( !hidden ) { + showHide( [ elem ] ); + } + dataPriv.remove( elem, "fxshow" ); + for ( prop in orig ) { + jQuery.style( elem, prop, orig[ prop ] ); + } + } ); + } + + // Per-property setup + propTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim ); + if ( !( prop in dataShow ) ) { + dataShow[ prop ] = propTween.start; + if ( hidden ) { + propTween.end = propTween.start; + propTween.start = 0; + } + } + } +} + +function propFilter( props, specialEasing ) { + var index, name, easing, value, hooks; + + // camelCase, specialEasing and expand cssHook pass + for ( index in props ) { + name = jQuery.camelCase( index ); + easing = specialEasing[ name ]; + value = props[ index ]; + if ( Array.isArray( value ) ) { + easing = value[ 1 ]; + value = props[ index ] = value[ 0 ]; + } + + if ( index !== name ) { + props[ name ] = value; + delete props[ index ]; + } + + hooks = jQuery.cssHooks[ name ]; + if ( hooks && "expand" in hooks ) { + value = hooks.expand( value ); + delete props[ name ]; + + // Not quite $.extend, this won't overwrite existing keys. + // Reusing 'index' because we have the correct "name" + for ( index in value ) { + if ( !( index in props ) ) { + props[ index ] = value[ index ]; + specialEasing[ index ] = easing; + } + } + } else { + specialEasing[ name ] = easing; + } + } +} + +function Animation( elem, properties, options ) { + var result, + stopped, + index = 0, + length = Animation.prefilters.length, + deferred = jQuery.Deferred().always( function() { + + // Don't match elem in the :animated selector + delete tick.elem; + } ), + tick = function() { + if ( stopped ) { + return false; + } + var currentTime = fxNow || createFxNow(), + remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ), + + // Support: Android 2.3 only + // Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497) + temp = remaining / animation.duration || 0, + percent = 1 - temp, + index = 0, + length = animation.tweens.length; + + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( percent ); + } + + deferred.notifyWith( elem, [ animation, percent, remaining ] ); + + // If there's more to do, yield + if ( percent < 1 && length ) { + return remaining; + } + + // If this was an empty animation, synthesize a final progress notification + if ( !length ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + } + + // Resolve the animation and report its conclusion + deferred.resolveWith( elem, [ animation ] ); + return false; + }, + animation = deferred.promise( { + elem: elem, + props: jQuery.extend( {}, properties ), + opts: jQuery.extend( true, { + specialEasing: {}, + easing: jQuery.easing._default + }, options ), + originalProperties: properties, + originalOptions: options, + startTime: fxNow || createFxNow(), + duration: options.duration, + tweens: [], + createTween: function( prop, end ) { + var tween = jQuery.Tween( elem, animation.opts, prop, end, + animation.opts.specialEasing[ prop ] || animation.opts.easing ); + animation.tweens.push( tween ); + return tween; + }, + stop: function( gotoEnd ) { + var index = 0, + + // If we are going to the end, we want to run all the tweens + // otherwise we skip this part + length = gotoEnd ? animation.tweens.length : 0; + if ( stopped ) { + return this; + } + stopped = true; + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( 1 ); + } + + // Resolve when we played the last frame; otherwise, reject + if ( gotoEnd ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + deferred.resolveWith( elem, [ animation, gotoEnd ] ); + } else { + deferred.rejectWith( elem, [ animation, gotoEnd ] ); + } + return this; + } + } ), + props = animation.props; + + propFilter( props, animation.opts.specialEasing ); + + for ( ; index < length; index++ ) { + result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts ); + if ( result ) { + if ( jQuery.isFunction( result.stop ) ) { + jQuery._queueHooks( animation.elem, animation.opts.queue ).stop = + jQuery.proxy( result.stop, result ); + } + return result; + } + } + + jQuery.map( props, createTween, animation ); + + if ( jQuery.isFunction( animation.opts.start ) ) { + animation.opts.start.call( elem, animation ); + } + + // Attach callbacks from options + animation + .progress( animation.opts.progress ) + .done( animation.opts.done, animation.opts.complete ) + .fail( animation.opts.fail ) + .always( animation.opts.always ); + + jQuery.fx.timer( + jQuery.extend( tick, { + elem: elem, + anim: animation, + queue: animation.opts.queue + } ) + ); + + return animation; +} + +jQuery.Animation = jQuery.extend( Animation, { + + tweeners: { + "*": [ function( prop, value ) { + var tween = this.createTween( prop, value ); + adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween ); + return tween; + } ] + }, + + tweener: function( props, callback ) { + if ( jQuery.isFunction( props ) ) { + callback = props; + props = [ "*" ]; + } else { + props = props.match( rnothtmlwhite ); + } + + var prop, + index = 0, + length = props.length; + + for ( ; index < length; index++ ) { + prop = props[ index ]; + Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || []; + Animation.tweeners[ prop ].unshift( callback ); + } + }, + + prefilters: [ defaultPrefilter ], + + prefilter: function( callback, prepend ) { + if ( prepend ) { + Animation.prefilters.unshift( callback ); + } else { + Animation.prefilters.push( callback ); + } + } +} ); + +jQuery.speed = function( speed, easing, fn ) { + var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : { + complete: fn || !fn && easing || + jQuery.isFunction( speed ) && speed, + duration: speed, + easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing + }; + + // Go to the end state if fx are off + if ( jQuery.fx.off ) { + opt.duration = 0; + + } else { + if ( typeof opt.duration !== "number" ) { + if ( opt.duration in jQuery.fx.speeds ) { + opt.duration = jQuery.fx.speeds[ opt.duration ]; + + } else { + opt.duration = jQuery.fx.speeds._default; + } + } + } + + // Normalize opt.queue - true/undefined/null -> "fx" + if ( opt.queue == null || opt.queue === true ) { + opt.queue = "fx"; + } + + // Queueing + opt.old = opt.complete; + + opt.complete = function() { + if ( jQuery.isFunction( opt.old ) ) { + opt.old.call( this ); + } + + if ( opt.queue ) { + jQuery.dequeue( this, opt.queue ); + } + }; + + return opt; +}; + +jQuery.fn.extend( { + fadeTo: function( speed, to, easing, callback ) { + + // Show any hidden elements after setting opacity to 0 + return this.filter( isHiddenWithinTree ).css( "opacity", 0 ).show() + + // Animate to the value specified + .end().animate( { opacity: to }, speed, easing, callback ); + }, + animate: function( prop, speed, easing, callback ) { + var empty = jQuery.isEmptyObject( prop ), + optall = jQuery.speed( speed, easing, callback ), + doAnimation = function() { + + // Operate on a copy of prop so per-property easing won't be lost + var anim = Animation( this, jQuery.extend( {}, prop ), optall ); + + // Empty animations, or finishing resolves immediately + if ( empty || dataPriv.get( this, "finish" ) ) { + anim.stop( true ); + } + }; + doAnimation.finish = doAnimation; + + return empty || optall.queue === false ? + this.each( doAnimation ) : + this.queue( optall.queue, doAnimation ); + }, + stop: function( type, clearQueue, gotoEnd ) { + var stopQueue = function( hooks ) { + var stop = hooks.stop; + delete hooks.stop; + stop( gotoEnd ); + }; + + if ( typeof type !== "string" ) { + gotoEnd = clearQueue; + clearQueue = type; + type = undefined; + } + if ( clearQueue && type !== false ) { + this.queue( type || "fx", [] ); + } + + return this.each( function() { + var dequeue = true, + index = type != null && type + "queueHooks", + timers = jQuery.timers, + data = dataPriv.get( this ); + + if ( index ) { + if ( data[ index ] && data[ index ].stop ) { + stopQueue( data[ index ] ); + } + } else { + for ( index in data ) { + if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) { + stopQueue( data[ index ] ); + } + } + } + + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && + ( type == null || timers[ index ].queue === type ) ) { + + timers[ index ].anim.stop( gotoEnd ); + dequeue = false; + timers.splice( index, 1 ); + } + } + + // Start the next in the queue if the last step wasn't forced. + // Timers currently will call their complete callbacks, which + // will dequeue but only if they were gotoEnd. + if ( dequeue || !gotoEnd ) { + jQuery.dequeue( this, type ); + } + } ); + }, + finish: function( type ) { + if ( type !== false ) { + type = type || "fx"; + } + return this.each( function() { + var index, + data = dataPriv.get( this ), + queue = data[ type + "queue" ], + hooks = data[ type + "queueHooks" ], + timers = jQuery.timers, + length = queue ? queue.length : 0; + + // Enable finishing flag on private data + data.finish = true; + + // Empty the queue first + jQuery.queue( this, type, [] ); + + if ( hooks && hooks.stop ) { + hooks.stop.call( this, true ); + } + + // Look for any active animations, and finish them + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && timers[ index ].queue === type ) { + timers[ index ].anim.stop( true ); + timers.splice( index, 1 ); + } + } + + // Look for any animations in the old queue and finish them + for ( index = 0; index < length; index++ ) { + if ( queue[ index ] && queue[ index ].finish ) { + queue[ index ].finish.call( this ); + } + } + + // Turn off finishing flag + delete data.finish; + } ); + } +} ); + +jQuery.each( [ "toggle", "show", "hide" ], function( i, name ) { + var cssFn = jQuery.fn[ name ]; + jQuery.fn[ name ] = function( speed, easing, callback ) { + return speed == null || typeof speed === "boolean" ? + cssFn.apply( this, arguments ) : + this.animate( genFx( name, true ), speed, easing, callback ); + }; +} ); + +// Generate shortcuts for custom animations +jQuery.each( { + slideDown: genFx( "show" ), + slideUp: genFx( "hide" ), + slideToggle: genFx( "toggle" ), + fadeIn: { opacity: "show" }, + fadeOut: { opacity: "hide" }, + fadeToggle: { opacity: "toggle" } +}, function( name, props ) { + jQuery.fn[ name ] = function( speed, easing, callback ) { + return this.animate( props, speed, easing, callback ); + }; +} ); + +jQuery.timers = []; +jQuery.fx.tick = function() { + var timer, + i = 0, + timers = jQuery.timers; + + fxNow = jQuery.now(); + + for ( ; i < timers.length; i++ ) { + timer = timers[ i ]; + + // Run the timer and safely remove it when done (allowing for external removal) + if ( !timer() && timers[ i ] === timer ) { + timers.splice( i--, 1 ); + } + } + + if ( !timers.length ) { + jQuery.fx.stop(); + } + fxNow = undefined; +}; + +jQuery.fx.timer = function( timer ) { + jQuery.timers.push( timer ); + jQuery.fx.start(); +}; + +jQuery.fx.interval = 13; +jQuery.fx.start = function() { + if ( inProgress ) { + return; + } + + inProgress = true; + schedule(); +}; + +jQuery.fx.stop = function() { + inProgress = null; +}; + +jQuery.fx.speeds = { + slow: 600, + fast: 200, + + // Default speed + _default: 400 +}; + + +// Based off of the plugin by Clint Helfers, with permission. +// https://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/ +jQuery.fn.delay = function( time, type ) { + time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; + type = type || "fx"; + + return this.queue( type, function( next, hooks ) { + var timeout = window.setTimeout( next, time ); + hooks.stop = function() { + window.clearTimeout( timeout ); + }; + } ); +}; + + +( function() { + var input = document.createElement( "input" ), + select = document.createElement( "select" ), + opt = select.appendChild( document.createElement( "option" ) ); + + input.type = "checkbox"; + + // Support: Android <=4.3 only + // Default value for a checkbox should be "on" + support.checkOn = input.value !== ""; + + // Support: IE <=11 only + // Must access selectedIndex to make default options select + support.optSelected = opt.selected; + + // Support: IE <=11 only + // An input loses its value after becoming a radio + input = document.createElement( "input" ); + input.value = "t"; + input.type = "radio"; + support.radioValue = input.value === "t"; +} )(); + + +var boolHook, + attrHandle = jQuery.expr.attrHandle; + +jQuery.fn.extend( { + attr: function( name, value ) { + return access( this, jQuery.attr, name, value, arguments.length > 1 ); + }, + + removeAttr: function( name ) { + return this.each( function() { + jQuery.removeAttr( this, name ); + } ); + } +} ); + +jQuery.extend( { + attr: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set attributes on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + // Fallback to prop when attributes are not supported + if ( typeof elem.getAttribute === "undefined" ) { + return jQuery.prop( elem, name, value ); + } + + // Attribute hooks are determined by the lowercase version + // Grab necessary hook if one is defined + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + hooks = jQuery.attrHooks[ name.toLowerCase() ] || + ( jQuery.expr.match.bool.test( name ) ? boolHook : undefined ); + } + + if ( value !== undefined ) { + if ( value === null ) { + jQuery.removeAttr( elem, name ); + return; + } + + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + elem.setAttribute( name, value + "" ); + return value; + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + ret = jQuery.find.attr( elem, name ); + + // Non-existent attributes return null, we normalize to undefined + return ret == null ? undefined : ret; + }, + + attrHooks: { + type: { + set: function( elem, value ) { + if ( !support.radioValue && value === "radio" && + nodeName( elem, "input" ) ) { + var val = elem.value; + elem.setAttribute( "type", value ); + if ( val ) { + elem.value = val; + } + return value; + } + } + } + }, + + removeAttr: function( elem, value ) { + var name, + i = 0, + + // Attribute names can contain non-HTML whitespace characters + // https://html.spec.whatwg.org/multipage/syntax.html#attributes-2 + attrNames = value && value.match( rnothtmlwhite ); + + if ( attrNames && elem.nodeType === 1 ) { + while ( ( name = attrNames[ i++ ] ) ) { + elem.removeAttribute( name ); + } + } + } +} ); + +// Hooks for boolean attributes +boolHook = { + set: function( elem, value, name ) { + if ( value === false ) { + + // Remove boolean attributes when set to false + jQuery.removeAttr( elem, name ); + } else { + elem.setAttribute( name, name ); + } + return name; + } +}; + +jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( i, name ) { + var getter = attrHandle[ name ] || jQuery.find.attr; + + attrHandle[ name ] = function( elem, name, isXML ) { + var ret, handle, + lowercaseName = name.toLowerCase(); + + if ( !isXML ) { + + // Avoid an infinite loop by temporarily removing this function from the getter + handle = attrHandle[ lowercaseName ]; + attrHandle[ lowercaseName ] = ret; + ret = getter( elem, name, isXML ) != null ? + lowercaseName : + null; + attrHandle[ lowercaseName ] = handle; + } + return ret; + }; +} ); + + + + +var rfocusable = /^(?:input|select|textarea|button)$/i, + rclickable = /^(?:a|area)$/i; + +jQuery.fn.extend( { + prop: function( name, value ) { + return access( this, jQuery.prop, name, value, arguments.length > 1 ); + }, + + removeProp: function( name ) { + return this.each( function() { + delete this[ jQuery.propFix[ name ] || name ]; + } ); + } +} ); + +jQuery.extend( { + prop: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set properties on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + + // Fix name and attach hooks + name = jQuery.propFix[ name ] || name; + hooks = jQuery.propHooks[ name ]; + } + + if ( value !== undefined ) { + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + return ( elem[ name ] = value ); + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + return elem[ name ]; + }, + + propHooks: { + tabIndex: { + get: function( elem ) { + + // Support: IE <=9 - 11 only + // elem.tabIndex doesn't always return the + // correct value when it hasn't been explicitly set + // https://web.archive.org/web/20141116233347/http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ + // Use proper attribute retrieval(#12072) + var tabindex = jQuery.find.attr( elem, "tabindex" ); + + if ( tabindex ) { + return parseInt( tabindex, 10 ); + } + + if ( + rfocusable.test( elem.nodeName ) || + rclickable.test( elem.nodeName ) && + elem.href + ) { + return 0; + } + + return -1; + } + } + }, + + propFix: { + "for": "htmlFor", + "class": "className" + } +} ); + +// Support: IE <=11 only +// Accessing the selectedIndex property +// forces the browser to respect setting selected +// on the option +// The getter ensures a default option is selected +// when in an optgroup +// eslint rule "no-unused-expressions" is disabled for this code +// since it considers such accessions noop +if ( !support.optSelected ) { + jQuery.propHooks.selected = { + get: function( elem ) { + + /* eslint no-unused-expressions: "off" */ + + var parent = elem.parentNode; + if ( parent && parent.parentNode ) { + parent.parentNode.selectedIndex; + } + return null; + }, + set: function( elem ) { + + /* eslint no-unused-expressions: "off" */ + + var parent = elem.parentNode; + if ( parent ) { + parent.selectedIndex; + + if ( parent.parentNode ) { + parent.parentNode.selectedIndex; + } + } + } + }; +} + +jQuery.each( [ + "tabIndex", + "readOnly", + "maxLength", + "cellSpacing", + "cellPadding", + "rowSpan", + "colSpan", + "useMap", + "frameBorder", + "contentEditable" +], function() { + jQuery.propFix[ this.toLowerCase() ] = this; +} ); + + + + + // Strip and collapse whitespace according to HTML spec + // https://html.spec.whatwg.org/multipage/infrastructure.html#strip-and-collapse-whitespace + function stripAndCollapse( value ) { + var tokens = value.match( rnothtmlwhite ) || []; + return tokens.join( " " ); + } + + +function getClass( elem ) { + return elem.getAttribute && elem.getAttribute( "class" ) || ""; +} + +jQuery.fn.extend( { + addClass: function( value ) { + var classes, elem, cur, curValue, clazz, j, finalValue, + i = 0; + + if ( jQuery.isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).addClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + if ( typeof value === "string" && value ) { + classes = value.match( rnothtmlwhite ) || []; + + while ( ( elem = this[ i++ ] ) ) { + curValue = getClass( elem ); + cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + + if ( cur ) { + j = 0; + while ( ( clazz = classes[ j++ ] ) ) { + if ( cur.indexOf( " " + clazz + " " ) < 0 ) { + cur += clazz + " "; + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse( cur ); + if ( curValue !== finalValue ) { + elem.setAttribute( "class", finalValue ); + } + } + } + } + + return this; + }, + + removeClass: function( value ) { + var classes, elem, cur, curValue, clazz, j, finalValue, + i = 0; + + if ( jQuery.isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + if ( !arguments.length ) { + return this.attr( "class", "" ); + } + + if ( typeof value === "string" && value ) { + classes = value.match( rnothtmlwhite ) || []; + + while ( ( elem = this[ i++ ] ) ) { + curValue = getClass( elem ); + + // This expression is here for better compressibility (see addClass) + cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + + if ( cur ) { + j = 0; + while ( ( clazz = classes[ j++ ] ) ) { + + // Remove *all* instances + while ( cur.indexOf( " " + clazz + " " ) > -1 ) { + cur = cur.replace( " " + clazz + " ", " " ); + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse( cur ); + if ( curValue !== finalValue ) { + elem.setAttribute( "class", finalValue ); + } + } + } + } + + return this; + }, + + toggleClass: function( value, stateVal ) { + var type = typeof value; + + if ( typeof stateVal === "boolean" && type === "string" ) { + return stateVal ? this.addClass( value ) : this.removeClass( value ); + } + + if ( jQuery.isFunction( value ) ) { + return this.each( function( i ) { + jQuery( this ).toggleClass( + value.call( this, i, getClass( this ), stateVal ), + stateVal + ); + } ); + } + + return this.each( function() { + var className, i, self, classNames; + + if ( type === "string" ) { + + // Toggle individual class names + i = 0; + self = jQuery( this ); + classNames = value.match( rnothtmlwhite ) || []; + + while ( ( className = classNames[ i++ ] ) ) { + + // Check each className given, space separated list + if ( self.hasClass( className ) ) { + self.removeClass( className ); + } else { + self.addClass( className ); + } + } + + // Toggle whole class name + } else if ( value === undefined || type === "boolean" ) { + className = getClass( this ); + if ( className ) { + + // Store className if set + dataPriv.set( this, "__className__", className ); + } + + // If the element has a class name or if we're passed `false`, + // then remove the whole classname (if there was one, the above saved it). + // Otherwise bring back whatever was previously saved (if anything), + // falling back to the empty string if nothing was stored. + if ( this.setAttribute ) { + this.setAttribute( "class", + className || value === false ? + "" : + dataPriv.get( this, "__className__" ) || "" + ); + } + } + } ); + }, + + hasClass: function( selector ) { + var className, elem, + i = 0; + + className = " " + selector + " "; + while ( ( elem = this[ i++ ] ) ) { + if ( elem.nodeType === 1 && + ( " " + stripAndCollapse( getClass( elem ) ) + " " ).indexOf( className ) > -1 ) { + return true; + } + } + + return false; + } +} ); + + + + +var rreturn = /\r/g; + +jQuery.fn.extend( { + val: function( value ) { + var hooks, ret, isFunction, + elem = this[ 0 ]; + + if ( !arguments.length ) { + if ( elem ) { + hooks = jQuery.valHooks[ elem.type ] || + jQuery.valHooks[ elem.nodeName.toLowerCase() ]; + + if ( hooks && + "get" in hooks && + ( ret = hooks.get( elem, "value" ) ) !== undefined + ) { + return ret; + } + + ret = elem.value; + + // Handle most common string cases + if ( typeof ret === "string" ) { + return ret.replace( rreturn, "" ); + } + + // Handle cases where value is null/undef or number + return ret == null ? "" : ret; + } + + return; + } + + isFunction = jQuery.isFunction( value ); + + return this.each( function( i ) { + var val; + + if ( this.nodeType !== 1 ) { + return; + } + + if ( isFunction ) { + val = value.call( this, i, jQuery( this ).val() ); + } else { + val = value; + } + + // Treat null/undefined as ""; convert numbers to string + if ( val == null ) { + val = ""; + + } else if ( typeof val === "number" ) { + val += ""; + + } else if ( Array.isArray( val ) ) { + val = jQuery.map( val, function( value ) { + return value == null ? "" : value + ""; + } ); + } + + hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; + + // If set returns undefined, fall back to normal setting + if ( !hooks || !( "set" in hooks ) || hooks.set( this, val, "value" ) === undefined ) { + this.value = val; + } + } ); + } +} ); + +jQuery.extend( { + valHooks: { + option: { + get: function( elem ) { + + var val = jQuery.find.attr( elem, "value" ); + return val != null ? + val : + + // Support: IE <=10 - 11 only + // option.text throws exceptions (#14686, #14858) + // Strip and collapse whitespace + // https://html.spec.whatwg.org/#strip-and-collapse-whitespace + stripAndCollapse( jQuery.text( elem ) ); + } + }, + select: { + get: function( elem ) { + var value, option, i, + options = elem.options, + index = elem.selectedIndex, + one = elem.type === "select-one", + values = one ? null : [], + max = one ? index + 1 : options.length; + + if ( index < 0 ) { + i = max; + + } else { + i = one ? index : 0; + } + + // Loop through all the selected options + for ( ; i < max; i++ ) { + option = options[ i ]; + + // Support: IE <=9 only + // IE8-9 doesn't update selected after form reset (#2551) + if ( ( option.selected || i === index ) && + + // Don't return options that are disabled or in a disabled optgroup + !option.disabled && + ( !option.parentNode.disabled || + !nodeName( option.parentNode, "optgroup" ) ) ) { + + // Get the specific value for the option + value = jQuery( option ).val(); + + // We don't need an array for one selects + if ( one ) { + return value; + } + + // Multi-Selects return an array + values.push( value ); + } + } + + return values; + }, + + set: function( elem, value ) { + var optionSet, option, + options = elem.options, + values = jQuery.makeArray( value ), + i = options.length; + + while ( i-- ) { + option = options[ i ]; + + /* eslint-disable no-cond-assign */ + + if ( option.selected = + jQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1 + ) { + optionSet = true; + } + + /* eslint-enable no-cond-assign */ + } + + // Force browsers to behave consistently when non-matching value is set + if ( !optionSet ) { + elem.selectedIndex = -1; + } + return values; + } + } + } +} ); + +// Radios and checkboxes getter/setter +jQuery.each( [ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = { + set: function( elem, value ) { + if ( Array.isArray( value ) ) { + return ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 ); + } + } + }; + if ( !support.checkOn ) { + jQuery.valHooks[ this ].get = function( elem ) { + return elem.getAttribute( "value" ) === null ? "on" : elem.value; + }; + } +} ); + + + + +// Return jQuery for attributes-only inclusion + + +var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/; + +jQuery.extend( jQuery.event, { + + trigger: function( event, data, elem, onlyHandlers ) { + + var i, cur, tmp, bubbleType, ontype, handle, special, + eventPath = [ elem || document ], + type = hasOwn.call( event, "type" ) ? event.type : event, + namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : []; + + cur = tmp = elem = elem || document; + + // Don't do events on text and comment nodes + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + // focus/blur morphs to focusin/out; ensure we're not firing them right now + if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { + return; + } + + if ( type.indexOf( "." ) > -1 ) { + + // Namespaced trigger; create a regexp to match event type in handle() + namespaces = type.split( "." ); + type = namespaces.shift(); + namespaces.sort(); + } + ontype = type.indexOf( ":" ) < 0 && "on" + type; + + // Caller can pass in a jQuery.Event object, Object, or just an event type string + event = event[ jQuery.expando ] ? + event : + new jQuery.Event( type, typeof event === "object" && event ); + + // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) + event.isTrigger = onlyHandlers ? 2 : 3; + event.namespace = namespaces.join( "." ); + event.rnamespace = event.namespace ? + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) : + null; + + // Clean up the event in case it is being reused + event.result = undefined; + if ( !event.target ) { + event.target = elem; + } + + // Clone any incoming data and prepend the event, creating the handler arg list + data = data == null ? + [ event ] : + jQuery.makeArray( data, [ event ] ); + + // Allow special events to draw outside the lines + special = jQuery.event.special[ type ] || {}; + if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { + return; + } + + // Determine event propagation path in advance, per W3C events spec (#9951) + // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) + if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { + + bubbleType = special.delegateType || type; + if ( !rfocusMorph.test( bubbleType + type ) ) { + cur = cur.parentNode; + } + for ( ; cur; cur = cur.parentNode ) { + eventPath.push( cur ); + tmp = cur; + } + + // Only add window if we got to document (e.g., not plain obj or detached DOM) + if ( tmp === ( elem.ownerDocument || document ) ) { + eventPath.push( tmp.defaultView || tmp.parentWindow || window ); + } + } + + // Fire handlers on the event path + i = 0; + while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) { + + event.type = i > 1 ? + bubbleType : + special.bindType || type; + + // jQuery handler + handle = ( dataPriv.get( cur, "events" ) || {} )[ event.type ] && + dataPriv.get( cur, "handle" ); + if ( handle ) { + handle.apply( cur, data ); + } + + // Native handler + handle = ontype && cur[ ontype ]; + if ( handle && handle.apply && acceptData( cur ) ) { + event.result = handle.apply( cur, data ); + if ( event.result === false ) { + event.preventDefault(); + } + } + } + event.type = type; + + // If nobody prevented the default action, do it now + if ( !onlyHandlers && !event.isDefaultPrevented() ) { + + if ( ( !special._default || + special._default.apply( eventPath.pop(), data ) === false ) && + acceptData( elem ) ) { + + // Call a native DOM method on the target with the same name as the event. + // Don't do default actions on window, that's where global variables be (#6170) + if ( ontype && jQuery.isFunction( elem[ type ] ) && !jQuery.isWindow( elem ) ) { + + // Don't re-trigger an onFOO event when we call its FOO() method + tmp = elem[ ontype ]; + + if ( tmp ) { + elem[ ontype ] = null; + } + + // Prevent re-triggering of the same event, since we already bubbled it above + jQuery.event.triggered = type; + elem[ type ](); + jQuery.event.triggered = undefined; + + if ( tmp ) { + elem[ ontype ] = tmp; + } + } + } + } + + return event.result; + }, + + // Piggyback on a donor event to simulate a different one + // Used only for `focus(in | out)` events + simulate: function( type, elem, event ) { + var e = jQuery.extend( + new jQuery.Event(), + event, + { + type: type, + isSimulated: true + } + ); + + jQuery.event.trigger( e, null, elem ); + } + +} ); + +jQuery.fn.extend( { + + trigger: function( type, data ) { + return this.each( function() { + jQuery.event.trigger( type, data, this ); + } ); + }, + triggerHandler: function( type, data ) { + var elem = this[ 0 ]; + if ( elem ) { + return jQuery.event.trigger( type, data, elem, true ); + } + } +} ); + + +jQuery.each( ( "blur focus focusin focusout resize scroll click dblclick " + + "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + + "change select submit keydown keypress keyup contextmenu" ).split( " " ), + function( i, name ) { + + // Handle event binding + jQuery.fn[ name ] = function( data, fn ) { + return arguments.length > 0 ? + this.on( name, null, data, fn ) : + this.trigger( name ); + }; +} ); + +jQuery.fn.extend( { + hover: function( fnOver, fnOut ) { + return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); + } +} ); + + + + +support.focusin = "onfocusin" in window; + + +// Support: Firefox <=44 +// Firefox doesn't have focus(in | out) events +// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787 +// +// Support: Chrome <=48 - 49, Safari <=9.0 - 9.1 +// focus(in | out) events fire after focus & blur events, +// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order +// Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857 +if ( !support.focusin ) { + jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) { + + // Attach a single capturing handler on the document while someone wants focusin/focusout + var handler = function( event ) { + jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) ); + }; + + jQuery.event.special[ fix ] = { + setup: function() { + var doc = this.ownerDocument || this, + attaches = dataPriv.access( doc, fix ); + + if ( !attaches ) { + doc.addEventListener( orig, handler, true ); + } + dataPriv.access( doc, fix, ( attaches || 0 ) + 1 ); + }, + teardown: function() { + var doc = this.ownerDocument || this, + attaches = dataPriv.access( doc, fix ) - 1; + + if ( !attaches ) { + doc.removeEventListener( orig, handler, true ); + dataPriv.remove( doc, fix ); + + } else { + dataPriv.access( doc, fix, attaches ); + } + } + }; + } ); +} +var location = window.location; + +var nonce = jQuery.now(); + +var rquery = ( /\?/ ); + + + +// Cross-browser xml parsing +jQuery.parseXML = function( data ) { + var xml; + if ( !data || typeof data !== "string" ) { + return null; + } + + // Support: IE 9 - 11 only + // IE throws on parseFromString with invalid input. + try { + xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" ); + } catch ( e ) { + xml = undefined; + } + + if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) { + jQuery.error( "Invalid XML: " + data ); + } + return xml; +}; + + +var + rbracket = /\[\]$/, + rCRLF = /\r?\n/g, + rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i, + rsubmittable = /^(?:input|select|textarea|keygen)/i; + +function buildParams( prefix, obj, traditional, add ) { + var name; + + if ( Array.isArray( obj ) ) { + + // Serialize array item. + jQuery.each( obj, function( i, v ) { + if ( traditional || rbracket.test( prefix ) ) { + + // Treat each array item as a scalar. + add( prefix, v ); + + } else { + + // Item is non-scalar (array or object), encode its numeric index. + buildParams( + prefix + "[" + ( typeof v === "object" && v != null ? i : "" ) + "]", + v, + traditional, + add + ); + } + } ); + + } else if ( !traditional && jQuery.type( obj ) === "object" ) { + + // Serialize object item. + for ( name in obj ) { + buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); + } + + } else { + + // Serialize scalar item. + add( prefix, obj ); + } +} + +// Serialize an array of form elements or a set of +// key/values into a query string +jQuery.param = function( a, traditional ) { + var prefix, + s = [], + add = function( key, valueOrFunction ) { + + // If value is a function, invoke it and use its return value + var value = jQuery.isFunction( valueOrFunction ) ? + valueOrFunction() : + valueOrFunction; + + s[ s.length ] = encodeURIComponent( key ) + "=" + + encodeURIComponent( value == null ? "" : value ); + }; + + // If an array was passed in, assume that it is an array of form elements. + if ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { + + // Serialize the form elements + jQuery.each( a, function() { + add( this.name, this.value ); + } ); + + } else { + + // If traditional, encode the "old" way (the way 1.3.2 or older + // did it), otherwise encode params recursively. + for ( prefix in a ) { + buildParams( prefix, a[ prefix ], traditional, add ); + } + } + + // Return the resulting serialization + return s.join( "&" ); +}; + +jQuery.fn.extend( { + serialize: function() { + return jQuery.param( this.serializeArray() ); + }, + serializeArray: function() { + return this.map( function() { + + // Can add propHook for "elements" to filter or add form elements + var elements = jQuery.prop( this, "elements" ); + return elements ? jQuery.makeArray( elements ) : this; + } ) + .filter( function() { + var type = this.type; + + // Use .is( ":disabled" ) so that fieldset[disabled] works + return this.name && !jQuery( this ).is( ":disabled" ) && + rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) && + ( this.checked || !rcheckableType.test( type ) ); + } ) + .map( function( i, elem ) { + var val = jQuery( this ).val(); + + if ( val == null ) { + return null; + } + + if ( Array.isArray( val ) ) { + return jQuery.map( val, function( val ) { + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ); + } + + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ).get(); + } +} ); + + +var + r20 = /%20/g, + rhash = /#.*$/, + rantiCache = /([?&])_=[^&]*/, + rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg, + + // #7653, #8125, #8152: local protocol detection + rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/, + rnoContent = /^(?:GET|HEAD)$/, + rprotocol = /^\/\//, + + /* Prefilters + * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example) + * 2) These are called: + * - BEFORE asking for a transport + * - AFTER param serialization (s.data is a string if s.processData is true) + * 3) key is the dataType + * 4) the catchall symbol "*" can be used + * 5) execution will start with transport dataType and THEN continue down to "*" if needed + */ + prefilters = {}, + + /* Transports bindings + * 1) key is the dataType + * 2) the catchall symbol "*" can be used + * 3) selection will start with transport dataType and THEN go to "*" if needed + */ + transports = {}, + + // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression + allTypes = "*/".concat( "*" ), + + // Anchor tag for parsing the document origin + originAnchor = document.createElement( "a" ); + originAnchor.href = location.href; + +// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport +function addToPrefiltersOrTransports( structure ) { + + // dataTypeExpression is optional and defaults to "*" + return function( dataTypeExpression, func ) { + + if ( typeof dataTypeExpression !== "string" ) { + func = dataTypeExpression; + dataTypeExpression = "*"; + } + + var dataType, + i = 0, + dataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || []; + + if ( jQuery.isFunction( func ) ) { + + // For each dataType in the dataTypeExpression + while ( ( dataType = dataTypes[ i++ ] ) ) { + + // Prepend if requested + if ( dataType[ 0 ] === "+" ) { + dataType = dataType.slice( 1 ) || "*"; + ( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func ); + + // Otherwise append + } else { + ( structure[ dataType ] = structure[ dataType ] || [] ).push( func ); + } + } + } + }; +} + +// Base inspection function for prefilters and transports +function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) { + + var inspected = {}, + seekingTransport = ( structure === transports ); + + function inspect( dataType ) { + var selected; + inspected[ dataType ] = true; + jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) { + var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR ); + if ( typeof dataTypeOrTransport === "string" && + !seekingTransport && !inspected[ dataTypeOrTransport ] ) { + + options.dataTypes.unshift( dataTypeOrTransport ); + inspect( dataTypeOrTransport ); + return false; + } else if ( seekingTransport ) { + return !( selected = dataTypeOrTransport ); + } + } ); + return selected; + } + + return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" ); +} + +// A special extend for ajax options +// that takes "flat" options (not to be deep extended) +// Fixes #9887 +function ajaxExtend( target, src ) { + var key, deep, + flatOptions = jQuery.ajaxSettings.flatOptions || {}; + + for ( key in src ) { + if ( src[ key ] !== undefined ) { + ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ]; + } + } + if ( deep ) { + jQuery.extend( true, target, deep ); + } + + return target; +} + +/* Handles responses to an ajax request: + * - finds the right dataType (mediates between content-type and expected dataType) + * - returns the corresponding response + */ +function ajaxHandleResponses( s, jqXHR, responses ) { + + var ct, type, finalDataType, firstDataType, + contents = s.contents, + dataTypes = s.dataTypes; + + // Remove auto dataType and get content-type in the process + while ( dataTypes[ 0 ] === "*" ) { + dataTypes.shift(); + if ( ct === undefined ) { + ct = s.mimeType || jqXHR.getResponseHeader( "Content-Type" ); + } + } + + // Check if we're dealing with a known content-type + if ( ct ) { + for ( type in contents ) { + if ( contents[ type ] && contents[ type ].test( ct ) ) { + dataTypes.unshift( type ); + break; + } + } + } + + // Check to see if we have a response for the expected dataType + if ( dataTypes[ 0 ] in responses ) { + finalDataType = dataTypes[ 0 ]; + } else { + + // Try convertible dataTypes + for ( type in responses ) { + if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[ 0 ] ] ) { + finalDataType = type; + break; + } + if ( !firstDataType ) { + firstDataType = type; + } + } + + // Or just use first one + finalDataType = finalDataType || firstDataType; + } + + // If we found a dataType + // We add the dataType to the list if needed + // and return the corresponding response + if ( finalDataType ) { + if ( finalDataType !== dataTypes[ 0 ] ) { + dataTypes.unshift( finalDataType ); + } + return responses[ finalDataType ]; + } +} + +/* Chain conversions given the request and the original response + * Also sets the responseXXX fields on the jqXHR instance + */ +function ajaxConvert( s, response, jqXHR, isSuccess ) { + var conv2, current, conv, tmp, prev, + converters = {}, + + // Work with a copy of dataTypes in case we need to modify it for conversion + dataTypes = s.dataTypes.slice(); + + // Create converters map with lowercased keys + if ( dataTypes[ 1 ] ) { + for ( conv in s.converters ) { + converters[ conv.toLowerCase() ] = s.converters[ conv ]; + } + } + + current = dataTypes.shift(); + + // Convert to each sequential dataType + while ( current ) { + + if ( s.responseFields[ current ] ) { + jqXHR[ s.responseFields[ current ] ] = response; + } + + // Apply the dataFilter if provided + if ( !prev && isSuccess && s.dataFilter ) { + response = s.dataFilter( response, s.dataType ); + } + + prev = current; + current = dataTypes.shift(); + + if ( current ) { + + // There's only work to do if current dataType is non-auto + if ( current === "*" ) { + + current = prev; + + // Convert response if prev dataType is non-auto and differs from current + } else if ( prev !== "*" && prev !== current ) { + + // Seek a direct converter + conv = converters[ prev + " " + current ] || converters[ "* " + current ]; + + // If none found, seek a pair + if ( !conv ) { + for ( conv2 in converters ) { + + // If conv2 outputs current + tmp = conv2.split( " " ); + if ( tmp[ 1 ] === current ) { + + // If prev can be converted to accepted input + conv = converters[ prev + " " + tmp[ 0 ] ] || + converters[ "* " + tmp[ 0 ] ]; + if ( conv ) { + + // Condense equivalence converters + if ( conv === true ) { + conv = converters[ conv2 ]; + + // Otherwise, insert the intermediate dataType + } else if ( converters[ conv2 ] !== true ) { + current = tmp[ 0 ]; + dataTypes.unshift( tmp[ 1 ] ); + } + break; + } + } + } + } + + // Apply converter (if not an equivalence) + if ( conv !== true ) { + + // Unless errors are allowed to bubble, catch and return them + if ( conv && s.throws ) { + response = conv( response ); + } else { + try { + response = conv( response ); + } catch ( e ) { + return { + state: "parsererror", + error: conv ? e : "No conversion from " + prev + " to " + current + }; + } + } + } + } + } + } + + return { state: "success", data: response }; +} + +jQuery.extend( { + + // Counter for holding the number of active queries + active: 0, + + // Last-Modified header cache for next request + lastModified: {}, + etag: {}, + + ajaxSettings: { + url: location.href, + type: "GET", + isLocal: rlocalProtocol.test( location.protocol ), + global: true, + processData: true, + async: true, + contentType: "application/x-www-form-urlencoded; charset=UTF-8", + + /* + timeout: 0, + data: null, + dataType: null, + username: null, + password: null, + cache: null, + throws: false, + traditional: false, + headers: {}, + */ + + accepts: { + "*": allTypes, + text: "text/plain", + html: "text/html", + xml: "application/xml, text/xml", + json: "application/json, text/javascript" + }, + + contents: { + xml: /\bxml\b/, + html: /\bhtml/, + json: /\bjson\b/ + }, + + responseFields: { + xml: "responseXML", + text: "responseText", + json: "responseJSON" + }, + + // Data converters + // Keys separate source (or catchall "*") and destination types with a single space + converters: { + + // Convert anything to text + "* text": String, + + // Text to html (true = no transformation) + "text html": true, + + // Evaluate text as a json expression + "text json": JSON.parse, + + // Parse text as xml + "text xml": jQuery.parseXML + }, + + // For options that shouldn't be deep extended: + // you can add your own custom options here if + // and when you create one that shouldn't be + // deep extended (see ajaxExtend) + flatOptions: { + url: true, + context: true + } + }, + + // Creates a full fledged settings object into target + // with both ajaxSettings and settings fields. + // If target is omitted, writes into ajaxSettings. + ajaxSetup: function( target, settings ) { + return settings ? + + // Building a settings object + ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) : + + // Extending ajaxSettings + ajaxExtend( jQuery.ajaxSettings, target ); + }, + + ajaxPrefilter: addToPrefiltersOrTransports( prefilters ), + ajaxTransport: addToPrefiltersOrTransports( transports ), + + // Main method + ajax: function( url, options ) { + + // If url is an object, simulate pre-1.5 signature + if ( typeof url === "object" ) { + options = url; + url = undefined; + } + + // Force options to be an object + options = options || {}; + + var transport, + + // URL without anti-cache param + cacheURL, + + // Response headers + responseHeadersString, + responseHeaders, + + // timeout handle + timeoutTimer, + + // Url cleanup var + urlAnchor, + + // Request state (becomes false upon send and true upon completion) + completed, + + // To know if global events are to be dispatched + fireGlobals, + + // Loop variable + i, + + // uncached part of the url + uncached, + + // Create the final options object + s = jQuery.ajaxSetup( {}, options ), + + // Callbacks context + callbackContext = s.context || s, + + // Context for global events is callbackContext if it is a DOM node or jQuery collection + globalEventContext = s.context && + ( callbackContext.nodeType || callbackContext.jquery ) ? + jQuery( callbackContext ) : + jQuery.event, + + // Deferreds + deferred = jQuery.Deferred(), + completeDeferred = jQuery.Callbacks( "once memory" ), + + // Status-dependent callbacks + statusCode = s.statusCode || {}, + + // Headers (they are sent all at once) + requestHeaders = {}, + requestHeadersNames = {}, + + // Default abort message + strAbort = "canceled", + + // Fake xhr + jqXHR = { + readyState: 0, + + // Builds headers hashtable if needed + getResponseHeader: function( key ) { + var match; + if ( completed ) { + if ( !responseHeaders ) { + responseHeaders = {}; + while ( ( match = rheaders.exec( responseHeadersString ) ) ) { + responseHeaders[ match[ 1 ].toLowerCase() ] = match[ 2 ]; + } + } + match = responseHeaders[ key.toLowerCase() ]; + } + return match == null ? null : match; + }, + + // Raw string + getAllResponseHeaders: function() { + return completed ? responseHeadersString : null; + }, + + // Caches the header + setRequestHeader: function( name, value ) { + if ( completed == null ) { + name = requestHeadersNames[ name.toLowerCase() ] = + requestHeadersNames[ name.toLowerCase() ] || name; + requestHeaders[ name ] = value; + } + return this; + }, + + // Overrides response content-type header + overrideMimeType: function( type ) { + if ( completed == null ) { + s.mimeType = type; + } + return this; + }, + + // Status-dependent callbacks + statusCode: function( map ) { + var code; + if ( map ) { + if ( completed ) { + + // Execute the appropriate callbacks + jqXHR.always( map[ jqXHR.status ] ); + } else { + + // Lazy-add the new callbacks in a way that preserves old ones + for ( code in map ) { + statusCode[ code ] = [ statusCode[ code ], map[ code ] ]; + } + } + } + return this; + }, + + // Cancel the request + abort: function( statusText ) { + var finalText = statusText || strAbort; + if ( transport ) { + transport.abort( finalText ); + } + done( 0, finalText ); + return this; + } + }; + + // Attach deferreds + deferred.promise( jqXHR ); + + // Add protocol if not provided (prefilters might expect it) + // Handle falsy url in the settings object (#10093: consistency with old signature) + // We also use the url parameter if available + s.url = ( ( url || s.url || location.href ) + "" ) + .replace( rprotocol, location.protocol + "//" ); + + // Alias method option to type as per ticket #12004 + s.type = options.method || options.type || s.method || s.type; + + // Extract dataTypes list + s.dataTypes = ( s.dataType || "*" ).toLowerCase().match( rnothtmlwhite ) || [ "" ]; + + // A cross-domain request is in order when the origin doesn't match the current origin. + if ( s.crossDomain == null ) { + urlAnchor = document.createElement( "a" ); + + // Support: IE <=8 - 11, Edge 12 - 13 + // IE throws exception on accessing the href property if url is malformed, + // e.g. http://example.com:80x/ + try { + urlAnchor.href = s.url; + + // Support: IE <=8 - 11 only + // Anchor's host property isn't correctly set when s.url is relative + urlAnchor.href = urlAnchor.href; + s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !== + urlAnchor.protocol + "//" + urlAnchor.host; + } catch ( e ) { + + // If there is an error parsing the URL, assume it is crossDomain, + // it can be rejected by the transport if it is invalid + s.crossDomain = true; + } + } + + // Convert data if not already a string + if ( s.data && s.processData && typeof s.data !== "string" ) { + s.data = jQuery.param( s.data, s.traditional ); + } + + // Apply prefilters + inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ); + + // If request was aborted inside a prefilter, stop there + if ( completed ) { + return jqXHR; + } + + // We can fire global events as of now if asked to + // Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118) + fireGlobals = jQuery.event && s.global; + + // Watch for a new set of requests + if ( fireGlobals && jQuery.active++ === 0 ) { + jQuery.event.trigger( "ajaxStart" ); + } + + // Uppercase the type + s.type = s.type.toUpperCase(); + + // Determine if request has content + s.hasContent = !rnoContent.test( s.type ); + + // Save the URL in case we're toying with the If-Modified-Since + // and/or If-None-Match header later on + // Remove hash to simplify url manipulation + cacheURL = s.url.replace( rhash, "" ); + + // More options handling for requests with no content + if ( !s.hasContent ) { + + // Remember the hash so we can put it back + uncached = s.url.slice( cacheURL.length ); + + // If data is available, append data to url + if ( s.data ) { + cacheURL += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data; + + // #9682: remove data so that it's not used in an eventual retry + delete s.data; + } + + // Add or update anti-cache param if needed + if ( s.cache === false ) { + cacheURL = cacheURL.replace( rantiCache, "$1" ); + uncached = ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ( nonce++ ) + uncached; + } + + // Put hash and anti-cache on the URL that will be requested (gh-1732) + s.url = cacheURL + uncached; + + // Change '%20' to '+' if this is encoded form body content (gh-2658) + } else if ( s.data && s.processData && + ( s.contentType || "" ).indexOf( "application/x-www-form-urlencoded" ) === 0 ) { + s.data = s.data.replace( r20, "+" ); + } + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + if ( jQuery.lastModified[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] ); + } + if ( jQuery.etag[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] ); + } + } + + // Set the correct header, if data is being sent + if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { + jqXHR.setRequestHeader( "Content-Type", s.contentType ); + } + + // Set the Accepts header for the server, depending on the dataType + jqXHR.setRequestHeader( + "Accept", + s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ? + s.accepts[ s.dataTypes[ 0 ] ] + + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) : + s.accepts[ "*" ] + ); + + // Check for headers option + for ( i in s.headers ) { + jqXHR.setRequestHeader( i, s.headers[ i ] ); + } + + // Allow custom headers/mimetypes and early abort + if ( s.beforeSend && + ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) { + + // Abort if not done already and return + return jqXHR.abort(); + } + + // Aborting is no longer a cancellation + strAbort = "abort"; + + // Install callbacks on deferreds + completeDeferred.add( s.complete ); + jqXHR.done( s.success ); + jqXHR.fail( s.error ); + + // Get transport + transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR ); + + // If no transport, we auto-abort + if ( !transport ) { + done( -1, "No Transport" ); + } else { + jqXHR.readyState = 1; + + // Send global event + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] ); + } + + // If request was aborted inside ajaxSend, stop there + if ( completed ) { + return jqXHR; + } + + // Timeout + if ( s.async && s.timeout > 0 ) { + timeoutTimer = window.setTimeout( function() { + jqXHR.abort( "timeout" ); + }, s.timeout ); + } + + try { + completed = false; + transport.send( requestHeaders, done ); + } catch ( e ) { + + // Rethrow post-completion exceptions + if ( completed ) { + throw e; + } + + // Propagate others as results + done( -1, e ); + } + } + + // Callback for when everything is done + function done( status, nativeStatusText, responses, headers ) { + var isSuccess, success, error, response, modified, + statusText = nativeStatusText; + + // Ignore repeat invocations + if ( completed ) { + return; + } + + completed = true; + + // Clear timeout if it exists + if ( timeoutTimer ) { + window.clearTimeout( timeoutTimer ); + } + + // Dereference transport for early garbage collection + // (no matter how long the jqXHR object will be used) + transport = undefined; + + // Cache response headers + responseHeadersString = headers || ""; + + // Set readyState + jqXHR.readyState = status > 0 ? 4 : 0; + + // Determine if successful + isSuccess = status >= 200 && status < 300 || status === 304; + + // Get response data + if ( responses ) { + response = ajaxHandleResponses( s, jqXHR, responses ); + } + + // Convert no matter what (that way responseXXX fields are always set) + response = ajaxConvert( s, response, jqXHR, isSuccess ); + + // If successful, handle type chaining + if ( isSuccess ) { + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + modified = jqXHR.getResponseHeader( "Last-Modified" ); + if ( modified ) { + jQuery.lastModified[ cacheURL ] = modified; + } + modified = jqXHR.getResponseHeader( "etag" ); + if ( modified ) { + jQuery.etag[ cacheURL ] = modified; + } + } + + // if no content + if ( status === 204 || s.type === "HEAD" ) { + statusText = "nocontent"; + + // if not modified + } else if ( status === 304 ) { + statusText = "notmodified"; + + // If we have data, let's convert it + } else { + statusText = response.state; + success = response.data; + error = response.error; + isSuccess = !error; + } + } else { + + // Extract error from statusText and normalize for non-aborts + error = statusText; + if ( status || !statusText ) { + statusText = "error"; + if ( status < 0 ) { + status = 0; + } + } + } + + // Set data for the fake xhr object + jqXHR.status = status; + jqXHR.statusText = ( nativeStatusText || statusText ) + ""; + + // Success/Error + if ( isSuccess ) { + deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] ); + } else { + deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] ); + } + + // Status-dependent callbacks + jqXHR.statusCode( statusCode ); + statusCode = undefined; + + if ( fireGlobals ) { + globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError", + [ jqXHR, s, isSuccess ? success : error ] ); + } + + // Complete + completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] ); + + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] ); + + // Handle the global AJAX counter + if ( !( --jQuery.active ) ) { + jQuery.event.trigger( "ajaxStop" ); + } + } + } + + return jqXHR; + }, + + getJSON: function( url, data, callback ) { + return jQuery.get( url, data, callback, "json" ); + }, + + getScript: function( url, callback ) { + return jQuery.get( url, undefined, callback, "script" ); + } +} ); + +jQuery.each( [ "get", "post" ], function( i, method ) { + jQuery[ method ] = function( url, data, callback, type ) { + + // Shift arguments if data argument was omitted + if ( jQuery.isFunction( data ) ) { + type = type || callback; + callback = data; + data = undefined; + } + + // The url can be an options object (which then must have .url) + return jQuery.ajax( jQuery.extend( { + url: url, + type: method, + dataType: type, + data: data, + success: callback + }, jQuery.isPlainObject( url ) && url ) ); + }; +} ); + + +jQuery._evalUrl = function( url ) { + return jQuery.ajax( { + url: url, + + // Make this explicit, since user can override this through ajaxSetup (#11264) + type: "GET", + dataType: "script", + cache: true, + async: false, + global: false, + "throws": true + } ); +}; + + +jQuery.fn.extend( { + wrapAll: function( html ) { + var wrap; + + if ( this[ 0 ] ) { + if ( jQuery.isFunction( html ) ) { + html = html.call( this[ 0 ] ); + } + + // The elements to wrap the target around + wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true ); + + if ( this[ 0 ].parentNode ) { + wrap.insertBefore( this[ 0 ] ); + } + + wrap.map( function() { + var elem = this; + + while ( elem.firstElementChild ) { + elem = elem.firstElementChild; + } + + return elem; + } ).append( this ); + } + + return this; + }, + + wrapInner: function( html ) { + if ( jQuery.isFunction( html ) ) { + return this.each( function( i ) { + jQuery( this ).wrapInner( html.call( this, i ) ); + } ); + } + + return this.each( function() { + var self = jQuery( this ), + contents = self.contents(); + + if ( contents.length ) { + contents.wrapAll( html ); + + } else { + self.append( html ); + } + } ); + }, + + wrap: function( html ) { + var isFunction = jQuery.isFunction( html ); + + return this.each( function( i ) { + jQuery( this ).wrapAll( isFunction ? html.call( this, i ) : html ); + } ); + }, + + unwrap: function( selector ) { + this.parent( selector ).not( "body" ).each( function() { + jQuery( this ).replaceWith( this.childNodes ); + } ); + return this; + } +} ); + + +jQuery.expr.pseudos.hidden = function( elem ) { + return !jQuery.expr.pseudos.visible( elem ); +}; +jQuery.expr.pseudos.visible = function( elem ) { + return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length ); +}; + + + + +jQuery.ajaxSettings.xhr = function() { + try { + return new window.XMLHttpRequest(); + } catch ( e ) {} +}; + +var xhrSuccessStatus = { + + // File protocol always yields status code 0, assume 200 + 0: 200, + + // Support: IE <=9 only + // #1450: sometimes IE returns 1223 when it should be 204 + 1223: 204 + }, + xhrSupported = jQuery.ajaxSettings.xhr(); + +support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported ); +support.ajax = xhrSupported = !!xhrSupported; + +jQuery.ajaxTransport( function( options ) { + var callback, errorCallback; + + // Cross domain only allowed if supported through XMLHttpRequest + if ( support.cors || xhrSupported && !options.crossDomain ) { + return { + send: function( headers, complete ) { + var i, + xhr = options.xhr(); + + xhr.open( + options.type, + options.url, + options.async, + options.username, + options.password + ); + + // Apply custom fields if provided + if ( options.xhrFields ) { + for ( i in options.xhrFields ) { + xhr[ i ] = options.xhrFields[ i ]; + } + } + + // Override mime type if needed + if ( options.mimeType && xhr.overrideMimeType ) { + xhr.overrideMimeType( options.mimeType ); + } + + // X-Requested-With header + // For cross-domain requests, seeing as conditions for a preflight are + // akin to a jigsaw puzzle, we simply never set it to be sure. + // (it can always be set on a per-request basis or even using ajaxSetup) + // For same-domain requests, won't change header if already provided. + if ( !options.crossDomain && !headers[ "X-Requested-With" ] ) { + headers[ "X-Requested-With" ] = "XMLHttpRequest"; + } + + // Set headers + for ( i in headers ) { + xhr.setRequestHeader( i, headers[ i ] ); + } + + // Callback + callback = function( type ) { + return function() { + if ( callback ) { + callback = errorCallback = xhr.onload = + xhr.onerror = xhr.onabort = xhr.onreadystatechange = null; + + if ( type === "abort" ) { + xhr.abort(); + } else if ( type === "error" ) { + + // Support: IE <=9 only + // On a manual native abort, IE9 throws + // errors on any property access that is not readyState + if ( typeof xhr.status !== "number" ) { + complete( 0, "error" ); + } else { + complete( + + // File: protocol always yields status 0; see #8605, #14207 + xhr.status, + xhr.statusText + ); + } + } else { + complete( + xhrSuccessStatus[ xhr.status ] || xhr.status, + xhr.statusText, + + // Support: IE <=9 only + // IE9 has no XHR2 but throws on binary (trac-11426) + // For XHR2 non-text, let the caller handle it (gh-2498) + ( xhr.responseType || "text" ) !== "text" || + typeof xhr.responseText !== "string" ? + { binary: xhr.response } : + { text: xhr.responseText }, + xhr.getAllResponseHeaders() + ); + } + } + }; + }; + + // Listen to events + xhr.onload = callback(); + errorCallback = xhr.onerror = callback( "error" ); + + // Support: IE 9 only + // Use onreadystatechange to replace onabort + // to handle uncaught aborts + if ( xhr.onabort !== undefined ) { + xhr.onabort = errorCallback; + } else { + xhr.onreadystatechange = function() { + + // Check readyState before timeout as it changes + if ( xhr.readyState === 4 ) { + + // Allow onerror to be called first, + // but that will not handle a native abort + // Also, save errorCallback to a variable + // as xhr.onerror cannot be accessed + window.setTimeout( function() { + if ( callback ) { + errorCallback(); + } + } ); + } + }; + } + + // Create the abort callback + callback = callback( "abort" ); + + try { + + // Do send the request (this may raise an exception) + xhr.send( options.hasContent && options.data || null ); + } catch ( e ) { + + // #14683: Only rethrow if this hasn't been notified as an error yet + if ( callback ) { + throw e; + } + } + }, + + abort: function() { + if ( callback ) { + callback(); + } + } + }; + } +} ); + + + + +// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432) +jQuery.ajaxPrefilter( function( s ) { + if ( s.crossDomain ) { + s.contents.script = false; + } +} ); + +// Install script dataType +jQuery.ajaxSetup( { + accepts: { + script: "text/javascript, application/javascript, " + + "application/ecmascript, application/x-ecmascript" + }, + contents: { + script: /\b(?:java|ecma)script\b/ + }, + converters: { + "text script": function( text ) { + jQuery.globalEval( text ); + return text; + } + } +} ); + +// Handle cache's special case and crossDomain +jQuery.ajaxPrefilter( "script", function( s ) { + if ( s.cache === undefined ) { + s.cache = false; + } + if ( s.crossDomain ) { + s.type = "GET"; + } +} ); + +// Bind script tag hack transport +jQuery.ajaxTransport( "script", function( s ) { + + // This transport only deals with cross domain requests + if ( s.crossDomain ) { + var script, callback; + return { + send: function( _, complete ) { + script = jQuery( " - \ No newline at end of file + From 5d6dbf72e35a568acd00e2f3076e183cd27dec48 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Thu, 24 Aug 2017 09:04:30 +0900 Subject: [PATCH 213/228] bugfix for online repl --- docs/Makefile | 2 + docs/index.html | 2 +- docs/main.go | 16 +- runtime/ilos/instance/error.go | 28 --- runtime/runtime.go | 441 +++++++++++++++------------------ runtime/util.go | 35 +++ 6 files changed, 251 insertions(+), 273 deletions(-) create mode 100644 docs/Makefile diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 0000000..8427c87 --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,2 @@ +all: + gopherjs build main.go \ No newline at end of file diff --git a/docs/index.html b/docs/index.html index 6da64f1..37d7080 100644 --- a/docs/index.html +++ b/docs/index.html @@ -9,7 +9,7 @@
- > + >
diff --git a/docs/main.go b/docs/main.go index 4e00c95..f26436f 100644 --- a/docs/main.go +++ b/docs/main.go @@ -1,6 +1,8 @@ package main import ( + "fmt" + "html" "strings" "github.com/gopherjs/jquery" @@ -21,12 +23,14 @@ func main() { tokens := tokenizer.New(reader) exp, err := parser.Parse(tokens) if err != nil { - jQuery("#history").Append("
> " + input + "
" + "
" + err.String() + "
") + jQuery("#history").Append(fmt.Sprintf("
> %v
%v
", input, html.EscapeString(err.String()))) + } else { + output, err := runtime.Eval(env, exp) + if err != nil { + jQuery("#history").Append(fmt.Sprintf("
> %v
%v
", input, html.EscapeString(err.String()))) + } else { + jQuery("#history").Append(fmt.Sprintf("
> %v
%v
", input, html.EscapeString(output.String()))) + } } - output, err := runtime.Eval(env, exp) - if err != nil { - jQuery("#history").Append("
> " + input + "
" + "
" + err.String() + "
") - } - jQuery("#history").Append("
> " + input + "
" + "
" + output.String() + "
") }) } diff --git a/runtime/ilos/instance/error.go b/runtime/ilos/instance/error.go index f35fc1e..561ade1 100644 --- a/runtime/ilos/instance/error.go +++ b/runtime/ilos/instance/error.go @@ -5,35 +5,10 @@ package instance import ( - "log" - "runtime" - "strings" - "github.com/ta2gch/iris/runtime/env" "github.com/ta2gch/iris/runtime/ilos" ) -func stackTrace() { - println("----") - programCounter, sourceFileName, sourceFileLineNum, ok := runtime.Caller(2) - log.Printf("programCounter: %v\n", programCounter) - log.Printf("souruntime: %s\n", sourceFileName) - log.Printf("sourceFileLineNum: %d\n", sourceFileLineNum) - log.Printf("ok: %t\n", ok) - - fn := runtime.FuncForPC(programCounter) - log.Printf("Function Name: %s\n", fn.Name()) - fileName, fileLine := fn.FileLine(programCounter) - log.Printf("FileName:%s, FileLine: %d\n", fileName, fileLine) - - splitedFnName := strings.Split(fn.Name(), ".") - packageName := splitedFnName[0] - callerFuncName := splitedFnName[1] - log.Printf("packageName: %s\n", packageName) - log.Printf("functionName: %s\n", callerFuncName) - println("-----") -} - func NewArithmeticError(operation, operands ilos.Instance) ilos.Instance { return Create(env.NewEnvironment(nil, nil, nil, nil), ArithmeticErrorClass, @@ -85,17 +60,14 @@ func NewUndefinedClass(name ilos.Instance) ilos.Instance { } func NewArityError() ilos.Instance { - stackTrace() return Create(env.NewEnvironment(nil, nil, nil, nil), ProgramErrorClass) } func NewIndexOutOfRange() ilos.Instance { - stackTrace() return Create(env.NewEnvironment(nil, nil, nil, nil), ProgramErrorClass) } func NewImmutableBinding() ilos.Instance { - stackTrace() return Create(env.NewEnvironment(nil, nil, nil, nil), ProgramErrorClass) } diff --git a/runtime/runtime.go b/runtime/runtime.go index 63eaa2d..89be105 100644 --- a/runtime/runtime.go +++ b/runtime/runtime.go @@ -7,9 +7,7 @@ package runtime import ( "math" "os" - "reflect" "regexp" - "runtime" "strings" "github.com/ta2gch/iris/runtime/env" @@ -17,60 +15,27 @@ import ( "github.com/ta2gch/iris/runtime/ilos/instance" ) -func func2symbol(function interface{}) ilos.Instance { - name := runtime.FuncForPC(reflect.ValueOf(function).Pointer()).Name() - name = regexp.MustCompile(`.*\.`).ReplaceAllString(name, "") - name = regexp.MustCompile(`(.)([A-Z])`).ReplaceAllString(name, "$1-$2") - name = strings.ToUpper(name) - return instance.NewSymbol(name) -} - -var TopLevel = env.NewEnvironment(instance.NewStream(os.Stdin, nil), instance.NewStream(nil, os.Stdout), instance.NewStream(nil, os.Stderr), nil) - -func defspecial(function interface{}) { - TopLevel.Special.Define(func2symbol(function), instance.NewFunction(func2symbol(function), function)) -} - -func defmacro(function interface{}) { - TopLevel.Macro.Define(func2symbol(function), instance.NewFunction(func2symbol(function), function)) -} - -func defun(function interface{}) { - TopLevel.Function.Define(func2symbol(function), instance.NewFunction(func2symbol(function), function)) -} - -func defun2(name string, function interface{}) { - symbol := instance.NewSymbol(name) - TopLevel.Function.Define(symbol, instance.NewFunction(symbol, function)) -} -func defglobal(name string, value ilos.Instance) { - symbol := instance.NewSymbol(name) - TopLevel.Variable.Define(symbol, value) -} - func New() env.Environment { toplevel := env.NewEnvironment(instance.NewStream(os.Stdin, nil), instance.NewStream(nil, os.Stdout), instance.NewStream(nil, os.Stderr), nil) - defspecial := func(function interface{}) { - toplevel.Special.Define(func2symbol(function), instance.NewFunction(func2symbol(function), function)) - } defspecial2 := func(name string, function interface{}) { symbol := instance.NewSymbol(name) toplevel.Special.Define(symbol, instance.NewFunction(func2symbol(function), function)) } - defun := func(function interface{}) { - toplevel.Function.Define(func2symbol(function), instance.NewFunction(func2symbol(function), function)) - } defun2 := func(name string, function interface{}) { + name = regexp.MustCompile(`(.)([A-Z])`).ReplaceAllString(name, "$1-$2") + name = strings.ToUpper(name) symbol := instance.NewSymbol(name) toplevel.Function.Define(symbol, instance.NewFunction(symbol, function)) } defglobal := func(name string, value ilos.Instance) { + name = regexp.MustCompile(`(.)([A-Z])`).ReplaceAllString(name, "$1-$2") + name = strings.ToUpper(name) symbol := instance.NewSymbol(name) toplevel.Variable.Define(symbol, value) } - defglobal("*PI*", instance.Float(math.Pi)) - defglobal("MOST-POSITIVE-FLOAT", MostPositiveFloat) - defglobal("MOST-NEGATIVE-FLOAT", MostNegativeFloat) + defglobal("*pi*", instance.Float(math.Pi)) + defglobal("*MostPositiveFloat*", MostPositiveFloat) + defglobal("*MostNegativeFloat*", MostNegativeFloat) defun2("-", Substruct) defun2("+", Add) defun2("*", Multiply) @@ -79,212 +44,212 @@ func New() env.Environment { defun2("=", NumberEqual) defun2(">", NumberGreaterThan) defun2(">=", NumberGreaterThanOrEqual) - defspecial(Quasiquote) - defun(Abs) - defspecial(And) - defun(Append) - defun(Apply) - defun(Aref) - defun(Assoc) - // TODO: defspecial(Assure) - defun(Atan) - defun(Atan2) - defun(Atanh) - defun2("BASIC-ARRAY*-P", BasicArrayStarP) - defun(BasicArrayP) - defun(BasicVectorP) - defspecial(Block) - defun(Car) - defspecial(Case) - defspecial(CaseUsing) - defspecial(Catch) - defun(Cdr) - defun(Ceiling) - defun(Cerror) - defun(CharIndex) + defspecial2("Quasiquote", Quasiquote) + defun2("Abs", Abs) + defspecial2("And", And) + defun2("Append", Append) + defun2("Apply", Apply) + defun2("Aref", Aref) + defun2("Assoc", Assoc) + // TODO: defspecial2("Assure", Assure) + defun2("Atan", Atan) + defun2("Atan2", Atan2) + defun2("Atanh", Atanh) + defun2("BasicArray*P", BasicArrayStarP) + defun2("BasicArrayP", BasicArrayP) + defun2("BasicVectorP", BasicVectorP) + defspecial2("Block", Block) + defun2("Car", Car) + defspecial2("Case", Case) + defspecial2("CaseUsing", CaseUsing) + defspecial2("Catch", Catch) + defun2("Cdr", Cdr) + defun2("Ceiling", Ceiling) + defun2("Cerror", Cerror) + defun2("CharIndex", CharIndex) defun2("char/=", CharNotEqual) defun2("Char<", CharLessThan) defun2("Char<=", CharLessThanOrEqual) defun2("Char=", CharEqual) defun2("Char>", CharGreaterThan) defun2("Char>=", CharGreaterThanOrEqual) - defun(Characterp) - defspecial(Class) - defun(ClassOf) - defun(Close) - // TODO defun(Coercion) - defspecial(Cond) - defun(ConditionContinuable) - defun(Cons) - defun(Consp) - defun(ContinueCondition) - // TODO defun(Convert) - defun(Cos) - defun(Cosh) - defun(Create) //TODO Change to generic function - defun(CreateArray) - defun(CreateList) - defun(CreateString) - defun(CreateStringInputStream) - defun(CreateStringOutputStream) - defun(CreateVector) - defspecial(Defclass) - defspecial(Defconstant) - defspecial(Defdynamic) - defspecial(Defgeneric) - defspecial(Defglobal) - defspecial(Defmacro) - defspecial(Defun) - defun(Div) - defspecial(Dynamic) - defspecial(DynamicLet) - defun(Elt) - defun(Eq) - defun(Eql) - defun(Equal) - defun(Error) - defun(ErrorOutput) - defun(Exp) - defun(Expt) - // TODO defun(FileLength) - // TODO defun(FilePosition) - // TODO defun(FinishOutput) - defspecial(Flet) - defun(Float) - defun(Floatp) - defun(Floor) - defspecial(For) - defun(Format) // TODO full syntax + defun2("Characterp", Characterp) + defspecial2("Class", Class) + defun2("ClassOf", ClassOf) + defun2("Close", Close) + // TODO defun2("Coercion", Coercion) + defspecial2("Cond", Cond) + defun2("ConditionContinuable", ConditionContinuable) + defun2("Cons", Cons) + defun2("Consp", Consp) + defun2("ContinueCondition", ContinueCondition) + // TODO defun2("Convert", Convert) + defun2("Cos", Cos) + defun2("Cosh", Cosh) + defun2("Create", Create) //TODO Change to generic function + defun2("CreateArray", CreateArray) + defun2("CreateList", CreateList) + defun2("CreateString", CreateString) + defun2("CreateStringInputStream", CreateStringInputStream) + defun2("CreateStringOutputStream", CreateStringOutputStream) + defun2("CreateVector", CreateVector) + defspecial2("Defclass", Defclass) + defspecial2("Defconstant", Defconstant) + defspecial2("Defdynamic", Defdynamic) + defspecial2("Defgeneric", Defgeneric) + defspecial2("Defglobal", Defglobal) + defspecial2("Defmacro", Defmacro) + defspecial2("Defun", Defun) + defun2("Div", Div) + defspecial2("Dynamic", Dynamic) + defspecial2("DynamicLet", DynamicLet) + defun2("Elt", Elt) + defun2("Eq", Eq) + defun2("Eql", Eql) + defun2("Equal", Equal) + defun2("Error", Error) + defun2("ErrorOutput", ErrorOutput) + defun2("Exp", Exp) + defun2("Expt", Expt) + // TODO defun2("FileLength", FileLength) + // TODO defun2("FilePosition", FilePosition) + // TODO defun2("FinishOutput", FinishOutput) + defspecial2("Flet", Flet) + defun2("Float", Float) + defun2("Floatp", Floatp) + defun2("Floor", Floor) + defspecial2("For", For) + defun2("Format", Format) // TODO full syntax // TODO other print function - defun(Funcall) - defspecial(Function) - defun(Functionp) - defun(Garef) - defun(Gcd) + defun2("Funcall", Funcall) + defspecial2("Function", Function) + defun2("Functionp", Functionp) + defun2("Garef", Garef) + defun2("Gcd", Gcd) defun2("GENERAL-ARRAY*-P", GeneralArrayStarP) - defun(GeneralVectorP) - // TODO defun(GenericFunctionP) - defun(Gensym) - // TODO defun(GetInternalRealTime) - // TODO defun(GetInternalRunTime) - defun(GetOutputStreamString) - // TODO defun(GetUniversalTime) - defspecial(Go) - // TODO defun(Identity) - defspecial(If) - // TODO defspecial(IgnoreErrors) - defun(InitializeObject) // TODO change generic function - defun(InputStreamP) - defun(Instancep) - // TODO defun(Integer) - defun(Integerp) - // TODO defun(InternalTimeUnitsPerSecond) - defun(Isqrt) - defspecial(Labels) - defspecial(Lambda) - defun(Lcm) - defun(Length) - defspecial(Let) + defun2("GeneralVectorP", GeneralVectorP) + // TODO defun2("GenericFunctionP", GenericFunctionP) + defun2("Gensym", Gensym) + // TODO defun2("GetInternalRealTime", GetInternalRealTime) + // TODO defun2("GetInternalRunTime", GetInternalRunTime) + defun2("GetOutputStreamString", GetOutputStreamString) + // TODO defun2("GetUniversalTime", GetUniversalTime) + defspecial2("Go", Go) + // TODO defun2("Identity", Identity) + defspecial2("If", If) + // TODO defspecial2("IgnoreErrors", IgnoreErrors) + defun2("InitializeObject", InitializeObject) // TODO change generic function + defun2("InputStreamP", InputStreamP) + defun2("Instancep", Instancep) + // TODO defun2("Integer", Integer) + defun2("Integerp", Integerp) + // TODO defun2("InternalTimeUnitsPerSecond", InternalTimeUnitsPerSecond) + defun2("Isqrt", Isqrt) + defspecial2("Labels", Labels) + defspecial2("Lambda", Lambda) + defun2("Lcm", Lcm) + defun2("Length", Length) + defspecial2("Let", Let) defspecial2("LET*", LetStar) - defun(List) - defun(Listp) - defun(Log) - defun(MapInto) - defun(Mapc) - defun(Mapcan) - defun(Mapcar) - defun(Mapcon) - defun(Mapl) - defun(Maplist) - defun(Max) - defun(Member) - defun(Min) - defun(Mod) + defun2("List", List) + defun2("Listp", Listp) + defun2("Log", Log) + defun2("MapInto", MapInto) + defun2("Mapc", Mapc) + defun2("Mapcan", Mapcan) + defun2("Mapcar", Mapcar) + defun2("Mapcon", Mapcon) + defun2("Mapl", Mapl) + defun2("Maplist", Maplist) + defun2("Max", Max) + defun2("Member", Member) + defun2("Min", Min) + defun2("Mod", Mod) defglobal("NIL", Nil) - defun(Not) - defun(Nreverse) - defun(Null) - defun(Numberp) - defun(OpenInputFile) - defun(OpenIoFile) - defun(OpenOutputFile) - defun(OpenStreamP) - defspecial(Or) - defun(OutputStreamP) - defun(ParseNumber) - // TODO defun(PreviewChar) - // TODO defun(ProveFile) - defspecial(Progn) - defun(Property) - defspecial(Quasiquote) - defspecial(Quote) - defun(Quotient) - defun(Read) - // TODO defun(ReadByte) - defun(ReadChar) - defun(ReadLine) - defun(RemoveProperty) - defun(ReportCondition) - defspecial(ReturnFrom) - defun(Reverse) - defun(Round) - defun(SetAref) - defun2("(SETF AREF)", SetAref) - defun(SetCar) - defun2("(SETF CAR)", SetCar) - defun(SetCdr) - defun2("(SETF CDR)", SetCdr) - defun(SetDynamic) - defun2("(SETF DYNAMIC)", SetDynamic) - defun(SetElt) - defun2("(SETF ELT)", SetElt) - // TODO defun(SetFilePosition) - defun(SetGaref) - defun2("(SETF GAREF)", SetGaref) - defun(SetProperty) - defun2("(SETF PROPERTY)", SetProperty) - defun(Setf) - defun(Setq) - defun(SignalCondition) - // TODO defun(SimpleErrorFormatArguments) - // TODO defun(SimpleErrorFormatString) - defun(Sin) - defun(Sinh) - defun(Sqrt) - defun(StandardInput) - defun(StandardOutput) - defun(StreamReadyP) - defun(Streamp) - defun(StringAppend) - defun(StringIndex) - defun2("STRING/=", StringNotEqual) - defun2("STRING<", StringGreaterThan) - defun2("STRING<=", StringGreaterThan) - defun2("STRING=", StringEqual) - defun2("STRIN>", StringGreaterThan) - defun2("STRING>=", StringGreaterThanOrEqual) - defun(Stringp) - defun(Subclassp) - defun(Subseq) - defun(Symbolp) + defun2("Not", Not) + defun2("Nreverse", Nreverse) + defun2("Null", Null) + defun2("Numberp", Numberp) + defun2("OpenInputFile", OpenInputFile) + defun2("OpenIoFile", OpenIoFile) + defun2("OpenOutputFile", OpenOutputFile) + defun2("OpenStreamP", OpenStreamP) + defspecial2("Or", Or) + defun2("OutputStreamP", OutputStreamP) + defun2("ParseNumber", ParseNumber) + // TODO defun2("PreviewChar", PreviewChar) + // TODO defun2("ProveFile", ProveFile) + defspecial2("Progn", Progn) + defun2("Property", Property) + defspecial2("Quasiquote", Quasiquote) + defspecial2("Quote", Quote) + defun2("Quotient", Quotient) + defun2("Read", Read) + // TODO defun2("ReadByte", ReadByte) + defun2("ReadChar", ReadChar) + defun2("ReadLine", ReadLine) + defun2("RemoveProperty", RemoveProperty) + defun2("ReportCondition", ReportCondition) + defspecial2("ReturnFrom", ReturnFrom) + defun2("Reverse", Reverse) + defun2("Round", Round) + defun2("SetAref", SetAref) + defun2("(setf aref)", SetAref) + defun2("SetCar", SetCar) + defun2("(setf car)", SetCar) + defun2("SetCdr", SetCdr) + defun2("(setf cdr)", SetCdr) + defun2("SetDynamic", SetDynamic) + defun2("(setf dynamic)", SetDynamic) + defun2("SetElt", SetElt) + defun2("(setf elt)", SetElt) + // TODO defun2("SetFilePosition", SetFilePosition) + defun2("SetGaref", SetGaref) + defun2("(setf garef)", SetGaref) + defun2("SetProperty", SetProperty) + defun2("(setf property)", SetProperty) + defun2("Setf", Setf) + defun2("Setq", Setq) + defun2("SignalCondition", SignalCondition) + // TODO defun2("SimpleErrorFormatArguments", SimpleErrorFormatArguments) + // TODO defun2("SimpleErrorFormatString", SimpleErrorFormatString) + defun2("Sin", Sin) + defun2("Sinh", Sinh) + defun2("Sqrt", Sqrt) + defun2("StandardInput", StandardInput) + defun2("StandardOutput", StandardOutput) + defun2("StreamReadyP", StreamReadyP) + defun2("Streamp", Streamp) + defun2("StringAppend", StringAppend) + defun2("StringIndex", StringIndex) + defun2("String/=", StringNotEqual) + defun2("String<", StringGreaterThan) + defun2("String<=", StringGreaterThan) + defun2("String=", StringEqual) + defun2("String>", StringGreaterThan) + defun2("String>=", StringGreaterThanOrEqual) + defun2("Stringp", Stringp) + defun2("Subclassp", Subclassp) + defun2("Subseq", Subseq) + defun2("Symbolp", Symbolp) defglobal("T", T) - defspecial(Tagbody) - defspecial(Tan) - defspecial(Tanh) - // TODO defspecial(The) - defspecial(Throw) - defun(Truncate) - // TODO defun(UndefinedEntityName) - // TODO defun(UndefinedEntityNamespace) - defspecial(UnwindProtect) - defun(Vector) - defspecial(While) - defspecial(WithErrorOutput) - defspecial(WithHandler) - defspecial(WithOpenInputFile) - defspecial(WithOpenOutputFile) - defspecial(WithStandardInput) - defspecial(WithStandardOutput) - // TODO defun(WriteByte) + defspecial2("Tagbody", Tagbody) + defspecial2("Tan", Tan) + defspecial2("Tanh", Tanh) + // TODO defspecial2("The", The) + defspecial2("Throw", Throw) + defun2("Truncate", Truncate) + // TODO defun2("UndefinedEntityName", UndefinedEntityName) + // TODO defun2("UndefinedEntityNamespace", UndefinedEntityNamespace) + defspecial2("UnwindProtect", UnwindProtect) + defun2("Vector", Vector) + defspecial2("While", While) + defspecial2("WithErrorOutput", WithErrorOutput) + defspecial2("WithHandler", WithHandler) + defspecial2("WithOpenInputFile", WithOpenInputFile) + defspecial2("WithOpenOutputFile", WithOpenOutputFile) + defspecial2("WithStandardInput", WithStandardInput) + defspecial2("WithStandardOutput", WithStandardOutput) + // TODO defun2("WriteByte", WriteByte) return toplevel } diff --git a/runtime/util.go b/runtime/util.go index b2236bc..d6f801c 100644 --- a/runtime/util.go +++ b/runtime/util.go @@ -5,6 +5,10 @@ package runtime import ( + "os" + "reflect" + "regexp" + "runtime" "strings" "github.com/ta2gch/iris/runtime/env" @@ -61,3 +65,34 @@ func genUID() ilos.Instance { uidsrc++ return instance.NewInteger(uidsrc) } + +func func2symbol(function interface{}) ilos.Instance { + name := runtime.FuncForPC(reflect.ValueOf(function).Pointer()).Name() + name = regexp.MustCompile(`.*\.`).ReplaceAllString(name, "") + name = regexp.MustCompile(`(.)([A-Z])`).ReplaceAllString(name, "$1-$2") + name = strings.ToUpper(name) + return instance.NewSymbol(name) +} + +var TopLevel = env.NewEnvironment(instance.NewStream(os.Stdin, nil), instance.NewStream(nil, os.Stdout), instance.NewStream(nil, os.Stderr), nil) + +func defspecial(function interface{}) { + TopLevel.Special.Define(func2symbol(function), instance.NewFunction(func2symbol(function), function)) +} + +func defmacro(function interface{}) { + TopLevel.Macro.Define(func2symbol(function), instance.NewFunction(func2symbol(function), function)) +} + +func defun(function interface{}) { + TopLevel.Function.Define(func2symbol(function), instance.NewFunction(func2symbol(function), function)) +} + +func defun2(name string, function interface{}) { + symbol := instance.NewSymbol(name) + TopLevel.Function.Define(symbol, instance.NewFunction(symbol, function)) +} +func defglobal(name string, value ilos.Instance) { + symbol := instance.NewSymbol(name) + TopLevel.Variable.Define(symbol, value) +} From 1a978135e68205cdf75e3b33ff549e8fee4df397 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Sun, 27 Aug 2017 14:55:45 +0900 Subject: [PATCH 214/228] bugfix for defspecial2 --- runtime/runtime.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/runtime/runtime.go b/runtime/runtime.go index 89be105..3c7699d 100644 --- a/runtime/runtime.go +++ b/runtime/runtime.go @@ -18,6 +18,8 @@ import ( func New() env.Environment { toplevel := env.NewEnvironment(instance.NewStream(os.Stdin, nil), instance.NewStream(nil, os.Stdout), instance.NewStream(nil, os.Stderr), nil) defspecial2 := func(name string, function interface{}) { + name = regexp.MustCompile(`(.)([A-Z])`).ReplaceAllString(name, "$1-$2") + name = strings.ToUpper(name) symbol := instance.NewSymbol(name) toplevel.Special.Define(symbol, instance.NewFunction(func2symbol(function), function)) } From 02fafd937c879c051005f2916886a15202c8b997 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Mon, 28 Aug 2017 13:26:47 +0900 Subject: [PATCH 215/228] Delete background --- logo.png | Bin 24232 -> 28799 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/logo.png b/logo.png index abea7a8a9ad66ff2337f4eefc70da6485f1fb8da..40144168acb70fb18ebd0a86b43dc980d8fe101d 100644 GIT binary patch literal 28799 zcmc$_gM-Z*v+r2F06onfOrOe?nZkGzLLGhgCQWiL68vs ztmv4$mtv@*IJJ0jeX=Rd#kBv9>*5!Ye)#)9(kI)b!jZXWi^5MtKFb$ROYdpwOR!#q zkz%~D%NHUKidpB{;yIKU^uN6?H{6F_^dqz(urR7#+AU1!%(48LtnoNyFrh<6{_y|j z3#z2Q<{__i(G(&6;QQ;BM@HtVN5<|{`~P0qxhJQOfoUG*%`M(lH21q@4DuRx7Ec}i zyW`x!{5Xck=Iya_PDi=i*r5~?0sXbK=X+oNd!>kc|NhvSA;e6=ISe7^RzgkKdt}OI zVS>N5)xiG+BcmEjH)*qw^QZ(D(mb{M-&05_DBkm^@MwB|dr>ujiZz~D`I~Lvzh7c9 z(p1=Ps<6<;yf`o;KU`wamowCZzeaP#4HmT+^D+iU4>iATY;4rn?-R+S@&pR`W38NR zkJUJxelRvMnQ>(XpJOL#6AYiN@QaI!b&QPArKF@(R8)@GIXL`l zYq=U48Z1vYrQsLU{04t0hO(IU`-PK1mwN@ea);SB8*$n?78cJrJ8I+PD5m`X=qh%pe);9?UvTof{KcYMLJ}7c;4~x zuTW4>mgg**M1K7EkTfNe&SE%t^u_|Sf1tl#$JjWiBbe}ylY!n24GrBr$HiWx(esUe ziJzgT`MJ4I>FMbM0s;gyG?LL^g$ny9o2o%*T3Q+!Y)5npWfKLKo16QQfx*zGr+r-Y zo7#=V-mJ(QI>)U+XabPR6S`h{{2-Ccv5 z3)?@7vd({I?PrJI3cepNZIueS%R0)Oba=Wvkb4-&O~shc*C6uqH?il;24-bt;gFJs zf`FvtxT>+0IQ`7%;jvXKW9)sHfx8_;-LS0pm$9!E3kCJX5!EDU4 zCiB77CaF@fPp+zO%C{O(z|x)+M3XiZnwic0!}RjqQC$WFi8_O;H zP<(gUW0&~UtqSdo+g_0+-$XSqFwphBfj9FsKmQ{qC+8a;p5%e7*z?s6jQ(VQ zczAfPh>6!gWSP<@#6!H_{r1qiy)fpIqqRCQ2qpQ8&tu6Yr%dra2bY=}UtHpCQ|Yn? z-QE0e-=?CSM3O7of+@MT{(M{eb479rt?8w7B4T3IHC`cgj8p_SR0#GE zvj;%k-MH9IKPq4GR^UJKU0Sp^$?}UyK65&d#DN7?o0ka7kMPe(3u6QY27b1*w5-pb z&C1Mtfsg-$kdV;P*}3w1tnwW$Iw+B|bQ9*LrqA{D^^-ZReu039qK`?sl{E#=&)@Jp zyJ>#AA0~c{r#*2rzhV~$Q2;CAFx?0 zY6OA;UO_B@YBG?>c651Z5eLE{C54oNl5%F=NR>I^Im?g!pVf-o$2n4Q(;Cc7+mc*d zkHV6Y_~2?UMMifgzb&tJsNLO|gpyQ}L`)TDXv*+f%g7M83?y1R(LgJE_?7=1k(f+b z4-L2(eN;wt#X6&=e!fFm;&yw{vb3cAzMm~{kdl&8S5L2XGILj;OuNZ1B}KDdbZab6 zwkwKC_P>h?&dfY|hZ6gaU)I^RYrJ#6u6$llP^D5`N@6k@-J`4Sw{Ea%U96?)H&N7A zkXEZ5mG)JE<|@%aQu4|9R_oH+ML5J&p9pTRl@FEW8Duw@;aZP zH8wWxBiSIGjbw>Ya&W{ABw)QHA}W+$XefZq_xFbkP=Y5N9dj;gI-Q=3lt;Nwt88p_ zX-?;USAkok9H&1~$V}E+q+}%{NfCR(U#3CbQTXjU*!^F|#%m3_LQj-Re(P;W7W8^Z zl}a@a-GA}a&V4z9QI>M+)aLhWeVsAiAsU1j$jyaKMHd5ucdo9kjOO#4?8=Z)FJx35 zQ`33+f{WKIKXg`Fec=KAx1_&+slr_I3AQMNnLtM~tVsELjZGc_m5ic%IsKY$gY|pV zO?=v)HXerH0y$6FSI>88ubQMD)vb9uwpIkR2R*#xeE2Z0*A3{6hX#Mh9iowPS)-h8 z4w%>!@-j2y;!(-8mul8e^K6TkX+eK^dkZCf-3O8285xO_%InezGFc)?QuYzkWJ>7` zSFIo!V%%w@rGf&NQt8WPw|i&0gZYBCi6UkkPdvQ7hka%q{5XIV$!4G&XQKzG;E) z+eBwowG8Mvcc-|pu`>C9y^ihMZ$&jP?@zZLy*oSkX9jXfzsboVC@U+YJbh}6V#C3~ z5kksM@csLDQ!R+s@2DtU1A}a)ekc@rd~#e^h zpheiWyWRdnID@*-iY(`lk`M8gs%G)^2Tm1J6KV<})GMN&yu*0o=R*BBE0LHgH6c}D z9P_fL=X-bmUCL)@N=!lmI=Bl*N5}jWD(V`iH?tRRO%E*-Uoy;v?Q|i61V5?uCFs+S4pkYZ;-F8N#T$)#PG-J%~aw( zJ83n^{VcmY2vw$5DvPC{Tytn}yVY)R>uX-rDl91x`SRsCKrJiV+kxHP;xQvm;Ff+2 zB>Gx3-4mQ{4H=GTP)&e-&ty1A@+E=!2|#$#qFbV(qUC@8wqx_(HE%`+7GzCKcYE!g z@A4mC9b1S?Qm}0^7cLHXxq_V}VdaXTS68A5A2hMrRiZPWk9Z5VS}Hc0g1!{R$|}b? z4uq?Qkyy>7^ZAbTPU5^>+@}mW*T6U0pH|nTqAQ=QV+0~N9PpN@ee*jzTLRmc=6D<1 zrv`IQJrhYtNC*fI-x`|uAgu&$3yqu9B#sMdV+W`xpMK}~pNO+z5B>@T4 z>FK#SN>0vKw-@{R@?3aP>>xU|8=Ow5w4gV5;bhQ`-k9$^&AvB(qh)Pu5C}8%kcKz< zq^!2WLQro8l9)|r75%2C_1ZgQb&gl{K51!$d@JhBKi@U8QBZj8u|GYHdu?OIZ=+2S zRAC?yh<0&i5+2U5^7V36jb|%6o0-Suf*4!~*sOi&6QT{|bYUK>v6Z_uYGm0=vEawd{A)1Pt^ot-c*9e*;)9H!_5=ZgI&j z)~jfcwZx~!&ac7pD)dBNr}Ay24`%)c;B#f(Lufp%Pq2AhyIV9WtU|+DQd~LoIdo0joTcCz@1}+s-#oZsMTpE3%O+r9Nli^PP8@bVk<9?Q_JgyMI zB{09myyF>lDvwcnU!2GCL=peS2&AawzcFH4JV^dJn9yVS;hsZWJfe4ONa2&FTCY%; z@G8oxhH(;d_6tlK{xX%8iDC3%i}{F^8@q%CA+2M}n2SrWRVp>*ub7zH--GYMD9+!@ zT2rCA_nTE9@){l+t|6ig1z{cXa%{)sGQ}5c<}m5 zTS*d{JxxsX(0qRzdO}qDBE}}tk$R%NllS*uF3h9&c)d?5av`vvSgD|M^-Y>D;8L8` zJD6BqSAN-U{~Km2`0M4!NJl^zy{O{L%bRYKbuy!7JiHphqJTvy;mF&Q4TbC+w#fne$#Zjv&O6encYcO8 zKJdH#9o*UZZ&W1B?d*IE+S$Ow^jJPvsLl*X4(om58Fz%kg;;}dtjEr z(kdBGew#O{U5!T*+2z56?ouPo4w~XV=i7|uI5@s&*bKtLK1XUMC_#{bO!F%;t$=dI!HkS2(>3xz{@A-mut$=luU2ndg3{@=J=)uh;RH<-c^5KOy~ z)xT-H`tCjHYt?t*2Ei}LwB8|cq8^W&`!4FQ(B$m6RnfHSzF8Dbgg+7PCi9R7m9q-=C9G4!rDp7t(3!( zjv+_rfi531%atD7LRNi;_>WAYC6+R2U5)|At~-iBLMj$*+u{GHg3z32n*{}BID}Ni z#Do;qy07C9Y~DT@Kx`18E+NCE_$)5|_Ln!ti@y8DsZ56KW4U)|yT|zj0Ae36HSQsUy6h2)epYc%~_{PRgBknMmrk!;4}ltxAkh z*bf$bVK6}&eC=#GldXTz-@Y{cIrtwNQZ)gvN)u~I#tOf6eA8#sV!b@)NCjb;O!?pT z1jxz32IvUhzXIN)J);5hEw#ts)$!UligX*z13@46Eg8DWGKQ_k#!?bOWeR6()@8zW zzUINPi?ujO7U6F>Ym2y%RqklP&ae zKh!EAf!R&hS1X)Z*lvIpg@Pjf;#K!&Ugu-dJ-cEOR~crU zi6@DNa=<#SuUA9w$Ta?FAT=AWmIFrMbTG!Vv9U!+=6s~5_xtieKaKpu2RD4T?q{lo zsfjlP!32R*VKyUc2MnawyXH zG=&hMTIet^AzW?55#@N~(K2Xh{EE++s@N6$NFNi{vQargp-s2tS^;wr7B%c`+KX_m zuNfqJUC@y0cC1$_FQbz8Kn3s-gH+R_?>9BIAZ~|)WdJu-s?AC7?(cOC4gCwg=INcm zMqV-MAl#hq`hWI*sykh-`-;o@ooL7_FDCs?ox7{!SG>-wewf65Z-xAH*1IF&z!mT? z<$4{@_U5Xwl}j}~+uO4*HoEok>67N)+&J?%9wDG&lL-q7BK`XHi_v8A)2r97bpavp ziqDm^@n(niIT=sEe6PG_zQ)7$_nXzdj1LjWx0zO7h1!Lp~Xi)s(BJ`Dd@gjl&)rs%!o-4nrlOT8y zi|Sz`&X~tZA^b0^^R^mklkNT>DQLc>0H^dmD$QwCpFfr1J8G*6s;K#N|1>T;%Sxix z>rQg!rv~+{=)uUem2pACBz;C~6TTddixF;e*1=BSXd~hsv6kaD+!pP^o9l!K+Aokr4>?DeVwg94gN?< zNy#fHjOKLG(a~YLTpoy6S~7l+PV~`&I_q{vyuI2?vS4(-a||KpCyV+Z{i~vasefQV z*UStPuqvEfT*vmdwmw-|lq4i1j&pN!ZHtR!?Ck92<>k$Q@ME%C6^1|S&XCt|Sl9UY z;1ZvhNCANmfeUr)&sERi6TE-_{v$Q@XCou{om@N7(9*7Lm1kxm;p5}y7Z zTE2OTMS>G2rIr^fGIU|)Z@elQ(B|{`c-2KLA5~#*|2=bumW|o3WNoGo821xwsyP* z$o)f<=tJ4ah!*q#Cu||C`8?>jMvDt;ina^ntBMAEb8~td6`9FK zg308n?9nGkwFT&$Xwzfs@q;ES7&KJ+#dc73JgUZBoSe9nidDQ|u%E&rB5x@ukXBY! z&@eFIqlTcM;ER_pebUq4fHA3cX^Gt3-TmnJ*eg67dvhoa8_=ZlwKjQUVd}=lG{1lU z*3r}Z)#!Gs*B*fLirfAZ*jf|}42=FnHVhEhe!;;QhpK;m=mNeBKCbt_~u#b8>;|1VtZJnXSk*TSRxmJIx ztGCj|1_#4Dq}S~r5J+oJkHlGHw+onU*^`r#EmzwEWw_&>g4dHLPo^usV}MU*GM#38 zPR#xsP{bSmUES886n+yyjE752{GbSQ)mtnz!seaXIVH#fgNrnVE~0SKR^22-O0)pRSN)1cLn-|t`Dx5 zWc;OTV+Vzv@NyqUT4a0yAzksocbax^e_t9az5H3`R_&TogN8I~oj2|m&Wkq&pTuAP z+Kpg%X{JJ1T0!{VR(0Do+4RjkIIFiSDJs5UV#0}xj0BYFGAS9^pmz!VP^9;9Dm` z2hsbD((&T)($&?~+j@J0s&jJQhlGaenwSJH)H_rgk>p7y`2qgo=ry7q_`pRlinf8d zl+kWSaq(;JmzHSiuW-JDgwry8tp9xp7+Wddyg{H84QW1FX>*Dn6R4yBwM@7Zho!P!|cC3-xT;AD5 z*|8{azR{*S*8-&spH?Zr6L6o%Q0jP4gW5(%aXHNAhiBrUZnp&B@%j4uqxxZy_KGcm zh_$q{>j3Gnva{1$pQTeOV_S-53n=_WAQ;rR-P$L0TAi%-ND3$uZUR!Qv&L$z97LPU z>9vKaX?ux!_43Y6&`O*CskueG32q7=cxHzaMTCbSpeuj$lzytjo9~O$7;tU*Me$(3 z1gRn;D@C)05asQzYX}dDfZ@mK=(xu}T$WD{3>XFy62XnuBF}9z#-OpN5C=yoy2)bd zZ@YxB04(T-d0AZ6zwdD!@}6EL94;h3y@B5HvAR4 z>8s8#(%=LZ!`6ujd~iQxQ)q(+219`bg z?0)rR>$KmhYR{!*V`(LksPPkN_^HTRx$zc(J5Qp2ozIei*u)36l@;GR5}bT~*XgS` zNhqLd09W{pNNlU6rKP;GvK4IHUx*SPA0Heke4?XU+1z~U;NVbGUw;agQW^@=7*pi- zss;MZ7isA^9zVPfUxqn>67hK4MQ(Rf>v4a>CX)j31^gHM{fn=^?t^MH^M{Ium-qbP zA)}h2;G*7PNv8$rElnQw7o$=c`s_)GPz?mGz-}nCw(AK-(AC$O@#7M8X3+G9I64b< zY{7?b#1$%Os%tW+D)?v`POb#mB9)3aZMntN6o1#IzQu}@Y7!E^5_$*@1@ST=8!;63 zp{8oDH)$O0-0rOc;pmYssB*1YVxb-h<1U~hDwS!KF!g)?`la*zyYKk8Vo6vGDCR!~ zlhLuU!?C=b#6-7j3l~~jkpQ=c_WZf&=_~ik1&4vwhFX{_i1}A6Kc3qIKJm|x+xPG9 zl}a^w7%;|PZj!!EDT*?NFP7bGHv94t8~SqFxXIy=E;Gy5kK<;YrDM>}Dy6}*EDDbk zCju{EC@l@!!U8=rEBK0~dEz{UyUOuK5dl)2R=+yRRyuY+S)vB$z}cOxpM!n4ES7hv zWh9%w$`o?nE=89~Hg(BjZ&K0}qAf1Y$44-ooWF-YnSW(1#}L6Wh_0QCl8=#e9*{9; z*UayFb-_>(E&U3v=c+BHdJMHFBHw)a^c>W|7l@j~1s4}#gDw|)GX=`-jBIZ! zz51ap7FRhxTbWrQG;v2#!?1A(VdPeD;sPvSevX^`baO-Z;m%c91ph?L`(NkfL65M2 z$60=?MM&0EW?t^(>czgA>5M||$Z7t`j&z(QeHT)k6xB)Ns1HM&O!LMl`oJ%bxkz#V zs|7#vhTp7GMtY~P;%uHKVAmOijZbU~>AZAEQZG+`1$eB9+xtZm6O)P`14N-&fJX-; zld)ZhhNh;7z+qv5y`G_=p+=o;!GJ!e{hmsw!anP8wfREf`H&09Q8?Lcz240(wpAxt z1Rh;e(l51O;(CcO`4Vpy1zV}g91qQhE)dtUQq`mmxQinFV8yMhh z4pGfu==Q_J7lve2PN=e1BnTVys2VJTG=))6&;R~iI;)G-Qdai2+nqEbNkM(`qy@l= z%Y%in*TWOOPKG~yzJ95Sx~T|8eoQ;JY*&9Y~?DIgp`+yw*B-1j@tP@)NA z&|V$^+>ZGDJF}{`xTr`-Pmdz)$6>c(Jv-3~+AzSf=O^wNQ_e@}@?;5k5y86~Z{Pa9 z?8Xo|x8`p`dbW=1WI*p#U5#?Og%Rll_5;v(Bhz4+Z+M|(vT4ucA(*zMVOms3H=r^V zt5QzDu2*9>SC2|`G(IH;Nd?6sH&ScUr~Z=ah)Oy;utBFuV_~jDJKdDHVxo+!163*J z7ej>DF0OAK1kojuM}gtD5L7(c-Q#4P1A2!&J3Q=(NzDE;+8F!!b738wHvrrnFSj6< zgoW4FbAv+5?e<@Oj*Q^gZ1x+)9TPL@`G^)=NJM?m1;7wqs^L$os+Pxc837CoW7J>w z6GgYc=E4+Bt`o*zpxR^vLyh94qS*u9hFYL-q6nOBZRsxZthx#dztmf4U1jHD|EGd- z))j7Y4XH!0b>@Yj!W96udkrbP)YUw(gBm$be8O+FKZ7K-6>RYYwCnE`qlQRvExpP^JG0p;R6plIFFIWQ;zvqPAY(E~_$)7|82655*(1Y}W;ON) z+bvORTk!Hm$9IlyLdv&l$_Kxw`sQG3YQA>6zL|ctN0tZU{|txRr-~l)8MGVQ0gPu0 z8-&Ly7{tZG$&BnYK*MuNuYR&gC$a^w)LjP6T4!imzI+y=EliH=m5|@_7WmZcdSw|x z#+%5${CzZABA!YADQLM#U#jrZ!QimmpTM%u?5^!`U)4Fnh3IT;ZS6m_0iY-j5Xo~D zUA~T7r+@a=`S~*dh=lr!4Nl^clC3>aRL6TWEH4QOvr0?DJUjp->*$MPcpKFtr=k+j z6;8g^8$-+KeD)EHH_K~l$N>DF?M}&-D7u7`@eTvv3at}^Rgv);uX6<9SS+Y@TP)DX zlo598Y6;{_y+1jF1ompU;_(;sxP^mOvO zT)0zOZ45&tRvFFWbZHFnei(GBhcf`;7AA!Y0MVCGhLdpp4&MW) zp2_3E)yLmo|N3NOy1|L%;&3S(AaOk)9)c$#sG&iEgoL!bvGD|eSGXt!bv|$PCwC8E zXu897yE$tCh@Q#m#DHwQeXT3pUzh@(U(5ypos4OmRurJP_@on>qHl8$XF=-tciqi|9>t9bg#J_wJ5f$Yf9ovl|TC1soWshkh-0aUW&)0nm zE>Z7OZ*V_}O|zo!dQSL`#qu*V^49yYr1K{|wxP{Uhl0hkhg_`Devoak?ysuqgk`FP z>{&QOn<(i~ezh=|UUuHD*v$E=Tc#Ov5AB#0=E8Di1>FG-s6!wu(vD&jGqRQ=dm4NIZ zX_D3k>?ChKenf*457?&%3-$Uvzu!AsSqz)x|1G!i_=Ey7z?46)-@Ui?Xv8569%gHIO$XJcD8T#f%C^CBx>ct?6vt~^vcz7?~gL* zfqxrk95>$9so~KBn@62wn)2WFd{ym;fR#q8rBWrR1>(+p-1|}tzVM|G(T2WcALDpR zlS%xqN2{lkS((owBS+514&gZjj2s}t(TCG`oH8dW;`u!q(O`+fTkyGYw#vi`$Z7W8 z)evJa`uJiHG6Jp8_HdCDc#!rl=E2g(IU#9`x=5m7B!NCYK3Jr|fB&)qA+B1=)*Pho z_rBPSiVFF>N5Y|0-e5o}WB`hX6A%S)O$;Cx`5#ClBQ<XdGhXk1-UvHfxj3=+!Kb0&a&^pyP1Ae0X3 zVuMhZ!Q4MHz!f?s>GFX9Nd};P>r{-EgG0GU8!JJrfJ(L|v9?fO##gOY54Ao*>+(1< zAX5mD-s$M5JEpBc&Nkc7#d%+inwdqSSJTdi{;4yVg_AhGi_63Yl@j8A3oz@NTGc3( z7#n2iCtEbZ<$(!t#gRu4-;(W(A~?rt`te z3BZPh>hkHfqJ+F+LOMP^CT0Hsepv)03UDOc-(DI@wZ*ID0S#M7*ayL8^ixg^cKubc zwXyyW{9eb!9R$ zb;A}5<7mqwex{I|;l5V&DK0LZ`&g~tg#~i+;o$)oYW$<3@R*sI|K2>fxw!%QWHMKj z6Ii66$j*StV3Vwpjb}t$@_6Khv&JJRde@>BV+ES3qBi=lDIa$0_6fpiI zA7iW7=6lrMUMcE1xyPNne*Eq2E!>egl*T``bBl$Bw(M29{S*{XdS}!#z?&3e+H?RI z3beGBBUT|spf54EZz4^6Z#MrpR_;yN5Mo7 zTz%1(4AQkvj>=|Tix)a68OuErF%WkQjFK#egAweswQrKok&N+(bQd5JEn=bs6dadn znmc}fTrSQ3FWOE|y@3g}va<3omaUD=DR}ZbfEB8?Sh6puHI@KO+|E#b^~FdicQ`gIc}kA|ny*V}TN+g}(QF6L%VsjagouApa= zk=3F-j}AyIgv|0ksDy0|5l2MIi%pE|=2yX53CbM~X*fC;z~Tb&VkD<{UHee^`8h0R zRDT$^G;tjjrEAYtZ2R-QDummOm)dZ@IbEiw-$J6WiR}G@D(V7#NT~^aO&1wsEvE)$XxB5L)u{ z^Fapv&ne{R=VzM2@wIPNXD~&5a3S6|smgMlI&i#wx6jwvDK&^~)5$e4&fCdL3F=_M zRar?Ckx+nkrshNnjWrI5>Z$gOIkvMkzgA<*%zP#?CCyciZpb{Kem0b_d39ZzpvHGP z|B}DRa{QMqS?vCXCj$EXf=&L*20b%g?Sg-U`>1KMb}blloiyzIzW#*v35hq0P?!ID znvJ#f-y1D&Z}0!A!M-Lh;A*g7X&w)?|KUzyVPXH!z_>W&q<;>ij5-4K`z}M-dA;3N zq`JDT1F4?LTI!|FZd@~NpJd4rFc_&K)BMHg=NC?a5N71?v0x1umFDQq3CgoC13-9w zC#Og{?c~V!8h7YZ;8Y7JB~G#=HDvx|^n(t;# z&$cgPy=268SjTN_xcSE~_viAM`q77NY;3A-_=E%nuh2BdqQ(J(Uv`QqF{_^Dc9Ag4 zs2l>?bz5sI#Pkaf56|ph=&mOs@(W_(B4wM-@i4emEF+_pNWXG7sYZ)_@8buOVu}O3 zyrd=0h^=ExOGL!8^Qzr8f7*zcZw!T5MM!nlc`l)7u-l7o;FfVIT1M(^tRM@|@>o7O zr5Uw?Z;Ce|nfL-8M}D&YVc|_pK50~SrGxwQVu#3SvLZXUIMes{7+0ULstcu|6%0+||vE$>qXyePhGuoEL-%4I;FPs^I$OW`}f`|9Tw{q*FU!`9;LV z#X%hd%;TKx@5GFZw?!E&1xn60hjKimp~VbT(sHZk8|yV+S3WTCy_f#!etOjHUGGAF zcfY-BveXrZlg{xG@xBKS3kJxElTkLLvtUA#E9g!j2f1`>f#D=)jCqF_^hugz^}1Uf zH7$b2)===cW7==_nIQ&ktTPg)zp0c#leJ&xP%!N5D(f})?B1C)e$>N$_WKR1;%GsJ z`*Jg4Xr_&}wl*2;`ubYU%|lmL7m%Vq$GEnD&;p8BINyyp;FaJQ6K=19FG)^L4lD_9 zQFFF~@OcJK!NZH0y&PEA$@ianQAy0GCk+IXvB6`zsi`FGf%kVOF{Nc@X*{Zd#l_AB z-zSQGh7^5MsrwK%T-#YgG+!g{Z8BvHIO9mztd#O&NR(`e)lLDM4DTP~5vnxR)o4g= zbJMn5rBY|l6bCsO8JDF474?;dFTLZ0$)ua>&vGeYOq;(#LKqM;>HFmt@BeteWCUn> zxCNc z>b+n3o8um}-cXC{XXn;|3I;NH(-Mg(!kdka*V0jnY&cE zB%QM1`<(n0_}2z_58HvEl4*)(UrpLeufFYS|MC$}IdHe&JEv#u4g7joNP;_BJ9^j^ zMmh!uCsP*#Y(Ui|ARquh1`7)-AS7gu)n-`B`4D=^8a4<<_Hejb|8RFr%1%!ule}EN z4GhZY!?!@wb8&HjCh>n@n_%wm8ML^TDKIp+ z=}BKKR<_{~Dkb$58*D*exwBm$?B?x?tkqp4uT1ug)dx$97Ams2lZOIo{)*4*nTjbP zN#Wr>vqA!%brjP*alAKDZwN~`9#zq>=wYmL?PUD!fJo#Z1c4tH9sTnh3Yxe8%GqS= z{NiGxkc048%%a<+CY*h>Wnd@+u>|IZ*8cutX-4w@Da-+&0quS#NBN53d~?Quf`TTd z&;A{8T~I9s)M8VDC~W6Tj#1%_wXu_PyA=TXy9dl(LB1)AKIp4f`(@lkekyJo3VtY`F^?Q{=-i?`NhEA#JP#iB#X4IBL)MzxDGrMxuQmZI(50;H_Qb*A z5{r}&kO-k)0bPuVi3!*Fz#*EojlMW%j<_#0(Xo>Oo}Nfm=H-Vm z$Wy+D^DCaIQD2Ah7Gic`Rhj3o)*09;??RboQAIet49;c+EvsbOYKW^D*_~|qD50>2vU!%v1gOFyH#g0z7Ub8~HoN$v2hwbv6DtpH zuMZa1(o+*@)`moztc3EjfI9QZIV>Pvk;G;Bo{4GHFj*s8*r!0iL^jb^=uol|Tpixxj0l+PA)|wJ*4v1_4EnNkW^oxkg z3l2*YoDgyja}v1eq^7RU9#%8ox0a znw#HHWJahl%vW~I)oh+F>=nl5)YfnHhR^NIyPsr-p*kxmkv3s|Laei%)fAl=`JS1j z$dx{&v#V4vdb(G;=bv>+`h?%|#kI;;^QU*WrB^$ycL7^Ngqtbmv8QMK_%Q}AtAoEy zRaDHDd>(@UuSbzCP!NNHo|QB{Oi!!Cz|~Q>Z=%t)c5&fq$>k7Apu4DOE91!rbQ3Ic zzBX9b6UHG2j#z)-2Q-JfN9Et6KN=$yK)No={E8a2(j zoMeNy{J3IT1Io!ogOih`O&^XM0T0iKaOm$RC zpPgreJ@QWgzD;!O;_T?;JT5Rn8aA=qkYsCZ!w?z5gRWCxE!l0l`KaKW6waf-s*?jI zuCJ&QO??+twd2$QUVng>;_;3 zN9&320SA~bUzp+ungBTcHQHNqb#tQ!)?x;D9^f7TD3cHz2@wIj=n)9Nx2&u$0U_qh zvE+fy>vW=CWRbgru+S#t`uB%&x$p_n^)+U9pUKbMFs&k6IgF`SR9Qr8K6E-jX%w}# zM)%opbvnA}X?Y+f(~JM=Y0*32<*}B5GGb#(0H?GTc>Vn$&>|A(<86aeZAqiO(RNdn z`+!$Kl;;=g@4VoF;l?9p^ z2`On6Gd%zvjLgiffT^5gg8(7+|2Y%@_X++@7o4jD)7PJTDDC!i1!P1%cPE|?JBhC? zIeU6x-WuP0GG&R6?>a)9C?ahsT~uF#u1Y_-SR|dCQ?B&Pbr<{H>QRcSB%f`UY7X|8 z65{Rpf{87kpY+Ta3%0qrptRtLh{O1L`@CaeWHuYA+gV&k>BA$_OW{}%B$9UWCoSWu6y(Oe&zfatBQsB#Ot)Et#C9}p zG_3;FcT1gCh28QH>L3LdU=!dJ`_b8%u$ftjlJ@1vM&C8s|B?boH?W1!yD?e*iH{R} zKu?6T%wT}^0W5@4*L!MebU>{BoC1tJBisT3eEz;*l*|M=0c<1-HCHw*45U>_+ACla z0SC4ek!+<1h?Y3(Yd3mR^2)JlcR4?bXClE?A$887R&ZWe$PBS>Vq|UgnaI%Aev%h5 zho;rhh3R|pn*CqiaE?7Nse0G-x%y2%S{mNLA3=`3!1|Sm(-!a9Cs|%z2)5Fhr%tDv zEq#4by8^P};&MnJ$ZUX5#&q_t#G&~ze0l;qL_<@}*1eB{P6uuc4#aR{+iYz%PgL1W?LNoCpcT;7 zMSk{-C?Dd?n`Tdi1CglD%dzSzC_Jz&YY8Quph&lv`+#3EaBh*iLBTjS4rc+%pXh$VjazYjH8K5pd9ci z7MGN$V**!&`ajc=`lO330IRKR`9MIWATBg}&Z#d0+Z%ybLsq7ZNV)?cX+a)z@jo16 zyB>EC!c(U3Taii$lm*rsqfE4rZWNWoih54cpAdztJTO#C< z5lU!al9?1Hg%T;3DXqn67dDp+5R$|-VBcB{wmc-+SPG0hOILp4PV`Vwgbj0jp2U2g z@KZLO-{~Yt#;X*)A9TIp;q(Ot3Si|1{)^F%6Xqr+7{tWHrht$^)fU1uaA55okGD&3Cm3+Ft%B5XzElN=PfG5?ansc+lhmP=-%NYY< zT=%~Y^p`M|_bhs?r)d+PK0YMOLQqeeH3$W?YpvgtXH>IK$ap@qVe`Wlr0YN)!&^qk>#S3>6c`Z9;(@wy1I&ag z1sAzGaMI-D;qG*3q~5^-u#U?hy__!-wsF-eGQVUr&NTS`zjlQk)TIG6O2uC)u4wQTfFh|AD}gROK_l;wvv8WW8xG}d32 zmmKu5GGkLmuV2w5_Vb$|*(pzH)YNS%SX!i1n-z^x53_|1+9950XTN)&Ui|?Axa}5j z>g?=bbN-K^ENG1>=rFhkud1pF4Gpasj7gzRBzfoTI_Ml$)k-@L zu_^DF^-O8v;JAox&(@t4tIou;(Si?EJsCnaJP6ii$FDG?9T1VScNqHYMz4!e{r|iG z_a3%S&tm^Mn9)O~o(wCOs67FmiBMe-Y~Fx7-C2;X1$YEB%_Y~ zZomW5*@!W4Ov!l4q(59XJ(2>#h$}fI1ss7|lVMSEE~6CN5jHxF{bJrPc-C?M#e6;a z&+=X}CKc7el%Vb8b%UM=j-;ekcb2V!Se};_pzKVpHP;f6>-6;JbEGEXIb=0bkFcR( zyvhrT&WGPP_G%%@bpG@_MW;;f?Cl4Ca}y5^s>ZWPU1RaO++S)U2db5Dll%QJ z2)5sXtpM{K8JT2m+HvJFdQmGY z;8FbZ!Y5jTK_CmSl-u$aBz)XABr#W4pGBv->~6o#Va>B~_g#RDe`hS6~m8k%GX>#g%|s_hFI{q&v1Uh|^4w2y3hA)0!*=$D7w zx(I2wE`4%xn@M0N$>Dx-Q>kCGiOQf2@r z=S#-IQ?!2W&pylf@!|W{3CEA$3U>B`E4l}J$pcICq@;hAm)}f}FiC~(nyi|JLXDyj zY&#&383R%L;jvKz#aT@-2l<@CfUWhyG>7NUTh2GDNcNg1KNsT`L>5bQ9?Sd8oFD(P zA=V+-46^orL(~+nFS>M1LEL=$lmz&1;FTCGq}n_M4OZd{-zE2(?K~N#hka@xp*DhQ z2QwN7IWTDeS9Jj3jqMVwsOjlNU0r$L>N1c%0hd8WO7x#c@)0ab7z-Qwka=w?r|O4v zZGM78%(mKfvFd6-a$_wwgwG%97CS#bgoUL_r=^{=*r*vaI!gGF+9{))Ofx?Vqi<^G zdTgo&^M{YyLWf~i6zN)_h}{{e>4IAh1pgja!^s((*$;ns9um7ky&K=!m<9(E=B-Gg8~m$GJvc}yp>U14Nl2gfq?=XgKrxiegO)j?<}K5IP5M;manCY z+#@8M|KZg_ot<}Dnsyv<8+`$rNiTllyiZd3i-h1TV1l%YvrQ@cUG$Too6^Wh)7Q5DzoRW%a0$>QL91?Qq9i11z#BlreSz!CbD%%4yBdb(Ye!|DaK^8LO=%xgqn;e5N^?wm8a-=>A_S0WVJ5f?KtWn z)IN%I5zCpy_j(u+BVPf%57>Eh;>fz_v#LyJ6&HW{5?5N+E%Z?PBRR8^S6S&0A_%-m zH;J#WS=U)=WERh1kW;()Z4s80bvCcD0jXQvHdzInCO&tk)$T|***CJWi1@UM(>tE` zkLj=vo`*%q>0_te138YRM)BNSBO9*}*Vj+S@O8{}-uz#BE!9|2g7g~qtJSkL2X;qb z@UyF{{aNJq{BQ1Z*QDB8Tux~ZC1+}e6FuZYJ;QNTsMHml#64(0 zzrP0?4I2Lc8vE*~sN1Mp15rRxEEJ?f=}=OJ5>&cdU_e@0WC%$GQ5q2eX(^FGhR$Iq z2?^C$odJ$0UQ_St(6FB2xGcVpu#OJ0q&=Dd7SFXH)( zT*4C!#iy){jM{+#9U`iiS93VRKA+A_gFrpa0b;Xv-xu|3051XLzwThjV^nnpdYfJc z8-v?_iaHUu`hkjTQ0A~OkV{*=Jw*W!g7I=wktPR7aQps#uH4}^=-Z#0eD~;8;^=yj z`-Pz)^SY)v5j(qbV@{!d>)z%Fiu=6m*6(1e&D~pBv^C$+=Qft57H;Yf#xG2r!I8)E zXqzqe+{_%zHq>4|wEI%wj2bXqwiKUrSC*IZWK3#fi|R*f z@1I>C_&g#mCN{aWgmL-g2#NUR)H0TSST7=J1vg5t{f`?Z8%EQ3atw;W<)#2OX6BPp zQc^^b$=_kC6hX4J&A<+<%kMWe2LwmpWfYEwTV?fvj@k=#`{A_d$Eadk&F=D>?YX(9 zeh!K0mRE0j?V@hCwi!!vXn#!~3>ir89b1A$Leoy$Y$IUzpO=)2HhQoyH9h1rU?9$U zf1GvU`P+!dbTc7ID;=HA9bU6hYCgWQ$CpO~jL25w7`?Adp{gc7eCVKXK6%o?KJRmP z1s01{d07p3D?O1c0pMEs^I3(gWNKvrSV~BzNEV>k@ln_@c|0s64ICu^q`Cw3lh@|3 zmHiuts#UO7+kd~EU#UCIKxC0EHy8J^!CEb{s0!C~Q(dP^au)XL@2)tu!KG*Ln-pJj zsNZ-JndnNr={iqoldXyHR>r~cQ8$BHMf;f()fP>=t9Piq)qXyKI>i!qK+SNwc8>&k z5t)M{Oujp3`5i6-%CX#HD@jXyu4nb=K3jtR2~{s4pxF--2|Ojo0^8VIlP@Taq0g zv&7eczHWX#o9J-OS^NT@gaY+ocg~LYzk9hcMEeXyo300)yd=-JffR2oFeLC@nIl~C zO8wTDzd%FB-9{zcLK&Y2!wvb#-T zG+J6!_h0N#NDwgPEoV=oW)TPx743q%OC5CDNlX2!8w=WcHPsInU0(BwyyVV0$e#`6 zUCvdG^TVnB-J!fr?YRd_Xi?ju92$-ZP#3`bVEsI$UD};-{2)Mbpo&iIcM^F|2g}YlMsOt#-I}6abFsN>bdae|&)u5(3x+J^6=OPJuxEf1u zko0s`fjwG<8j&L6-b+8%3*POr*k802=+YK!LYAwY;>|P694xeP;}S|)pRdKd5l&k5SN&e$N_XDi zCzqa{d3`&VrUXM`K*dF0s!MY^qYF>%m3>(naF<~?VFIGuC)Velj2ogL+Aoh*Xp*c# zTLI|l=NTmaJa_JY4`9&03)uCjUSlH|dBd}Fp?VM)tdbu_386nub zsKBWsx1%L0Ulz>#-07B;bzEJRgM34?)XfL$PaTqvJ3B8ezt^{u-5D;@*V4v4w3t=Q zM0l8_mWQjvPcKYs1t2OzZ9;RX`nv-lmD)z^_GF$?$h-Y~*uid>{pFhck)?9&@}=jc zV@>q~n-x#@Tc|ntc+C&FxcO(CKQiTIM^((xx6HrX=X!|mEO50S3~mo1rtnVaF<{fd zW!#VG^417H^AA<2&(n*P!is0VTn3(J25DcmK`3tzY_&&sAMtUDVb`k4pYg=SPzHoGd zLdz{I{gn!@@uinWKZKjQ?@!@Jv53`(`26-ri$k z8B^C8bj>XeNeGuf&#etH8N5>rWy4-0Pzu3G>O!A{AAN zN37z&#!Voenk1D9Nc0jC5`Yk!uGpEtp&TzDPb4ja`HaSLQ)VtXCFNYF#Ng$*<(eaj z!<7i%$&KHGc3v*o7Ht{iR6EXry?B%WhJ4CTS@~3cdt%FQJJ*9$nV%9o+}=#5cNOUu zZV{j!V;JZ`(IM}tM3VxMyubW~rW1u8CY=6iOy0W3%}b?b-wGJ*?p=Mo(R`xdP>)ea zz-)PvA4(4$ow&YxS!>fBQsVxnaqi=MT73hJ=fb7?4sQTA)gDg&nfs2`o`auZC?}Ab zABp4Odw6UdlAPaxIW8w!8--$IKelh^@lP5SNWOy5|52h;Q zi|c21l#Rc%pcQg^FQh6n@;h6SDkM!>1Pp7|zv`?wC1mQi^1*c$O8pQ(z^%-b0mm;}o#mxV4SI0$em0&;S4I-oD4CF-Q25^mJakPGr=o3m@c zASV_R;A-L_%tK%Tz!>!p{NBfHjeiqeu1b#;z3eK_4GtQ@YGmiMucv(vzyHer1>)2u zivA`E55LvLA@kaX*LyCWb)zGQOC=?Fj8V9UE`q0B3R}(&|4cH981I9W8#wR)9GjPW zWA&@Oa%l!J+G{TB6x19}c&z}9yjLYI2%Y7S`d#L_M1y0Mj@x8mCMprx$JWjsMw%-u z@EX_ecN=%{F*zjn^1{*t{<~`aJ0;*l2FwT#{`%SS}BzTs_GQbD0ZYQ@-?;GQCZV+)tDrUE>*V*VhRmZG7}YGamP8dUC| zH!wT>cK%C_XFxp7@rB@o_A@T)9_Vn)?z*713##zkpDYM%o!b9fGvGvdRg^au58DkYq_b3z-nq1l8vyd zlqN~;ke#gW^a~4133_5?w-5eg&m=oP)(tm2G;Fia1vp&B`+!q@1Xs8kz(!DUJ{Y(nFx&;Xn1KWiN5~9}0q#H#*vqTx-zotLOAHB3-8JYc_7pK8qz4~C-LkQ1^%jYjNTPp0v((8}%PB)BZWMGwVBfz}3l?@<=j3Be`(FpDukUhn zG}2MGCdS;x2HavJnKI({!X z)V@HNOTPPn>LCe!k>>bVCokw#s^-#Bn3%(01+4I=VlC*cp0}k+scy;~TRdlJGh^*` zU7J|)A*=L)*5-3AP(^0#TQF~v=nyEHZALCn1~JDtYNL&F^l9X(FJGs%`rgd*z{IPC z`l}KLf;wwLS(#ruW1`|W(Ya!`#0RRs+S*BA8QBLDfoD2V*QaMeu7*Z);1V=};Py|v z2D06SvGU@#uFKEk{DZp!*rLQ}t~-5Vwf)@h^6VKs4UJK1^G%YO?wWbBBINV8YZk@d zt-Qzfa?*XbO_;Cp9!hWQ@@@WU!c4GcH)DgQFEUg*%_jPGNQ)g%C`T(8J7>}SA|5;`d?Cgy6y9**a6VMC_Y z-gJayIM{nBrAW|0iCEbku~TP z`J#ktgOfVMaO!hy6R$F=R4)*&)ZhK zh$6#1T3Z(!7=%8CFuRIT)a%2QX617C0y5qjFU5`B0Y`EFG`IKt{!yMy$zzmmXU;gA zU3mMq?rmN=t+}Afi_6A84kU(_WrJs?r_hnHgU3QLsgcO!1RJZr(r&jAZn0f&FDCIC zmUl4+RHGI(V$;@ORO$=Bin!kWqCk&p;m@CaqaWTnI#*GMu}|hpY>2JRO_^uU{%+x` zn{SPc9X+zjVgy|z;&isL{6NpNjf%AXMe3&goj)9Mipe|!^c58)`NN0?1fqr&R_ZYw zu6jHTPs4g+pa(q^!6T`nUBQ6lUbi%?8hV{18ipR+8qLF`{&f$wxlE@j^=rlaGQFzI zT(xw6ib4MUcNKT2Nu3pGbv^QuP8OwroUsWXhi5)(a&%eFoh6?IOhuK^PxjFX$& zg>9|w;r!Co$|Alk^Hg4g()QT}G0@B+k|-gCXXt(*;=L>2bGVjb2KuD!^5 zUOSYye!`8hU|eIZNY%(B_;#RNYIrr4|x0I}GN;5&& z?X|{2N9$-3EL?x}vtQB?S9YO2hl~*k=>l=u231ll2%eOZ5LZB8K-91$d#%cwTUdm( zt}RXg0}N7~DPo89-9Ki@HAx?_a5_;T{8Hqz`?|UecBK*@fB5yyQl)wn&|(!HI8sL^ zUy6CA9lr2XcH@P~Wop{)?(X9`{VY7;U_4PDiT0wyA-|?8=8R>s@UJ2e6N6*z+@ZE} z_=Wdf!<&M$wq7g!TWZe)w4MKm#rq|e6+0Kkd(5|PkrY|}kalvq>o8umI543M7BWJ1Loc(EJrs%@mh4bO zwpq&l3@d%bgO%AW4!+UY z4){TD!^0^(N0N*Q4!wT}9Sj5Y_=PeD5kR*p7?Pkc#W*P~d<{3!83_FF!BH!3CC)0( zq&ZT6u;R+GN@)?u5ct}2FvPjGGidi@#J+!I>EE1(EwZw@CVQJ6u($kw42W845Y8Gc zU|{23+*M0kD=)tnad{V%g2>Xq1BvFuDf=j(gKlxJhbx3#(| zt)vv%jGGXnkMSte_v{|sXUNF7W>I1!e;?1uYtM2=ep26^tBIw ztxPSWngP`|{b(PHabpzRndC_-Z-K8IHdOT?HkMgPNJn$dPAOi142*rGiK?Of{Ro>u`|>tESf$@Q01 z#f~#Dq%f7ZX}2b3{sj5QveRW=C9sk zMG24M<8*X%X?>Z+qP`jEsxqvWY%Ie-+Shblt>Tg1B@H?xw(hLKwZTB=`S|>2CM9?m z%-FWXDrIJl%wZ~OCOU(eWfS3+*K@!zFTJhLyZ4E?(?(8r(M>&|z1;)OWP7tdIw|#X zC4aW78^u_(mguEQ*3XjA5GH7##eogQ#KhFKh`I+#`M@8F;6X$@_HpemQu*UlVO}8L z1nYzb<_IxAS^5_w#Lxf@e^6rn9Wsmf1zkz%Wqvp@HQSB67wGB3fh-5~Q84x5sso1_ zB5DfG%3=rWy~J~;>bt91kT7l*Ax;Y9@*igEZ#fYR5J!^Tr^q5a^TMug_hB1vKE%t* zmwc2oc8p*=XIjiH#_Ih;_LtwMb#jx%yKb1xNzGPP)p4qT@$T;I3f81$Vz`t6bF>&8 zO!)ZCob;mJ!66?Mh%JJMb5>Z$QnkOTtZnbv&7Z`>4=C3H}?LH z*F@UD4RH@t!<+?Z2R{l}_q^;Di4x&m2aTo^M3Zk|P6Y0v`S<8O7MR4=yB-kz)${Ur ziP#Fw{u&r`Og+v%X1CA=gLvU0|0x#aF6UELJ6jm=FX0pW=UrfKR|?boE=8{f8G z85D6Qaq5gSQ#0JyT$Xp4;kP=x9nuw099XUL_t>!uH;La7fbD{kzR}6iEj7F&zFiJC z2FTYly%06o*bdqGvOF@Eb<4+eNgFP_9O!<-$udF58b%if^BVS0V~MRGywMIPultJ` zOl*tM?lDF$w$}Eq)8-PJ_&KqvE@V*0*zNVYVmFt|NxXXbwQ%LT67*x!omtkQ*06#p z0Of9cug8Vk^Uh%EG4=^jg6iSXJPfOOq-Vk5%7GnAJdyzoE zJ+;|AUuvJzA1E}tdUfVDb@`oj8eQ?Uv|HJoam*PpN9$Qw!`D3a#!*|YWvw1qQ3Nv* zonH2Rq?Y6N!oCySBuTj_N#{9?WsAuVMPKR7gt*PfR|LoW$e`Obhaa)R8@M%R=Jq%b zm4Ib=i{Q|+Oh3lQc^=N06+ou8IwPNDjtT9M4e3gXtjHqwhF0duQsNMcKJ3XQ4T3U_ zjtg1Yx2T2XGr zxlJ$g40?6-)#e^&(iMmRZ2=I?WA*E7He9WgEi?Fg3@Q#5R)z94{I5rS&BGSfwHt$! zGlV*z*wY3tY>46x`|RWA_xStkqjD9{IVEM6nk=vs!z=-pYp_ zQyInB@B&2e!yZN6iVrsP0Y>`zh?{E~;G7476sm}hv1prl(fXb3?MY}2(Qh5zY$D6v z!eEZ-Er0*k#VZ_dslj|emNf8+v3_6fRZS3lJ)Y{6fi5h=PJh$iMpV9Y6`tO8IlQO6 zvsuy>n@~>5UteF&EK4I0aJXMt^nIviOro%%xn|g1VIx&Wf_jAEWglOjKg_tj{puBh zSthNa@Bht%lcHgNL->OW7i_wa;T>^Z0HliFTzelK9Z*|)Kh|90efQ3@&m%w;oBaJ- zk#7r?5xuOCJ$RE(gIDHLWMuTzV9#3g=++)>ednWxT4`0I85a?@r#K}ww4q9&8>knK zi&QZ-b3qkZ8gJ$3!e&uM2RO}l2%6UUaWtN$5}%Vj;_ca-Ve~c@>e;ejHZvCD+q7?{ zNbu!_Bao=F z7S4H%8IQs&5js*L|4U(o+eT{9y-O@`t6b8BgciCAU4db=jx94csF z0@#pt^Tl17FuelP#x0J1iJ^s2NWmrdf1O`x=kM$~QC{#y18qT0mAGFOEGy zMHT%~9IN4F%^fdI-LoV;UmkOnNx=#?w!_~8wPCVrETwJt?;l^j zn!BKk7Jf|aEGRA5Nml0H!BBztF*q+OEbxqYOzzGxYtQHJN?A{5=aEhO_Ka(_OJ&+o zZtqz-H`8Z*rV%t(iL7`JE?boB2;ak<`7s`pRl2k4m0ixfswoY067}xha*gDlwdb>~ zSBRc>jEqnExL(uRpp%SSd^Z0)j_~BA@_&fV-U`-mbf|vIZQ#&$OW4!(cKtWbKZ6Qk z%j^ul8}n**(LYR}q8QPVMXy5i=kEa?$&3qXXVDg(SWULZqa@DuPH#rVouvrh{a7}u zL;AUP?3)i`FXY%eq!gTZG=iP~;x}=HDNz&70e@N}`m~taEjLcwdtVU`{Hn9;|BAkw zYw+b7u+;%bGbCUh|z)EQhn(8C*t2!>pDkF;yk^hKfz4Es@$oP3^+r{=8(wLKVu@bqcV;p31VeV*ew(cG1a}aG7#QxTvBqlM?X%t(+Jvd8Mnwgva0Ds^hH1Q2~)tU2o z58ca+TrH-^&*x26H%rDejbX38m5$xa`1!}PCv$vB1JDL@88k6LX$L;YpL^P+cf#$B z_hzD4JpJQjyw=q(@fg|F2T)Ah6hENtx1~IvS36~4AvY4u8s3oRwI{B_v84H1L~4$k zTio>Yy^(mKI|`|yQ8sR6UC6Kwacv?~mTLCKjT@oh`vAZK@&+7PcmcWK3^{rI|JdR| zeWz{LyoA#C#aUU4f0%`w)?lCU)z}EVE6ABx$*uIPB$y z@1r&Z+FsmnP=TVA6)Qqil)x}*pRb>rug3+ir;d)Y1_reH1_s?dJtvBW&qlS7M76x0 zo3j)U6a)hXs;eQ5_D4TP%biX_3-tlevyy#wtx3QpZ*Y(r5-xy9Pk_4N-k+Qi-}Q8c z7W@?CDMSZV@R?TA(s~VCh3=yVXXf8|)KIXyOK7ABwnf&`NjjDwVk*2;E42$o0En1{ z(9pjG(CFcgDhv}(V|6h?)4~N+>P^_+aV&Uda>dQJ=isZ6ad1YOms5L01zv5&4t8eP z6xEln!lIAnNLCI$V=$CNvgNqXp8YLWRY<-B1PEAdHbyy>HmaZD( zP_&VnIZI#akn8f!(v55L3!8ThADCL{d-g>Ci*1l7+M~be-+<&~$_Xt!g1oSsljn20 z+A=#)E$Cx8rySQ%P(wYP9M|ZpQ#DmwAq~;ln-CB54Lr@+U4z@n>esAoZK1L}3FiN5 zNaQ*Hx?}!zFIQKe8{#~!K#9>1P{aMYjOmNVl8%R^a7P0U%c>U#0OFJ9Cm5-WzD>tMb_&Vv7yF;U~ zfG-PoE+v5=emVLQiPVMk1W1iEl9Ifi+7qOtrO$onF2Ci zYsOf~W`?4*TamYuVTij7G0O;gTf)}61Yk;F#L;`tgC6fkKPui#%r42)hf8xAIO{|| zS5?iE_4GXdXcm4v~)rIvK!VpSJ&jCmeO`%vjr{Z0Pk)7yhLDOgw2B2J8#xAjb8SjE`9kj>Ap_o^M8-3Ie{a~88r@;Vt+y zRn*~>EiH<3=x{S*E%(Xr)V-ZZw6dJsw!-GC*EO*LorhO!g>nAt>j;#q#=mj7Gt$xF zd(;a{OYs)s%wNOaVztfn8ML9w z(KV#odK2rTV!OWOcyG6CS5lmZGsK*@V=hd;j|!vdxr``aPbmBAcjf9}c7y=o=%n9f zin?2V)SG=nx1HbLThjzYVOFF9A=tKz(D_N0Zvw``yjElFZ-)msn% zpGT5<^LFFCGwSDcrZ8R;>iWh9{I{H8OZhFl1>3m*uf0oO)8#xEnQXm{cicoU>GLyc zKZsAuNP0`K|4j3Sv&om=^ZwaMThxRtV_DWX;wrwTIHTc~=_9fJ0h^BSP@&8mh8aIo zZ#|>Iz&6W6U7~~H^;KctJf!{+*-rcy(=%teHX<4R`?=RhN7-H8ix40GEc4Pk#J{;= zlzF+Vf&ZU3NL5p0NB#ScQ=(69WrB+dJWk;9yU73h=F!?`3Q7M>mxKAejQ@Fq`h5+J z+%~?6f@#YC`AiDgZ~@WVtHVW{PBU`+|MQo$z&ZORTvH+Vsa@D%pA>#2{P$7macHz} zdPWABLD>MK#NpKe3@)IdLH~y6Kq$01BrpDZWa1M2f4@TS9x?=si7ShEP9DM+3m%hy Mr1B6W{lxG80B^L2VgLXD literal 24232 zcmcG01y@^Lv~94W#i2;C;Oh>EQVVK*kr8Hf8hIEvy3|o(7(WAcf8+;3B)X>&=G@0E=Y8BsT^&snqN-c ze|UNMS$S}fWo&M?yP)c;*S=hNl66vga3b&hsJ!}s{}FPw))|0^frBcY%lY3c(i)8D zB_a2-HAC1gN;eErLHCsJXZ_2-XGm$t1s!jJ4}~Bj{U3egFG{9gSXfq;g}Se0xPMgq=CA>p|0ggsgKX!KZRZ~+_Rdu>62=(yb040+ZgA@f0_zuL{dhdF+xv%R8EnJKR z`e*ZYn4OF3>gjUq^*q}5JrNNDBO_%XBwrB}3IVsawsLcG&+2&|C%0Wu>)r|`OuPY~ zEH~e_-mW}u#mg@&ECkS*dSeppEe15!5PE1_(zFofD9b+}o>%+sW zE-W-%ZgL^>zQQ^ibe=v=pjU2tKDO8QI`2UkE)JmrM%A|Ncd(wfi;R^F6K;^#Ix075 zdvQ>4w$C@-adY%=;SdxR1&szx_L#%G3d~6xbPx1tH_4UiXug{!j!*ul3i(<*C8`5ej zDoh%`){4^Y4o*+Ulv(;{S3GtzMV{6%Du09>Bvp7_jZ54vIm!Ff>{7V6Z)GuPX^B;} zE!d`oB8A~g$0|uSQ9VK}H+p|$KHg&BHI?^7^^y6ul$Ms3m!o~&bmrI8*0v_-g~Jex z$(D(dKtn?-*KUxbQm$GAhQn~R%^NzJ6;ihr>nUwviEO*FWSWM{PbV%-|7unUY2&!g(Ed>QRWQH(7&3)UeR zWOCIU+f-oThrRs!!J?3awb;kKxmwz*K}Oy2pXAnN-zf_NmDpsB(*AI1#--2zkD`Dj zS)6%SAG8{MMU({Wacs6l5u%>A#DYHZq0u5Qd<19=O3ou&d43s8^z@3j+wtVAEDnR zu^CV4&<%FiwPRl4?>{Jn7fJEh>@79(Qbm5lK-1OLb#y8C^2yZH)YjIPe`KAnr@vp) z&8?w@dbvr+=gIv9m~UP8ExT^&gwqA?MoVRNE-NMJfRAGIN>+{$>F2C$%9-Qdg4?=! z@2vzV9VQEkEI9?*16?$@q-U#6Eo@1Ql8wLQGM1d}9Ue})c&j9m^9-zA-ZwQhU8Js` z!;V{-UsS2d`C^JEe0R;qWK%Rs4R{Wk_5-D~S z7P3}1`WxlIRFH*7tFM1q%`4F{IJqR7yzAjQGg(g>xRa>_0}7j?{A9e3e@;(^$eL4 z*Gw)i*u`yPxQvjBr}_9f59SLxI{M7)>@HvQCN?!SwNJbLN}SrVlC-t8wNtVX#{Py0 zmD~94fVdNGRz$NKhTX!HVH%C{03jA!P9D%}5P2aD7#4{-v*dW~NK+ibg_c*EQ))l} zIdG`gCB4TFmxM{7v%jd+GC4&bgX5NcnD{~qd1V+o8<0Fl#b*lTW>cPB68P|;1&Q-t z&o%Y+?M1HWRf;mW(2Uo+g6@YZL&m>4#x}F1BG7UqnfUAhZD6mGIPsB#^wCp56v;6a z8W{_Y6}zKzyXLX5yoALSnfeICDS~s^{PFv~!s%p4yANt736JI0Co37;czzj*VZ5Xz z?qSucvv7A$>8Uf4)O9*NJ)Pw`uA7t_`Xt;(!X>NSuJBwfxN`K@fRwkD1Z*0ehzu%3l3O9@2IQClmn8fN&j@uCHxUG~{b{u*!0P!2 z6`b{&Ar|8%k0zHd^sN_zjIBBM;z98n^vOroh{!11MgQdmmPz=}^*Tp1M!JefppsH0 z{xL9Fq%;*HsSZzb#OfDmT(d+cH+P;UyaG;grzjJtB*M-kK~IzJ;F~1;+_AYI_+TvR zv^kn5(`4NuI%#`*)`Cx;fOXtdsqePz;xVw<2(h(2o^5}*UN>a?rhAYL+0FKS0Y)P> zTjrZ2)`7h5!=%_QMTjT_)CE;a8CHwKy3G>$l+NRlO2d&!B8s$OLjual{iu$spjz0v zj21!sL6jEDsZ$xR3w&V=7sCyLfK`xAI>cS@JqfWektHiry-0$R(H{-1t$!Bv z{w$wzXFqNS%}7mz@d}PAC@FFHzC6jM^I(Z-P@OB9Zrt45Bqb$Dka;Iu_kEKLRF)UI zzB}I>85scw+FvvkCXA+WA7;PaXX|EGlcGe0$(%$oiX#?5_VSG5k5)*&Z6~s<{IG;F zpw!?O%+LMAfd!dZgx*{!BP}xP&Lvz5)MT@4CCbG+?9rr3U4hhYhNVNk(4V%*?}oE8 zuT4-EQ%T@{uSbTmSts?jfk10>?346RatZ~#O6ux)Q#uqy+)#)@%0X!VTUW5=RY$|z z@moYg3X7YQx2o#IojEM6j{Y0SGR`AsPuoye=j`IrQ|La)_2tW#_M7^uWyc}rl|BUr zBiPYDfdmqMVeE^V<$ZFKb-~_w+!|q_=u$;Z@Q578BJ3yrAzt}oreih!4*RaZTEVF zhX>mM_$AdmYyP(_@!|ZZKNeh8X+@T4=2;#)*R%TV?&lj~=1w|!?d`soJ0te(&o?j6 zkHGaQH^z{_r@g(h(r$mEFj?>0{?+~@ZP7X#1>1N($*~lt&YR{IRM%6|xfbXmm*T@; z+y$h^FMn8MDc|X;3_fXKIy~OQ;?U;h9X$Eis&Lb=bQ!*X&qb&iK~WwEB5r3G;7~K0 z3xDtay}}~Raleqe)+~`@L}JHT?ECl!?bJC+Eg+qvlM2qw&hoOct=&Gt`E?AZatgiv zsD{G=ng{$A92;6%Dx6)_(y~-Gx6u~}z9mp5(eW2}Z1!}sm@JYr9J6I7@dh((S%#_z1lJuY!pV+eF!Sri1M2W1<5~C0926gY4uI9EgoM z3)5^(yKi>tmoz0F-hoC63CLNOo>kp_tODtsOwfDQ4{(k0=vcx$OoKR}%jg1P9%lgH zZk=mZDr#AH&dX=)ECB^c7~9AGOizDQ?%;mP?}4|smAY_1YWSR=5RHdDZ1<`oc^L^$ zFYZxl4f*TRbE^LABRh*nipq4^!!{L;@>bMK4-w6o)H5P%9W-|lL z4@JoRog}T}I6Q-bTCt-MaN&nY}p9Fnd zqs-PrZTRfaj12)U-Vh$UqXhrjh(;Dy+|PD%;h5~dpQHL=pTJ+u%tsj#6Qx~$xIx&^ zs4>}6I!CGBN%*)IaCVN8|8^?u$-BEg6u3Ph!LBf|z zugmbKQa7NgWrF&ftSkKapEZ9Nn#D5Jwf8b3Cn__zU zC)W0*0a%x67HK)(a5g{9TgyljitKO(6oO!(n#@>B(?ZyoIH4@R7g97UxesqB3M3_( z@+KnMl*?EtuycXHb$lgkt_WXu+q#JQSLUPll0i9Xu-B(HIRwBb3*7xv1ivfB0Uy{Ili$!x4-45Fqp|<_0rlR*d_lXMK5#6Mai`+cT(BDuERnt4K zn;c(ZPHvE>sw%qm*sikwM-t|DBq58d%6UIYIcua$z?GI<8mp?75f3LZ{ywmrp_MR?X z0N4=sY_^Ye{F&8)oHwmfdjNw2BH-O(ks7u${cM5S>>30_Jew?NQOtZe3QQ!RZW(ha z9Q)RzHvm-7q&4euNLy{vN1vslN*@pay{6_uE38pEK8eEi2NiIA^}5j{CVFSDHidK+ zdJJ#yDp5B4vlmHg$C6@9DJz@)6p{yJX*2xUNzPvH?UXDc zV%#YJ$<1Rzfe{T2{DN-NoKmmN1TSdpDi&&~^(2P`0pE3@X6oOg45zEhmGtZ<E(!W+mt{6IRaGp-Sr=7R z%2-J%Y~~5+ruCjMItaW@$ahfeSN{9m2-A> zu4`zB_}PFJjyq`S9?7%+@en2P^@_F}uL|9m3&0SWRrP*d8gWt4N`i~%K zsg?K}Gh)q}6o7S_nx5`ymg>0X9q$Fukh+>0KHJ#hZ`;SKN%;o5<%jb=GBUoeIeB?` zb#)1;>%oQz2?={mm6mChhh4WbhQVielU(`ZduL~7{r#ba1mSt)8-M>QkYj4pS&Rd~ z&}=NL_3L^U8UYHHwwBiSF=p}?8hHTI&P+{3wuWIc7;{UddC_>wm~{`*Kd9oAM%^(PIJX;1G`0$adOv!wqAZTaB}}xnwVnFDKK`R?gfHi3XB$k1k{VWh9)Iwz%mD#I zj%h$eiUiNVz(7D>OUap&J7>c89z95`sq(N%SWr+$Rkhx6dk~eSajm>|RGPhe+yWqC zs!S5`lP7zOJJZO-B)N#5AAnM&!rt4O2``Za)4|={{q^OUwf*U$3}BiT7Ep{UTdAbP z`hn3%PfJT;)o(NE2^Xt3vCN$_C7jntDsaWsEy?!gIh*)G(zS{;Ze(kwGc=4IN4{CN zQ9(LY%AjqY-1$KzNcjhvSWc4`zXSLYLH&CDp=V4+zb?!2@W~OPKK*lF;Xe9E*z;FI z@Caj9@mHh3(LlnXCW*Sc%<10jmnnz)ZIhEFrIl!Dja>$c{?)_0n+(IA{3UUfUl?GH zi7;>VXcB?mt3w^*uV2qH-Bt_(eE^a=JRBu^OkG!Zd1{KPC(2du%e*vEFvXOK?Bts_ zZ&ti6W!qP?KS1F`-Q0N7dATd4h|>Xrl!%m6?)k|WzOb&n{S}}CJswiGRgO@n+%BppdugMwVeg2mZ^;ZHRuubAXa$x(l~XalT_gR5gcpVToh7* zmKC4&`jxGd(A-Xoi&l&z8K|_hu5lP0B$JQXyoCV^`dOmbV_6#{RlAZsT{ok?f}o>~ z$kO@CBRNm;@mqy9i=jStAo+sOPmXlBY-pHdi$u0(<@3dm_3j8G;x9g3MGb@nTwo|U zYmkw{R;5xSbwma}G&MKt`#xU-K;LXAiMg<_5TGYiRaJ+QS>Gvpe}r|EQRk8r+P}Pq z^%HG^H%TiJq<3YQ&-Xx93=9QWVPLg*oOL2L*so@NyTPX3<}A)CNbq?AR;=&SdHd^Q zdpj^L00BEDHt+a7kH)Qd{v^~PG&I}i!`(*2aRL}@*ok}ZPIjYRrV7gOUmf4y8YRHA zF^eAi%h4H@TH=8|&L-)>e|2jfvdm4%W!}?7fB6zAXiuKt5{pP)8XmdoDL>^#nkIn+ z(zxL%RFUZn@8__`Q{AxRsZ11pw0Yc4-lQ*9QLy4RXz`s+tFN~ZGDo7QDe8<7L|*C` zW0A|?tM<6u`B&xCjtMi;)0b3M3SSO$>gr>Zn6UPkG-XT!m4*3eMx8X3bH!Axc^b_Y z0VO4+=grZ-Zu8o&yl>_eN!*tPatSVT?Wgg00qHl*O#L0j+2}2I;KPrm68<)_L%rOO z-R?^RM@ik!Gc7)!r|Ih>6rDLmhtja|%l@UXe4bf_{N*s9(z3)>&ps6mF^lfFU7{pG#w_p*URumD43Z)j zUKCGuPbdNN$2a`75&ORtFT5JkK;jf)E@7YdYsW}m57di?v-Me~2vqTo3-b$l;5w%) zH4UZFO^RM#UH~p_dTPpq9JRoX$}Fk;=g*%N6|xOed9;*0N7c~Ii6)2^-`BN{g?j7k zZwDn^YGyVQl(&%-XtsSVZvXO5u}CJ+gH`2(H#zVh)z zu^MjIuoA9tu{=fhhy6|c=YuU}`3eIow0KwdF)MayPI{{oM-GW3PyCAO@&?3U!{KZZ zk%|rSTUKdCPkyi)1W1>=zy#br999)S<|c)_F&K!W-cO>-rc-iE9(L7EGUR!z9m~qW zO@R~0^ByyqMiBjj8s9^BSY-*OD5z1A%BvkRs5T`?S)h1EnP1e^t#~h#7WT=+U@$8v z`?W%GhOsvdRuZo8J5rykCyu`5s@w0eVih&3)>cKDb_IsdZ0y#{6RWB9Q8$=6i&epe zGB{ZtMbFmy0YEpt4xHGCD~3m`hTWmX0&503zGT|WXU}6Cj*E{TGD+>$FX=Rf0Hxgc zm){QcUmpT6ge7nFc8j^09UWQK%#m1-a;S!m=Eh%-YLCI#Re!DM5ZKGOH7?ze)CsrL z+FO%L*n@LxFk$mq(#-BJQIhpbw5Rg`(zFhDjD}TN-s5su)s49DITSty#33Ty*A-Pa zliBA?su4N!BufNZucC6IGfFfYU^N)q@pJr(06oZ4^m^F8+1ZKt>1A2C*YQDR{#&@c zV`ZzUqZJS{M|*pGfEJ<5@-gGGz`aMu`6mxAugF;k+&@tOSHg6VF?4QjPNM_Hp(KZ3 zAaktC&?OHR1U{N$2ZE;_^_>kU=nM5mkZBdmx&scgmI*OJCKhbx8lBKjmY=1zd^l3v zvCSIR*7bFPvUw?&quK(eE%l;wH+yI;@QG4$wkUJus{cNc?eSH+l>1WPYuSLY)9f42w%WbpcLV(UMgZxPHEC^*b~tZ69%X>+)uQ$Sha2)A^UYC;og2B zK{in%U8u6&F8$axV#}%KE;e$>qmx<7Tz^<>C+-Ft6l-3l8v6NsfHs#?x$bi2CjDop-wMkIrZKe+`bzk^OV4}k@ecmVSkC4e$`4UQPoU>3j7 zh?4kJivDx{RTyp5@e)7XYLHR>-Nw0-e8Z0cJ8T@Mq#{dzGnZ^7uZ%BF%s#R@0ffhK zfcM06>9rYbY+}>KJr|Sl!gdz=)7T0hJ)5%Agiaz? z>SF{6&QIT>N1~Y{D&q>N`)>1(#r$swBkb?nAwFA>@K4Kk~i{>d_Mg(Pr_zB>VEa zbox84*%gUzUy=$ODU&O56t8f^&`3}X+VZ_8ecwG-5c9uYfcF4w3ICkW^oDAaPh3$& zl{(NOt@ni}c>VGo5O1-ev1o7KGV3(51z-=Dxre)?i~qMn0F#ybDa52!XnD{C?d10H z9jl%ouqOf==SY@Nb4|^}>FwjQ56A$I7(E0a-8{d213-m2;I*^cLl&oekiDd=pmIB+S1XM0V&PAT_^W0ZP}cQtk{n zmnA7Z$bsWWhapC1*sIACyT0!~``TrFM|&*rjQU!bjAkHq>*Bv8EuS^HzEZNjUenm@ zoCyzWrJqetL@|y`Awg-7yh%pZ1&@ztz!e@X;&YT{UBs-RK%?#x`xgk)Fr$7d>78Oz z>DdiZQqq(CedHjqBFkVg3W$x3jm|FvztvNWHvs@3@)P~8^nvZ)g^3ab?5x2dA&ZNP zK-uQA*5S9ZvQksSfp11mfCdP)q1Ge;tq~ z?*R%hwta8uIB=CY#!n>C_zdgrD7+)oz>K8F9j5MR9~0DF_Qdd#;b}Qw22z+}U0frqdpd zQCYr;PJ_Rr(B#;`N|oT)9-IoW3rJwkdS!e6BARj!$Mmtega@e-TzR@AQ^lPe)E`HEx^0xCOn49O+F_n zt?1KZ0Ak%8&CJ(h=OGM(RJJ`FOqZ!626UEhK{`%v^^AL^BO*J0zn_XSn@&xp8nA+G;A0Xazx8eNA$CsX!5)WEf zwZ9;R&7-6HOywZH;`l_XL`BF>82>f#{`6J&;n-eY;Mv*toZz&2IVJz#S5H0^5!Ub2 zYgYgoicE_3h7c#U$YZNN7H#yq61l0QG6A80@Y7j0P=PylFDXl(wp@+^GtW>wm_D}q zc%a_?FkR*20ytRWY2`&V#oSL%OXaMmYmYWkN3n8je;`WWOuY9JSXIIHpA>2z# zlHPI2R8gU8@lk*mc?X9?N8LiRT+h6q1qp?mjY~wI%#Du?sk$R+(%_NcH|}InI?B%) zeja$1p(`ydB4(8#PpY}hhq}4BovySBEVJgu#>R46&v;#?uMTV5zwQ@j3-_K@JmrM; zXDU7I<-hciiH!QsJ4)CHSZNIVhjuBBk+uXN1=8W+5utwNb9F>4#${>L^O6D0ZK_*a ztDb9%6Q{PFUEkHoB{mMTTzY~rZgbnTI5)nqzcy9gJrlh%#MO&W`TjT7Gxv>;vN|88=LC?OakRL7x`e*QW?XJ8eb;p$(C|r_}A+%CkBFX_Pk2?B;!EP$% z3~g9k%n#+FpBoM1zp5Vh1l6T%?IALAHy|3E--yj-1*-76A>k;A>Lu>H8bc6q>RO>1 zuRn`lhKxCg3aw{J4R1U;87%v1>2q;;GSY32ESq5j3&Tdn~M3szCtGgdeLBZlM%v*6Q0mDF(U z<|=AgqNHf3-+I}xpC85jLxhz3JY~AGvdQ^Nu4O@n%L66{LJgRFdv)Avs7aJ ziQr6gZ$}zqFhQm5ddlang{_smeLYp;n`3QdhCt6ci$nodBFMvRLjt>~HBMKn8R!02jLd$^i6k|I-(cpS) zI9UMdztaCKaKs8e6J-&jc|*~6+4HSsa7a~_(lTtkgeh$&X~9q2p-xOptJC~WpB%ol z3{Ug?zwzoqkdA{-HEe1*{GQupHH=#-4ScNx3t{#a6U?zm!aNXhrn|uk7UK$UfA!Xe zxla9;nW=`T*ey4Aiu<`Y{4Gw#Eu7um35={*rA)zjW4pwgF0^bYQYYHKub$U2WXu}^ z1bW{P8)O}2sD;iA5u#v8X{M&Rr0Z&&gc=1}<=rvRUB00}&rZF8D~4gH4(7*tBS3?S zyw7ovzdmvH^*xxwZeY`v_9v_=a$&T$d8lWSZm{=(ZrXe+5u8_U!vv&AgCqsU`M~T)q?+ zS*qsL+HN7~$F9`1l=+HYYkpmOoOy0s;&3=vPRqGzf^d$GIvOW2a{pRF8yL!WQLP@C zP8IlGz||&lHnW2c4eEPmxJnuQ9&32C4-6f4!aeF%KRQufnGGo{Ov~E}oI!xXeUF%d zmNiGvA8jSj6V2gDeL!cHlshcBEf0RM!rtY1`;#Fd;TKvhCVB#ID!I-wf`(Fxv!DVS z*oZ6qcGZ{d^(o752OV0sG-+B`ZcZ6NCuu{NJx2S@RJmM6T=C{)`7j*q=wlA(-@tfd zh%A|<@wkwKFSU35dSad4Zr?OtgQ_>h=IGab?Zu^u;ia;XRv>C zJ>QZI*1oVPGkjo{e)P#Xe6w9Z>!dOw#N*k+G^8P~l$Q25*J`REW9;A}nahDp5rR&# z(Cl_fz$&B|Yw!5F7O)aRW*49C;nRRLD>V1XzLm|$E2eH%spE^Zin`#6j_4!=A_)px zHI9FBsjuPks3B=6-rdvT+}NB@ehT_Cx!nVv^QB4{u_WgHapzTfbR3WbZ_jI4ek3z# z5KC!nn0EHKN;XQ{-iOXhl8Ea_;zKUZ1Nj3^Hk~li=#OK91I5$GO3%6%CkS8t{bbyJ z6$sHAcn-k$M&_fjchrSeXX8}Vdxobzk#(7d3`ZJ`T?|P2{O@g5L z5jA!vB56Nad-35eI=@qpATp4(IJCD`=H^l=!6pQ~mt!LBp0_8}`raE9zFRMyh~5}N zTV}3xT!a$#rFF0d{E2WHZxBG3+473hCa!k)?{s$+joqho?54GRQ%6{C%WD!16pS;I zBFTb|NZV(*K6^yZ)=Fa_k?lUo4#_x;)o+vXic}AP8RF3o(Wmgf6zHqkV72BPC|3&m}X$t z14n~=esL3?jGGLZB5b+6`)uk59$zvP?C03$uu<#60Ia5>iL`wHU#fO>GxFYi3ogZn{&GE5eHKCqpr5k23+wd zY_<0<&5v)=JY$DAU`u9g)tKDcSABO<&CS?^ctL<^#&WW#{h_S=+vNyvEnn_o<7c}8 z$FZ!x00f%<8(4rU?JG45809D1oJ{IyG`Ze(@Pkxg7fl3iK=vRFrP;(ZBF~>zeSXTO z#9k`M!meSF2`Gq{?t8jr z3lW4hHZNm;Y8+uZ$?=D9$*wDV?+`bggfcSr5d3=iusIC6Ei=S;FPEAZuKdYyFBxM?zU#s;{bF~q_19><%oo7LYL=_%bvN~@vL zajjt5TeP$?8^R%3Sy=!-M?sD>cO)ug_)F*p0fXu%3?b(c?%Agsph@4ZEYuviz4&n6KaQ0w85S%iAcDT96=B9Xeg0DSs|+=npm&WO9QpQTxEeQ=M>c+J#=)X( z$X%YPYB8JM|Dn74p4_eOPWNOr=~R(uRi0KZP~W4FQvyT7u_?^dPp4U|D20sfo95@N zt^`As;E@^ldBFV!2o6B&*;^sUrS3%PA->5eTx(&)xKps zld$#-!?(A>3MQ2V%gA56kKHOznDW`QBOIkLPfW=SJ&QqmBgXx6RHK;eN_*u}B<8Z_hjZmVeqHSh*># zwDe@L;q+bmT~9;%^KrUe)BZnZ?F}MgZQ_7~pH3`LlEB6Gr)YfZ$pQ*6s2@$L>|8u&-(m4 zJ~N|GX|K#sNI=yJuTv1sm2mgZ*wZ}Tm^=fb2Jlh+f z_o|+OY4d)4z6IQ3CWiv~{jp^s<%QG$%9>B;BLa3$}K7P6?2(Lta- z1yw7COk1Z6xa5tW@8e!h$ZyXirB;~S4BHvQ{pFxc%cf&lIs-LX^U0_`fyMN*zZm& zfzrI|QPwJ-EDr12H*m?4-93RvrU$0kwch|dc!l+maqeT(CsCw}cF_`9vX zhS0w*B#82AS9HE^TVyBjY}&c;dk5uRQ1EzDv|93WkAvN zxA)p42FNN-G|J|C);C+>OWo@U3m1)Bqs=T%an*I0I4LrAj-l~MFiezDge~7K=y}3n z<7okpx;FgmI8SsMgW^`QA9+st%w{h67JAYM%h2HdvzG}~$g*Zh`wc%w60M$1Dq2%$ ztu?e(uw1jYC_mqLv-ih-ZxbQ+fbj3M^mGw`68INQ!iVLx0LxM8G$!PBu{AKyEN&Rf z=!gMd7db$JB^z%69n>OPqoC+C{lys|S|`e0(0PQwP;hNIdG(uTsF{(&$eGOgXWDQ5 z_d+NYlrTmlILL>Zz7d}hE(~lh*0ifR6FF7XcEX30RFE|Q%|SqNP$rz=<$g7vmZhti`o;V=^f%|d&ERX%lzl9LN+IE+|`m_UdBE02V77IGD zba>D^ag7+tMMTnC%QE{V&tuwjH&i3U&8Yi>!Gp7|PqF~|h!cPJpC9Gi6e~%%=aS8GWDvL9#$Vkb#>aKTN|mf%7W5T5)u;M zr%ke|mWx5_s@5BTy(1!^>%fhh7ei;h^|&15q{JoVeNWe8fs4|AdLhtH1}gvrJgZBk z5!z|MU6^1R{nWendubU-Ap#Njgg^G6bY^+f?~5$3ngagpTPRBp3~8FHCM9mi459Sw z!>0Bm4Y*YH`a3@_U4H+<0^J&*&3@W=*KR@3OF%E|fsKVs(cRr$1&~9lPa~^3P9xl` zEoWVPE-_>4pIo;Sl|Or5np$UGB84)8{&2AqjkG`8`SC9dMID3kArIR%*iAl4>c#ni zHvyL$I?345F!baIM78ADRy*!WACV*H3nfp~pnveQWZsCK4KfyQoe+M4%t|v19D&2K zJ@ZUro5jrj>TKuo0fZhfIj5|?_d|ew1uLr7vKCK;Op!3*2AoR)q^$Onro$CL)^gY- z$^PW1|10MyLcd%#RvIG61nRu*r%~gUU3<#n)vzf$guoMjeJg}lPGVgA1yO3u+qS}t z;CJVu&sV(#ziv8qS?$GveQflI4ns^Fdr>NfsY|azZ5QR@2glpUforr9cAFWjAwc}- zp{X}I!USa)(t&{Ow~$q^cLebVhScvzYVQ2*Az+) zBqH|jj7Q>jaVcd|&gSC_f$GqV{ql-TE!oN17zu~SoU2?`8sD-9M*93NDq4HX%eB=h z_~Q{<%!gi&r#pUEf~qf;36B2EAPQVl2&+5G+O(I~N9uV5-OYMDackGs)g=joaHOA5 z_G|&DN8aZm9w6s%+bLy*?ZPVKr_0P)^p4~^1l5*YL5%1b_0ty>pVi8a2u4qhKN2zf z0Z`hH)pa&?vXI2YiIkappkj<5n8PxT#UyEE^Ex(m0{-ILlSRkW6m}TTK(Y!7F?zmb zIAtn*xMKuk1y#d5<7M{|Y}m@cR%AA_Ne=W~El_H3t0S~52xwsJk;@Qk+<*K?RPZMJHAI#pLvF#klq#!`k1M&$mubmEHyTVh~ zQPkEZ4uj}mdxVduUfg`gybyW46tSKur#JJa@ofk^f2=W0yf~9xbFD-hJyi>jpny29 zDu%Cr6@K8_fQo%kc~|E`Fg|-=f#JTIKW#OVvQA*cU~M=I|zhD8<`*`GOm!iuLy zx23Ja$fH({wBl~8XX{FbK0=~IgOK$8T@6~~B8!o#s(QJ`dGqS?$-H@X>+{Xx?r^Fx zLGW3bVgE2kjD2Mu-9I|r-sdu1P|!G)qN*WqpOgJY;Om#arVOyBjg&fySmoVUsTx11 zht{f1O?GP4;fL}Ah)i#iPd~sKs3t1u*&Xg=hL|f&{@z}G@Eq2lAfI40n1x0F z&k`!k50B5cdShJ_g~v+q8IqaHu*p21(lbl&v3tT+C+)_@7-#CCucuzuvLGHX2RFz*DPxh4K zFo4Z}7rD&_m!SY6$iFOqi~ zE?w}kaGmh`5|yQ@cvj7tz+r|s?!Zh(daU-xL0_Yjy;reDVOTiHjUxhJsk7OtO(8XW z%x;8%F@Skx8GuO9z~R8v=jGLr6!vah#dr{T5tQiKQ#`{J@abU)o{8$A#FCjY617yCqU~Z^+@GsDlrUHPjq2BIN%<(#xsS=3ht(&5Q~0)8q2v zMY)X#@#C}T+yP0iN*+kCt1ri^z}c>5x-5#GQ@l~oRwp9a(fF`gPJzl7X4%^evnRu2R zZv9>)N@lr6omh{4`vI!`w^jBTwx2J0qaVqvr!?^$yBHn_s5x9w&7~ToH>aG+e_UTj z^|u~}m<_bCOI_VoYo8>D@!5o@+Pag}6yaipP5lkGp5KUscRYb2{GLac_(oeBg}k$S zazHO#Xs0VeD8cu9HF*l;YtIvCaY>2Pa9uJ?4~`fha+VlHFsZGD$jlC;an~j>mnF=@ zgBpuTVy%?Q!_Y<79N&I~pEU79tKCN%eO?NZ$jJ;L(9Q~#Q?Ewo@J6!^Hyi#M_t-h# z0ztOWRd}82&xFQskTx9PimNVSHi#0O+EAMNLa27Lh+BYtG;ialnBo(B1T!3tijzFN zSikr?-8$Ffg;VcS&&eWLC)xevCr|NST0o>;TFNMvDGu&h1roFM3>S;;LA1*-CXYY^ z9Ww70j7<~P`D&QuM!zIi#FiaFc*Gy*WK-s=M$czD{;;T$pI?WUu@0)sF4q_DlXD0Fs|f&W@GJ)YR0H1At(b zU1ou`%D@Hhr!w{XD_@IYcd*wsFEwrt^ZHG5Hs+QZ6#|H~7amIy+dq|yiC`x89ibsM^D=2LQCSPEboj{(k9gX55QtR#-~R<5&|VQX=tYxlQ;=9JhrlHVijR$^&38Gw zs{P38?TDK_X25HP2wl1`pbOkCm8RRAam8T`$0dR2_@Z8tDLy9Wa zU#eOLK)y-@RQx~Q2A}JR{~b@(G3Q{$9r|QOFbK@$+#Ssuvy^~BY&KL9YBwpvb{xBQ zZDOc!Ji?GJiikl-)Os4)dfV|I=&Z2bM9K1RuTKGATmz|Zp zy<6wvzP&wKs2}1+|NV;&-;ov`EnvxYvApmL99<7{thqBz=si4b&0Ulv9ku4UuX#Vr*m|DcgQ)3XptPZ^D>K;{%*ngM-i~YT`zfKAQ8DGuhxWu9@st-v5bcv zf##3EDXeBS*nNokM^E<=p|jUE7jcPs&K)9qp?0eH3v(QP8*sX-LI=tLS6@+ETiejU z`${MmxY0x%{1K@89R}j0L6|z-Z}^pz*XbrvB{cdx_OzBrVbe&&v?Y}hf8yY@KN8bKz>z(JRpPen0z&BDDU|_dS20n= z@X%HEPU~PPLY~)q2kMBW(UA@d<{gY!w68bw=JJ^zxE1*ZAX3tnz;RjOi)5nkJqjF^ z{wqSW_6Q#lSET+57oCmpq5)UsVtF6SKwTpiwtjE`F&x|LwGz zZSy0hrL+`Fd_vO%@1DnOh)X|2YPYr#w}<5xY$-*BCqOmr>t`v}O)d>}`g0)K=z=V6s(Y)@HRH%!8L^2so7 z#B+T)B`~SfS%&VyZ5UUq zOc_GSS$&6+u%ljerj{1&O2&pW@UvS5jRjz2K=vn3tlxnUlaQ=Qe2UO=SaF;VE%kRh z-bzzRKEpG@A(e)Nd3j77N5T8Gf3u0d+81iCJq%PdvaB|-ByE;Iq&7W@)2U}sU!G$U zWq0y8?|<`k09`0Kn5rkwI2UD_RT^m(E$rGVY14j}`U8cH;O0iBt$lIBVko|eLAx54 z+-t#(8iXTqdpcaLb3j92wyrWOvq;xkAO$Xniya6;o8Pm{b;82sg-@Rg%#+KrMq&qp z4u9S8go2%)bYEcRhZPn#ia%_;UQA~R4x*a&;%`5btPyZYb1eNB=-x)9|EI^YcWCbY zU(kQ<`;y4H=$W7ozqDI-^Kumu*VDA470QMvE0`pVoE7)@x$P5`k2(7Gz~95Tn&`lo z+XIoKj-auHA5%Z^`ZYjXxiUeG)x`>?E<11=yz}sl&2xS2D{ad3Cm9wQi^;serwMi4 zE~`%FJ-kyEK)Z(dM;5|JgrQ7&gU>n$fuwVwV0MOkp{&s~A6BP}o~3;~8Z7e^$5rDk zV?*ZPbE=K>_ENfZ*rN8Or3XZ&EINfA)L^(mY|$}~sZ0fPf9%B3f8~8U44E>O4Da@t z2Sp{AbwAhJ?FUOnZ=Kn(5Fe`uozT!%tUXHtuo1N>o%{~Sd2jPX<`a4ilYk6S_$y;Vs+A5EQCA= zf+YMm#6n56O~3Tr-<2GRXLnC6PGiS{gxkSj@W>>zYe((~&x?Ue<+CnPEy|GfSiGm2 zlpz`3jt8Oi)=1${(p)%24zsWaWi}=+MukY;aXo9rZ;x0pj%jyu^U3xR9+{LYGh_4; zp&2jV-!x@2ld87h5{XZqi*@a>WZKBd1VV7>6kyTribikdc851Cy+niV5K3p=MDw3K z5W$y&_GfIq=bLe<#nMDhWp;YQ`ZBe{6}Top#!m*aC9~&`tx^TS{a5+x@Q1`X5B}{> zzNCvdm+h(h_kmVBXKYDeep(saTZGK1ZhA?C;vO@ocn+7l001hQLW%^)_LU_c73K27 z#ku0{G(1AHqc0-7M&uAC{zTg4k^T4*SaTfK3R~zD*3Jso);^}kgt+BCGnPnSU*a8e zr2O+ovXWq`aC{t^8>OS(sPzX`*FrBvns1Yi;n2`{>sTRvNXVFAQ%QqrVr&Doyi- zUU7y))zn((9c_OJh4@PvS=VEF^mUc`nt7Qb`38F_oja1vl;)qQ@w+-XIy%03rFOar zY#bTVzHk5cA9tEu;i$(t3@17~M;kj9nKn$_d!|{Sn|jc^`)0QGcOEf@@z=EqmjWym z)ua%eWL2s{m`TuVl^2Cm3R9wgwab+8vo!Q^fx4S|!{kIfyp=ej5|cKFs1t|XpLpyn z6~K_JSSw#eLU{N9m7dO>HZZtadghBSAAZ=n>D4zx!&)Q7mHfbX#c!!S0_2QJGq^2S z04X8U;D6(n5S-enDs5N_b~i8hQ$If|2!K8CNa1BWA1W*{5Y6ziZbk~%ok1WQ&a3*h zM-tF5+VzFu^ErOXwEC9C-y2KPtlRaJ{+9-%*$)UILPBQ@D}IH;13Q@AOn7X7IQpF( zk@bDG6gbNwPwCi%U~e3&s|Cv#&Ggfh{*#@#nH|>S8iYt%%@up^a{;y>&%Nm_O%p(d zt;^h;-&SrQk>U!c?CljF?f3+C5EI5u-)d^wY!`T98UO629 zMS`4rdpl$0kFyODT|6zYZfMcj`H_SBV?z{ah!f?HyL}W0)8{?oG%sQbZPlig581@? zspAf%5%A~yx?nF&J$obNeFEMfG9YUpig9i`U(ddYyE%&k!D{z;xrgZm=Rinv-FUfo zE7w`sEy6rQHT)e>Ig0NY(`rB%z58XfODLyH$xnO?IxW{*1_aUh3sO1m~1Gtd{u z-(a8oDx+>dM{+5h(I=SuPd~&-jv=pyon%sB;#bAP(z~QhNq4$ItP2-g+35@8)8Fka z`2KnXP%kD(JPV6fZbST^coSUBcD-kKmOQ}~nz-<|T^KIcw{eHZbcf>-cr2vnpeKjkhTm*;;CMFOoy6t6v4cvVwE&}9(Zo7nlfm4W8wLoF2tolG$ zrvBCJcW@01Y7swd;1@}df#`)xEQSeq zfV?GUHN)3}{Q7?Ll7#U`#o(!FP9JGAm#B%3y;dsUvK{dkBVpUGA76_Lj-=&0yzuTg z6ttmZ_LpQw%=s0XO>7#^jX#$4?9(I)M^mX;{&ye^sn1~ZRu9VTF=|dVnT%k6hsA2R zq8^W+%+QW1i=kyBqB36VP5_Ayw#14j#BDS*G{BQ`IdpS1^zG#&2z@+zyO|G)f_ZRK zRr!uJ-@g3>n|uw)!*&470{Br>$ns|>m*1Vp6>vagu_#q!2Bw94AyB75zA93Vv}Ik# zv9WH^py^Sq+e_yB;3KYO4@!&7+JQmCELRD%*yQrm{)j5$yV5kbe)zmQHM-REL%qqv zK*IzFFPQ34rvgA9Z!w0X6L(djv9A)y;9xit82-{{moS2bdwcVi{*a zM|jq$X>NR+iX?1yX6EeoiRz3U3X}@;olmbFEEwYJH7!UVCWUJAY#tSr7z|x?@R2yo zPH+~`;CVa0KTet6QMXbko&8D^lk3oQbb#}F$wmFp#hoxmVMDxCl^R*lmuy3uCeZdv zh&*B{PW>_m-`_3l6E`FtJ06;gaC#rvCQZV?%%iGz|C3i5<$q9KQ>LryQ`%}lCISKH z((X&GWmui}YN=c!RQ&v$?8)aCeVPF^&QX3UQF@UFHYYTAIv~d1%_WZwS9rg2GgGS^D zT{j{!6R_K>nMQjMhmi0*GdO7K9WdXxyqNti9Z?!lp<#6wmD)e@qgDe7DX=?|cyAS; z!c!%M=;7T!jz5@YG-vm&Ny!t7D{hUZ1xqs1+KO!(rPo-npS^~l>wdgUuthB|FigyL zq%odHanXq=zU(q)`2otF7}1H>9~jR}A0IA%VHOUuY&p{Ts-*IoVEgVs>v9!1U62rk zo=bb-Ls@^6Fst|j7^qN&)hZdJ;!NtJcL3N*#{r8*n`1k8$VL=^?y@Y zk(o!xIW*B_2=^_L_MmB}%|hj6^pDM+Q=?GNsgu8l?f=2C#0skjc-faia9ayaK3t&r zY!Pizvkb-iJl3z2W2+TEg-lSg1n#BQJA&1{C>}UeD=#Y{NZI`@0aYD6-;3Zxnd9hf*-Lc%PK&F{tgg%mvbB_JUJ#lkhu zU<>iCALZv9@mHB&)Nk;pp~L6K&o(v|a8dOFM2HQW)!zT_^Xk_&C9(BFj1i<}EX zj2auZI_Yhy1PZIh5ZAG6k2%hb4dBXZ36znvw6=Q|{^r0+VVk~JXA8J4f$s#goLu?G z$H$;=rJ`TaYUUF!5fC(5#}+oA7>O;NeG$am|ExibMKH53HHn5lnL$30MSB#Lt W zoj1;{PbmKGYrBr*-xee+E*-SLV}cjH=o?5Z{c~r?dRzo^a7W>h=~}c;iv^DA*7&Oz zy>QnjY<6(pJBIuJgZhS!+c53fBq!ufC*2UYt5J(Tqf_BVKXNx(YYxOQFNi8Va4M&V zpm_QC{DDL4rM)a?6`n45t`+pGxyd-3k2y3oBO&Ph zoFzU9@IHB_`cO3q7Z&}hqu%q`(}X6RRQVw^Ej?SCf|K{d>gjVKx{sS?Sx?YOw1>FL zvw@0nk5LZxMDuUnYg&X?V@F_|*H+e6@h!aM?__1?%Ku20u#CWfkY@4))zJi`{nb6v zN-!q@JvB+-H&f&TYisPD6M2Y7QB(~3_rS;RmCPk!y#%>gju;h0squj24LPcpow`jE zGwBicSf1-i-slfTyS$L_CSDnoYeSmUEaPU=&sX@6$CiBbk9CO`pnZh?W9y8@2Ffbu%`{YId6!bZRE`?_)Uz8Ry~}*vU>dt4JcJ>;x#ExpES%@n& z1y*+?m7eGV=HoVzjeEzq5K$*{oOZoz0?j^Nzby5l{fds+l)wxgAmoU`UdjA!RYpW4 zh8GrZ-PUXX00i-{A@xt5c&)WQITqql$qT;H$KPkCu4X2F=8WNbU+Y=E{d$l~_C%x! z4xx)lp7f5P%JndSn_eu0CA>N#e_l*V&4VH>5EPyGi#pHl779E|9a|GU!iOAqTUV0=tRv zaVdb!0n%Q3_~hdcenbzW=ej+w9#`b6W4SH(-{-iWrP1H0B z`(C_JF6yz4MkBOH@k0LztGxz1fd^<6et$LFcs}41%eL#v5Um+=r!&4-S(QSMN|nM0 zN@qP(%uPQK9GZjiyDZJV@wrKU_;1Hg{MWqCO?7>i-?fv9QkNA29@ItNw+0kvCG$eJ30jmYH6p-{trkxp5 zrfO*{U6k3SOJ_TEM&BkT=1v<=rJ5FGlCi0AmybTWbfs0{tHOR8Tlqj(mpx+PaZKoFT$J2Sbvb$Ju zew4j`bI|sDu`zMOCu4hY^YeNwgEbAXE)wRWwObKge_c+vdfaoUIw5H(j}{)dK5)+w zqX!wDJjz(+ILRyL6x3cYd~IatXYsiLlm&8ru*!#GbHOnpg}j~j0?86lnowo-eTBib z$oC7J&}#2)#1zT{-jWnOXZZB#BdVG*y;G^Z9dWFc*wM{Mh)@$7fpWoO9K|uP(6H!zk8Nt*+FWWu7^V_;l%< zio9eT&X;d@mBNl+&(5Z=8CXjR*VxObdcPwl^17)15_zc;c{)EkJZS@aSMkpVapo|y zBo?_|y%TR4<&y$%qvR6B0#oqlv?JiPeljPywx$!4h zGuf*#sy}TRI5jjqOL2hO#rz|uA=3^%OFCIXb#L0wt?#qef4nrU`sS>?hCgq$v;_y| z!u^{3CEY#O=$5~IVL_z2aGwW$+@WYK9N-@VGBqQcOe)e9cmWk2#H^ufS1sw@Yw?Qu z3`>-@y`=enWMZ+Fh)1dq)5J%A3Dt!~LS(&XiSxMWyH{l!a z8Yx^Ir_KSxEiOeQ2FoE^CSr`YQAbY>iu7w*js+uMlO9Xj#W5(PHA6#vuhM};pA;M2 zS=hPi;^m{0!Di$iFr>J(?Uu#NV`I`)kXk^bB$TO!?^GnfW1zp_PH*8}_liw>#BoK^ z^T0Xr1$N_JzhBC^i8^wLhf7PW$(WMs4LJnTJVmC8G~abxf1%6%Y5I>`MnpZ!Qigb_ z8&_7fZTp6#Hi43^6!+UZgECDQU{pr@UqX;oXL9<3*IKi{-3wP&m31YE64Lq$>r6k0 zl=G2Z&Au@@kib!{>W2#l?U5Bb=6Y!P@DBIM#rP1j{jGcL+v;SpvUPT?fYKa?&sMow zjmuoK(FbuW+mtC?M1SrCYekxyCrTI|5<)+FI@47rdu<}vGvKG^wm=$<3o(rjPwK~4%KLsxmaO^YbMuNqP z5el@J`bHcpNggGi`E14cOM0LG39xM9A?2%xzJt_JQGRFxDKpzw?>pmSb_U~f&`6Z(Cv+*rpUlxmCnmgBy9;fl_e#TA9u-QRr`3! z?&&ZN7M*n?^;smnS(jsfz!@u(kI@~Q+?Hk* zn>$#1cc<9t;}cHyJql$A3CZZEx}b*MrZ%qxvBBs<9UU0fpiY7 zz}}5aY!tI-mxRa1NEGF=8l90h2Ap9h#@``p7yb1!4kl3U0})0zY^v)jb3N(KKnz;C zA_eP)zVe^@@x%y5SRZzVV4t-5E-I&&-k#xfP`qsw=*e55{ zu62BZf+z8F*T%RM?vNkx4l?}Q)6-KXL}rC^*m;x#1x9em`T0gChkn0Hk6`l!C&gXvL{GG)}u%G9JkdwmX&W*nEAuO5ZppDx&@)?xnpc2Vv&pL(XJhi$E@L5SSxC;p!A zhxwPh%USc?(x=(#e96ism8m%QQB0NYnDXom z0rw$G^8Ar>DI0=-MY2<@bhV?El^ks^x4W2-3inijuX^YF8rJKcLzVT3J?y=!-)zz4 zI5Y$<%%yXuqO9$tIHw6+$h}H$j%q`MfBp`nQvnk;GUq`sE#+ESZa185uxl)JIBy`O z?GAa*w%4{b>#?Be4r%rv zCsbD-@9xI6WxG08ym_lUjfETTQF!rbJTWCjro7zmM5dp=eQ|O9(1mVc^Ynyp!>8%fn2gyu z6D5xIn^Px(7f(q&AW&9?CJ3oqJ0nCcycS0mN_P9z5($JAg~4J84wrxg|1yORH)wU! T2Fd~TJmiVII;vdm#k>ClOMHU) From 1e2da0647c49dafd781da053867ebe7624929ce9 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Tue, 29 Aug 2017 09:43:51 +0900 Subject: [PATCH 216/228] Renamed Tokenzier --- cmd/main.go | 5 +- docs/.gitignore | 1 - docs/Makefile | 2 - docs/index.html | 17 - docs/jquery-3.2.1.js | 10253 ------- docs/main.go | 36 - docs/main.js | 40225 --------------------------- docs/main.js.map | 1 - reader/tokenizer/tokenizer.go | 7 +- reader/tokenizer/tokenizer_test.go | 2 +- runtime/runtime.go | 13 +- runtime/stream.go | 2 +- runtime/util.go | 5 +- 13 files changed, 16 insertions(+), 50553 deletions(-) delete mode 100644 docs/.gitignore delete mode 100644 docs/Makefile delete mode 100644 docs/index.html delete mode 100644 docs/jquery-3.2.1.js delete mode 100644 docs/main.go delete mode 100644 docs/main.js delete mode 100644 docs/main.js.map diff --git a/cmd/main.go b/cmd/main.go index f887f49..af31857 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -11,10 +11,9 @@ import ( ) func main() { - env := runtime.New() fmt.Print("> ") - for exp, err := runtime.Read(env); err == nil; exp, err = runtime.Read(env) { - ret, err := runtime.Eval(env, exp) + for exp, err := runtime.Read(runtime.TopLevel); err == nil; exp, err = runtime.Read(runtime.TopLevel) { + ret, err := runtime.Eval(runtime.TopLevel, exp) if err != nil { fmt.Println(err) } diff --git a/docs/.gitignore b/docs/.gitignore deleted file mode 100644 index c08f9ad..0000000 --- a/docs/.gitignore +++ /dev/null @@ -1 +0,0 @@ -_site \ No newline at end of file diff --git a/docs/Makefile b/docs/Makefile deleted file mode 100644 index 8427c87..0000000 --- a/docs/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -all: - gopherjs build main.go \ No newline at end of file diff --git a/docs/index.html b/docs/index.html deleted file mode 100644 index 37d7080..0000000 --- a/docs/index.html +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - Document - - -
-
- > -
- - - - diff --git a/docs/jquery-3.2.1.js b/docs/jquery-3.2.1.js deleted file mode 100644 index d2d8ca4..0000000 --- a/docs/jquery-3.2.1.js +++ /dev/null @@ -1,10253 +0,0 @@ -/*! - * jQuery JavaScript Library v3.2.1 - * https://jquery.com/ - * - * Includes Sizzle.js - * https://sizzlejs.com/ - * - * Copyright JS Foundation and other contributors - * Released under the MIT license - * https://jquery.org/license - * - * Date: 2017-03-20T18:59Z - */ -( function( global, factory ) { - - "use strict"; - - if ( typeof module === "object" && typeof module.exports === "object" ) { - - // For CommonJS and CommonJS-like environments where a proper `window` - // is present, execute the factory and get jQuery. - // For environments that do not have a `window` with a `document` - // (such as Node.js), expose a factory as module.exports. - // This accentuates the need for the creation of a real `window`. - // e.g. var jQuery = require("jquery")(window); - // See ticket #14549 for more info. - module.exports = global.document ? - factory( global, true ) : - function( w ) { - if ( !w.document ) { - throw new Error( "jQuery requires a window with a document" ); - } - return factory( w ); - }; - } else { - factory( global ); - } - -// Pass this if window is not defined yet -} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) { - -// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1 -// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode -// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common -// enough that all such attempts are guarded in a try block. -"use strict"; - -var arr = []; - -var document = window.document; - -var getProto = Object.getPrototypeOf; - -var slice = arr.slice; - -var concat = arr.concat; - -var push = arr.push; - -var indexOf = arr.indexOf; - -var class2type = {}; - -var toString = class2type.toString; - -var hasOwn = class2type.hasOwnProperty; - -var fnToString = hasOwn.toString; - -var ObjectFunctionString = fnToString.call( Object ); - -var support = {}; - - - - function DOMEval( code, doc ) { - doc = doc || document; - - var script = doc.createElement( "script" ); - - script.text = code; - doc.head.appendChild( script ).parentNode.removeChild( script ); - } -/* global Symbol */ -// Defining this global in .eslintrc.json would create a danger of using the global -// unguarded in another place, it seems safer to define global only for this module - - - -var - version = "3.2.1", - - // Define a local copy of jQuery - jQuery = function( selector, context ) { - - // The jQuery object is actually just the init constructor 'enhanced' - // Need init if jQuery is called (just allow error to be thrown if not included) - return new jQuery.fn.init( selector, context ); - }, - - // Support: Android <=4.0 only - // Make sure we trim BOM and NBSP - rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, - - // Matches dashed string for camelizing - rmsPrefix = /^-ms-/, - rdashAlpha = /-([a-z])/g, - - // Used by jQuery.camelCase as callback to replace() - fcamelCase = function( all, letter ) { - return letter.toUpperCase(); - }; - -jQuery.fn = jQuery.prototype = { - - // The current version of jQuery being used - jquery: version, - - constructor: jQuery, - - // The default length of a jQuery object is 0 - length: 0, - - toArray: function() { - return slice.call( this ); - }, - - // Get the Nth element in the matched element set OR - // Get the whole matched element set as a clean array - get: function( num ) { - - // Return all the elements in a clean array - if ( num == null ) { - return slice.call( this ); - } - - // Return just the one element from the set - return num < 0 ? this[ num + this.length ] : this[ num ]; - }, - - // Take an array of elements and push it onto the stack - // (returning the new matched element set) - pushStack: function( elems ) { - - // Build a new jQuery matched element set - var ret = jQuery.merge( this.constructor(), elems ); - - // Add the old object onto the stack (as a reference) - ret.prevObject = this; - - // Return the newly-formed element set - return ret; - }, - - // Execute a callback for every element in the matched set. - each: function( callback ) { - return jQuery.each( this, callback ); - }, - - map: function( callback ) { - return this.pushStack( jQuery.map( this, function( elem, i ) { - return callback.call( elem, i, elem ); - } ) ); - }, - - slice: function() { - return this.pushStack( slice.apply( this, arguments ) ); - }, - - first: function() { - return this.eq( 0 ); - }, - - last: function() { - return this.eq( -1 ); - }, - - eq: function( i ) { - var len = this.length, - j = +i + ( i < 0 ? len : 0 ); - return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] ); - }, - - end: function() { - return this.prevObject || this.constructor(); - }, - - // For internal use only. - // Behaves like an Array's method, not like a jQuery method. - push: push, - sort: arr.sort, - splice: arr.splice -}; - -jQuery.extend = jQuery.fn.extend = function() { - var options, name, src, copy, copyIsArray, clone, - target = arguments[ 0 ] || {}, - i = 1, - length = arguments.length, - deep = false; - - // Handle a deep copy situation - if ( typeof target === "boolean" ) { - deep = target; - - // Skip the boolean and the target - target = arguments[ i ] || {}; - i++; - } - - // Handle case when target is a string or something (possible in deep copy) - if ( typeof target !== "object" && !jQuery.isFunction( target ) ) { - target = {}; - } - - // Extend jQuery itself if only one argument is passed - if ( i === length ) { - target = this; - i--; - } - - for ( ; i < length; i++ ) { - - // Only deal with non-null/undefined values - if ( ( options = arguments[ i ] ) != null ) { - - // Extend the base object - for ( name in options ) { - src = target[ name ]; - copy = options[ name ]; - - // Prevent never-ending loop - if ( target === copy ) { - continue; - } - - // Recurse if we're merging plain objects or arrays - if ( deep && copy && ( jQuery.isPlainObject( copy ) || - ( copyIsArray = Array.isArray( copy ) ) ) ) { - - if ( copyIsArray ) { - copyIsArray = false; - clone = src && Array.isArray( src ) ? src : []; - - } else { - clone = src && jQuery.isPlainObject( src ) ? src : {}; - } - - // Never move original objects, clone them - target[ name ] = jQuery.extend( deep, clone, copy ); - - // Don't bring in undefined values - } else if ( copy !== undefined ) { - target[ name ] = copy; - } - } - } - } - - // Return the modified object - return target; -}; - -jQuery.extend( { - - // Unique for each copy of jQuery on the page - expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), - - // Assume jQuery is ready without the ready module - isReady: true, - - error: function( msg ) { - throw new Error( msg ); - }, - - noop: function() {}, - - isFunction: function( obj ) { - return jQuery.type( obj ) === "function"; - }, - - isWindow: function( obj ) { - return obj != null && obj === obj.window; - }, - - isNumeric: function( obj ) { - - // As of jQuery 3.0, isNumeric is limited to - // strings and numbers (primitives or objects) - // that can be coerced to finite numbers (gh-2662) - var type = jQuery.type( obj ); - return ( type === "number" || type === "string" ) && - - // parseFloat NaNs numeric-cast false positives ("") - // ...but misinterprets leading-number strings, particularly hex literals ("0x...") - // subtraction forces infinities to NaN - !isNaN( obj - parseFloat( obj ) ); - }, - - isPlainObject: function( obj ) { - var proto, Ctor; - - // Detect obvious negatives - // Use toString instead of jQuery.type to catch host objects - if ( !obj || toString.call( obj ) !== "[object Object]" ) { - return false; - } - - proto = getProto( obj ); - - // Objects with no prototype (e.g., `Object.create( null )`) are plain - if ( !proto ) { - return true; - } - - // Objects with prototype are plain iff they were constructed by a global Object function - Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor; - return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString; - }, - - isEmptyObject: function( obj ) { - - /* eslint-disable no-unused-vars */ - // See https://github.com/eslint/eslint/issues/6125 - var name; - - for ( name in obj ) { - return false; - } - return true; - }, - - type: function( obj ) { - if ( obj == null ) { - return obj + ""; - } - - // Support: Android <=2.3 only (functionish RegExp) - return typeof obj === "object" || typeof obj === "function" ? - class2type[ toString.call( obj ) ] || "object" : - typeof obj; - }, - - // Evaluates a script in a global context - globalEval: function( code ) { - DOMEval( code ); - }, - - // Convert dashed to camelCase; used by the css and data modules - // Support: IE <=9 - 11, Edge 12 - 13 - // Microsoft forgot to hump their vendor prefix (#9572) - camelCase: function( string ) { - return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); - }, - - each: function( obj, callback ) { - var length, i = 0; - - if ( isArrayLike( obj ) ) { - length = obj.length; - for ( ; i < length; i++ ) { - if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { - break; - } - } - } else { - for ( i in obj ) { - if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { - break; - } - } - } - - return obj; - }, - - // Support: Android <=4.0 only - trim: function( text ) { - return text == null ? - "" : - ( text + "" ).replace( rtrim, "" ); - }, - - // results is for internal usage only - makeArray: function( arr, results ) { - var ret = results || []; - - if ( arr != null ) { - if ( isArrayLike( Object( arr ) ) ) { - jQuery.merge( ret, - typeof arr === "string" ? - [ arr ] : arr - ); - } else { - push.call( ret, arr ); - } - } - - return ret; - }, - - inArray: function( elem, arr, i ) { - return arr == null ? -1 : indexOf.call( arr, elem, i ); - }, - - // Support: Android <=4.0 only, PhantomJS 1 only - // push.apply(_, arraylike) throws on ancient WebKit - merge: function( first, second ) { - var len = +second.length, - j = 0, - i = first.length; - - for ( ; j < len; j++ ) { - first[ i++ ] = second[ j ]; - } - - first.length = i; - - return first; - }, - - grep: function( elems, callback, invert ) { - var callbackInverse, - matches = [], - i = 0, - length = elems.length, - callbackExpect = !invert; - - // Go through the array, only saving the items - // that pass the validator function - for ( ; i < length; i++ ) { - callbackInverse = !callback( elems[ i ], i ); - if ( callbackInverse !== callbackExpect ) { - matches.push( elems[ i ] ); - } - } - - return matches; - }, - - // arg is for internal usage only - map: function( elems, callback, arg ) { - var length, value, - i = 0, - ret = []; - - // Go through the array, translating each of the items to their new values - if ( isArrayLike( elems ) ) { - length = elems.length; - for ( ; i < length; i++ ) { - value = callback( elems[ i ], i, arg ); - - if ( value != null ) { - ret.push( value ); - } - } - - // Go through every key on the object, - } else { - for ( i in elems ) { - value = callback( elems[ i ], i, arg ); - - if ( value != null ) { - ret.push( value ); - } - } - } - - // Flatten any nested arrays - return concat.apply( [], ret ); - }, - - // A global GUID counter for objects - guid: 1, - - // Bind a function to a context, optionally partially applying any - // arguments. - proxy: function( fn, context ) { - var tmp, args, proxy; - - if ( typeof context === "string" ) { - tmp = fn[ context ]; - context = fn; - fn = tmp; - } - - // Quick check to determine if target is callable, in the spec - // this throws a TypeError, but we will just return undefined. - if ( !jQuery.isFunction( fn ) ) { - return undefined; - } - - // Simulated bind - args = slice.call( arguments, 2 ); - proxy = function() { - return fn.apply( context || this, args.concat( slice.call( arguments ) ) ); - }; - - // Set the guid of unique handler to the same of original handler, so it can be removed - proxy.guid = fn.guid = fn.guid || jQuery.guid++; - - return proxy; - }, - - now: Date.now, - - // jQuery.support is not used in Core but other projects attach their - // properties to it so it needs to exist. - support: support -} ); - -if ( typeof Symbol === "function" ) { - jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ]; -} - -// Populate the class2type map -jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), -function( i, name ) { - class2type[ "[object " + name + "]" ] = name.toLowerCase(); -} ); - -function isArrayLike( obj ) { - - // Support: real iOS 8.2 only (not reproducible in simulator) - // `in` check used to prevent JIT error (gh-2145) - // hasOwn isn't used here due to false negatives - // regarding Nodelist length in IE - var length = !!obj && "length" in obj && obj.length, - type = jQuery.type( obj ); - - if ( type === "function" || jQuery.isWindow( obj ) ) { - return false; - } - - return type === "array" || length === 0 || - typeof length === "number" && length > 0 && ( length - 1 ) in obj; -} -var Sizzle = -/*! - * Sizzle CSS Selector Engine v2.3.3 - * https://sizzlejs.com/ - * - * Copyright jQuery Foundation and other contributors - * Released under the MIT license - * http://jquery.org/license - * - * Date: 2016-08-08 - */ -(function( window ) { - -var i, - support, - Expr, - getText, - isXML, - tokenize, - compile, - select, - outermostContext, - sortInput, - hasDuplicate, - - // Local document vars - setDocument, - document, - docElem, - documentIsHTML, - rbuggyQSA, - rbuggyMatches, - matches, - contains, - - // Instance-specific data - expando = "sizzle" + 1 * new Date(), - preferredDoc = window.document, - dirruns = 0, - done = 0, - classCache = createCache(), - tokenCache = createCache(), - compilerCache = createCache(), - sortOrder = function( a, b ) { - if ( a === b ) { - hasDuplicate = true; - } - return 0; - }, - - // Instance methods - hasOwn = ({}).hasOwnProperty, - arr = [], - pop = arr.pop, - push_native = arr.push, - push = arr.push, - slice = arr.slice, - // Use a stripped-down indexOf as it's faster than native - // https://jsperf.com/thor-indexof-vs-for/5 - indexOf = function( list, elem ) { - var i = 0, - len = list.length; - for ( ; i < len; i++ ) { - if ( list[i] === elem ) { - return i; - } - } - return -1; - }, - - booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped", - - // Regular expressions - - // http://www.w3.org/TR/css3-selectors/#whitespace - whitespace = "[\\x20\\t\\r\\n\\f]", - - // http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier - identifier = "(?:\\\\.|[\\w-]|[^\0-\\xa0])+", - - // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors - attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + - // Operator (capture 2) - "*([*^$|!~]?=)" + whitespace + - // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]" - "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace + - "*\\]", - - pseudos = ":(" + identifier + ")(?:\\((" + - // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: - // 1. quoted (capture 3; capture 4 or capture 5) - "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + - // 2. simple (capture 6) - "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + - // 3. anything else (capture 2) - ".*" + - ")\\)|)", - - // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter - rwhitespace = new RegExp( whitespace + "+", "g" ), - rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ), - - rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), - rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ), - - rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ), - - rpseudo = new RegExp( pseudos ), - ridentifier = new RegExp( "^" + identifier + "$" ), - - matchExpr = { - "ID": new RegExp( "^#(" + identifier + ")" ), - "CLASS": new RegExp( "^\\.(" + identifier + ")" ), - "TAG": new RegExp( "^(" + identifier + "|[*])" ), - "ATTR": new RegExp( "^" + attributes ), - "PSEUDO": new RegExp( "^" + pseudos ), - "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace + - "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + - "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), - "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), - // For use in libraries implementing .is() - // We use this for POS matching in `select` - "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + - whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) - }, - - rinputs = /^(?:input|select|textarea|button)$/i, - rheader = /^h\d$/i, - - rnative = /^[^{]+\{\s*\[native \w/, - - // Easily-parseable/retrievable ID or TAG or CLASS selectors - rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, - - rsibling = /[+~]/, - - // CSS escapes - // http://www.w3.org/TR/CSS21/syndata.html#escaped-characters - runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ), - funescape = function( _, escaped, escapedWhitespace ) { - var high = "0x" + escaped - 0x10000; - // NaN means non-codepoint - // Support: Firefox<24 - // Workaround erroneous numeric interpretation of +"0x" - return high !== high || escapedWhitespace ? - escaped : - high < 0 ? - // BMP codepoint - String.fromCharCode( high + 0x10000 ) : - // Supplemental Plane codepoint (surrogate pair) - String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); - }, - - // CSS string/identifier serialization - // https://drafts.csswg.org/cssom/#common-serializing-idioms - rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g, - fcssescape = function( ch, asCodePoint ) { - if ( asCodePoint ) { - - // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER - if ( ch === "\0" ) { - return "\uFFFD"; - } - - // Control characters and (dependent upon position) numbers get escaped as code points - return ch.slice( 0, -1 ) + "\\" + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " "; - } - - // Other potentially-special ASCII characters get backslash-escaped - return "\\" + ch; - }, - - // Used for iframes - // See setDocument() - // Removing the function wrapper causes a "Permission Denied" - // error in IE - unloadHandler = function() { - setDocument(); - }, - - disabledAncestor = addCombinator( - function( elem ) { - return elem.disabled === true && ("form" in elem || "label" in elem); - }, - { dir: "parentNode", next: "legend" } - ); - -// Optimize for push.apply( _, NodeList ) -try { - push.apply( - (arr = slice.call( preferredDoc.childNodes )), - preferredDoc.childNodes - ); - // Support: Android<4.0 - // Detect silently failing push.apply - arr[ preferredDoc.childNodes.length ].nodeType; -} catch ( e ) { - push = { apply: arr.length ? - - // Leverage slice if possible - function( target, els ) { - push_native.apply( target, slice.call(els) ); - } : - - // Support: IE<9 - // Otherwise append directly - function( target, els ) { - var j = target.length, - i = 0; - // Can't trust NodeList.length - while ( (target[j++] = els[i++]) ) {} - target.length = j - 1; - } - }; -} - -function Sizzle( selector, context, results, seed ) { - var m, i, elem, nid, match, groups, newSelector, - newContext = context && context.ownerDocument, - - // nodeType defaults to 9, since context defaults to document - nodeType = context ? context.nodeType : 9; - - results = results || []; - - // Return early from calls with invalid selector or context - if ( typeof selector !== "string" || !selector || - nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) { - - return results; - } - - // Try to shortcut find operations (as opposed to filters) in HTML documents - if ( !seed ) { - - if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) { - setDocument( context ); - } - context = context || document; - - if ( documentIsHTML ) { - - // If the selector is sufficiently simple, try using a "get*By*" DOM method - // (excepting DocumentFragment context, where the methods don't exist) - if ( nodeType !== 11 && (match = rquickExpr.exec( selector )) ) { - - // ID selector - if ( (m = match[1]) ) { - - // Document context - if ( nodeType === 9 ) { - if ( (elem = context.getElementById( m )) ) { - - // Support: IE, Opera, Webkit - // TODO: identify versions - // getElementById can match elements by name instead of ID - if ( elem.id === m ) { - results.push( elem ); - return results; - } - } else { - return results; - } - - // Element context - } else { - - // Support: IE, Opera, Webkit - // TODO: identify versions - // getElementById can match elements by name instead of ID - if ( newContext && (elem = newContext.getElementById( m )) && - contains( context, elem ) && - elem.id === m ) { - - results.push( elem ); - return results; - } - } - - // Type selector - } else if ( match[2] ) { - push.apply( results, context.getElementsByTagName( selector ) ); - return results; - - // Class selector - } else if ( (m = match[3]) && support.getElementsByClassName && - context.getElementsByClassName ) { - - push.apply( results, context.getElementsByClassName( m ) ); - return results; - } - } - - // Take advantage of querySelectorAll - if ( support.qsa && - !compilerCache[ selector + " " ] && - (!rbuggyQSA || !rbuggyQSA.test( selector )) ) { - - if ( nodeType !== 1 ) { - newContext = context; - newSelector = selector; - - // qSA looks outside Element context, which is not what we want - // Thanks to Andrew Dupont for this workaround technique - // Support: IE <=8 - // Exclude object elements - } else if ( context.nodeName.toLowerCase() !== "object" ) { - - // Capture the context ID, setting it first if necessary - if ( (nid = context.getAttribute( "id" )) ) { - nid = nid.replace( rcssescape, fcssescape ); - } else { - context.setAttribute( "id", (nid = expando) ); - } - - // Prefix every selector in the list - groups = tokenize( selector ); - i = groups.length; - while ( i-- ) { - groups[i] = "#" + nid + " " + toSelector( groups[i] ); - } - newSelector = groups.join( "," ); - - // Expand context for sibling selectors - newContext = rsibling.test( selector ) && testContext( context.parentNode ) || - context; - } - - if ( newSelector ) { - try { - push.apply( results, - newContext.querySelectorAll( newSelector ) - ); - return results; - } catch ( qsaError ) { - } finally { - if ( nid === expando ) { - context.removeAttribute( "id" ); - } - } - } - } - } - } - - // All others - return select( selector.replace( rtrim, "$1" ), context, results, seed ); -} - -/** - * Create key-value caches of limited size - * @returns {function(string, object)} Returns the Object data after storing it on itself with - * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) - * deleting the oldest entry - */ -function createCache() { - var keys = []; - - function cache( key, value ) { - // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) - if ( keys.push( key + " " ) > Expr.cacheLength ) { - // Only keep the most recent entries - delete cache[ keys.shift() ]; - } - return (cache[ key + " " ] = value); - } - return cache; -} - -/** - * Mark a function for special use by Sizzle - * @param {Function} fn The function to mark - */ -function markFunction( fn ) { - fn[ expando ] = true; - return fn; -} - -/** - * Support testing using an element - * @param {Function} fn Passed the created element and returns a boolean result - */ -function assert( fn ) { - var el = document.createElement("fieldset"); - - try { - return !!fn( el ); - } catch (e) { - return false; - } finally { - // Remove from its parent by default - if ( el.parentNode ) { - el.parentNode.removeChild( el ); - } - // release memory in IE - el = null; - } -} - -/** - * Adds the same handler for all of the specified attrs - * @param {String} attrs Pipe-separated list of attributes - * @param {Function} handler The method that will be applied - */ -function addHandle( attrs, handler ) { - var arr = attrs.split("|"), - i = arr.length; - - while ( i-- ) { - Expr.attrHandle[ arr[i] ] = handler; - } -} - -/** - * Checks document order of two siblings - * @param {Element} a - * @param {Element} b - * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b - */ -function siblingCheck( a, b ) { - var cur = b && a, - diff = cur && a.nodeType === 1 && b.nodeType === 1 && - a.sourceIndex - b.sourceIndex; - - // Use IE sourceIndex if available on both nodes - if ( diff ) { - return diff; - } - - // Check if b follows a - if ( cur ) { - while ( (cur = cur.nextSibling) ) { - if ( cur === b ) { - return -1; - } - } - } - - return a ? 1 : -1; -} - -/** - * Returns a function to use in pseudos for input types - * @param {String} type - */ -function createInputPseudo( type ) { - return function( elem ) { - var name = elem.nodeName.toLowerCase(); - return name === "input" && elem.type === type; - }; -} - -/** - * Returns a function to use in pseudos for buttons - * @param {String} type - */ -function createButtonPseudo( type ) { - return function( elem ) { - var name = elem.nodeName.toLowerCase(); - return (name === "input" || name === "button") && elem.type === type; - }; -} - -/** - * Returns a function to use in pseudos for :enabled/:disabled - * @param {Boolean} disabled true for :disabled; false for :enabled - */ -function createDisabledPseudo( disabled ) { - - // Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable - return function( elem ) { - - // Only certain elements can match :enabled or :disabled - // https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled - // https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled - if ( "form" in elem ) { - - // Check for inherited disabledness on relevant non-disabled elements: - // * listed form-associated elements in a disabled fieldset - // https://html.spec.whatwg.org/multipage/forms.html#category-listed - // https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled - // * option elements in a disabled optgroup - // https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled - // All such elements have a "form" property. - if ( elem.parentNode && elem.disabled === false ) { - - // Option elements defer to a parent optgroup if present - if ( "label" in elem ) { - if ( "label" in elem.parentNode ) { - return elem.parentNode.disabled === disabled; - } else { - return elem.disabled === disabled; - } - } - - // Support: IE 6 - 11 - // Use the isDisabled shortcut property to check for disabled fieldset ancestors - return elem.isDisabled === disabled || - - // Where there is no isDisabled, check manually - /* jshint -W018 */ - elem.isDisabled !== !disabled && - disabledAncestor( elem ) === disabled; - } - - return elem.disabled === disabled; - - // Try to winnow out elements that can't be disabled before trusting the disabled property. - // Some victims get caught in our net (label, legend, menu, track), but it shouldn't - // even exist on them, let alone have a boolean value. - } else if ( "label" in elem ) { - return elem.disabled === disabled; - } - - // Remaining elements are neither :enabled nor :disabled - return false; - }; -} - -/** - * Returns a function to use in pseudos for positionals - * @param {Function} fn - */ -function createPositionalPseudo( fn ) { - return markFunction(function( argument ) { - argument = +argument; - return markFunction(function( seed, matches ) { - var j, - matchIndexes = fn( [], seed.length, argument ), - i = matchIndexes.length; - - // Match elements found at the specified indexes - while ( i-- ) { - if ( seed[ (j = matchIndexes[i]) ] ) { - seed[j] = !(matches[j] = seed[j]); - } - } - }); - }); -} - -/** - * Checks a node for validity as a Sizzle context - * @param {Element|Object=} context - * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value - */ -function testContext( context ) { - return context && typeof context.getElementsByTagName !== "undefined" && context; -} - -// Expose support vars for convenience -support = Sizzle.support = {}; - -/** - * Detects XML nodes - * @param {Element|Object} elem An element or a document - * @returns {Boolean} True iff elem is a non-HTML XML node - */ -isXML = Sizzle.isXML = function( elem ) { - // documentElement is verified for cases where it doesn't yet exist - // (such as loading iframes in IE - #4833) - var documentElement = elem && (elem.ownerDocument || elem).documentElement; - return documentElement ? documentElement.nodeName !== "HTML" : false; -}; - -/** - * Sets document-related variables once based on the current document - * @param {Element|Object} [doc] An element or document object to use to set the document - * @returns {Object} Returns the current document - */ -setDocument = Sizzle.setDocument = function( node ) { - var hasCompare, subWindow, - doc = node ? node.ownerDocument || node : preferredDoc; - - // Return early if doc is invalid or already selected - if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) { - return document; - } - - // Update global variables - document = doc; - docElem = document.documentElement; - documentIsHTML = !isXML( document ); - - // Support: IE 9-11, Edge - // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936) - if ( preferredDoc !== document && - (subWindow = document.defaultView) && subWindow.top !== subWindow ) { - - // Support: IE 11, Edge - if ( subWindow.addEventListener ) { - subWindow.addEventListener( "unload", unloadHandler, false ); - - // Support: IE 9 - 10 only - } else if ( subWindow.attachEvent ) { - subWindow.attachEvent( "onunload", unloadHandler ); - } - } - - /* Attributes - ---------------------------------------------------------------------- */ - - // Support: IE<8 - // Verify that getAttribute really returns attributes and not properties - // (excepting IE8 booleans) - support.attributes = assert(function( el ) { - el.className = "i"; - return !el.getAttribute("className"); - }); - - /* getElement(s)By* - ---------------------------------------------------------------------- */ - - // Check if getElementsByTagName("*") returns only elements - support.getElementsByTagName = assert(function( el ) { - el.appendChild( document.createComment("") ); - return !el.getElementsByTagName("*").length; - }); - - // Support: IE<9 - support.getElementsByClassName = rnative.test( document.getElementsByClassName ); - - // Support: IE<10 - // Check if getElementById returns elements by name - // The broken getElementById methods don't pick up programmatically-set names, - // so use a roundabout getElementsByName test - support.getById = assert(function( el ) { - docElem.appendChild( el ).id = expando; - return !document.getElementsByName || !document.getElementsByName( expando ).length; - }); - - // ID filter and find - if ( support.getById ) { - Expr.filter["ID"] = function( id ) { - var attrId = id.replace( runescape, funescape ); - return function( elem ) { - return elem.getAttribute("id") === attrId; - }; - }; - Expr.find["ID"] = function( id, context ) { - if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { - var elem = context.getElementById( id ); - return elem ? [ elem ] : []; - } - }; - } else { - Expr.filter["ID"] = function( id ) { - var attrId = id.replace( runescape, funescape ); - return function( elem ) { - var node = typeof elem.getAttributeNode !== "undefined" && - elem.getAttributeNode("id"); - return node && node.value === attrId; - }; - }; - - // Support: IE 6 - 7 only - // getElementById is not reliable as a find shortcut - Expr.find["ID"] = function( id, context ) { - if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { - var node, i, elems, - elem = context.getElementById( id ); - - if ( elem ) { - - // Verify the id attribute - node = elem.getAttributeNode("id"); - if ( node && node.value === id ) { - return [ elem ]; - } - - // Fall back on getElementsByName - elems = context.getElementsByName( id ); - i = 0; - while ( (elem = elems[i++]) ) { - node = elem.getAttributeNode("id"); - if ( node && node.value === id ) { - return [ elem ]; - } - } - } - - return []; - } - }; - } - - // Tag - Expr.find["TAG"] = support.getElementsByTagName ? - function( tag, context ) { - if ( typeof context.getElementsByTagName !== "undefined" ) { - return context.getElementsByTagName( tag ); - - // DocumentFragment nodes don't have gEBTN - } else if ( support.qsa ) { - return context.querySelectorAll( tag ); - } - } : - - function( tag, context ) { - var elem, - tmp = [], - i = 0, - // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too - results = context.getElementsByTagName( tag ); - - // Filter out possible comments - if ( tag === "*" ) { - while ( (elem = results[i++]) ) { - if ( elem.nodeType === 1 ) { - tmp.push( elem ); - } - } - - return tmp; - } - return results; - }; - - // Class - Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) { - if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) { - return context.getElementsByClassName( className ); - } - }; - - /* QSA/matchesSelector - ---------------------------------------------------------------------- */ - - // QSA and matchesSelector support - - // matchesSelector(:active) reports false when true (IE9/Opera 11.5) - rbuggyMatches = []; - - // qSa(:focus) reports false when true (Chrome 21) - // We allow this because of a bug in IE8/9 that throws an error - // whenever `document.activeElement` is accessed on an iframe - // So, we allow :focus to pass through QSA all the time to avoid the IE error - // See https://bugs.jquery.com/ticket/13378 - rbuggyQSA = []; - - if ( (support.qsa = rnative.test( document.querySelectorAll )) ) { - // Build QSA regex - // Regex strategy adopted from Diego Perini - assert(function( el ) { - // Select is set to empty string on purpose - // This is to test IE's treatment of not explicitly - // setting a boolean content attribute, - // since its presence should be enough - // https://bugs.jquery.com/ticket/12359 - docElem.appendChild( el ).innerHTML = "" + - ""; - - // Support: IE8, Opera 11-12.16 - // Nothing should be selected when empty strings follow ^= or $= or *= - // The test attribute must be unknown in Opera but "safe" for WinRT - // https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section - if ( el.querySelectorAll("[msallowcapture^='']").length ) { - rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); - } - - // Support: IE8 - // Boolean attributes and "value" are not treated correctly - if ( !el.querySelectorAll("[selected]").length ) { - rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); - } - - // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+ - if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) { - rbuggyQSA.push("~="); - } - - // Webkit/Opera - :checked should return selected option elements - // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked - // IE8 throws error here and will not see later tests - if ( !el.querySelectorAll(":checked").length ) { - rbuggyQSA.push(":checked"); - } - - // Support: Safari 8+, iOS 8+ - // https://bugs.webkit.org/show_bug.cgi?id=136851 - // In-page `selector#id sibling-combinator selector` fails - if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) { - rbuggyQSA.push(".#.+[+~]"); - } - }); - - assert(function( el ) { - el.innerHTML = "" + - ""; - - // Support: Windows 8 Native Apps - // The type and name attributes are restricted during .innerHTML assignment - var input = document.createElement("input"); - input.setAttribute( "type", "hidden" ); - el.appendChild( input ).setAttribute( "name", "D" ); - - // Support: IE8 - // Enforce case-sensitivity of name attribute - if ( el.querySelectorAll("[name=d]").length ) { - rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" ); - } - - // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) - // IE8 throws error here and will not see later tests - if ( el.querySelectorAll(":enabled").length !== 2 ) { - rbuggyQSA.push( ":enabled", ":disabled" ); - } - - // Support: IE9-11+ - // IE's :disabled selector does not pick up the children of disabled fieldsets - docElem.appendChild( el ).disabled = true; - if ( el.querySelectorAll(":disabled").length !== 2 ) { - rbuggyQSA.push( ":enabled", ":disabled" ); - } - - // Opera 10-11 does not throw on post-comma invalid pseudos - el.querySelectorAll("*,:x"); - rbuggyQSA.push(",.*:"); - }); - } - - if ( (support.matchesSelector = rnative.test( (matches = docElem.matches || - docElem.webkitMatchesSelector || - docElem.mozMatchesSelector || - docElem.oMatchesSelector || - docElem.msMatchesSelector) )) ) { - - assert(function( el ) { - // Check to see if it's possible to do matchesSelector - // on a disconnected node (IE 9) - support.disconnectedMatch = matches.call( el, "*" ); - - // This should fail with an exception - // Gecko does not error, returns false instead - matches.call( el, "[s!='']:x" ); - rbuggyMatches.push( "!=", pseudos ); - }); - } - - rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") ); - rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") ); - - /* Contains - ---------------------------------------------------------------------- */ - hasCompare = rnative.test( docElem.compareDocumentPosition ); - - // Element contains another - // Purposefully self-exclusive - // As in, an element does not contain itself - contains = hasCompare || rnative.test( docElem.contains ) ? - function( a, b ) { - var adown = a.nodeType === 9 ? a.documentElement : a, - bup = b && b.parentNode; - return a === bup || !!( bup && bup.nodeType === 1 && ( - adown.contains ? - adown.contains( bup ) : - a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 - )); - } : - function( a, b ) { - if ( b ) { - while ( (b = b.parentNode) ) { - if ( b === a ) { - return true; - } - } - } - return false; - }; - - /* Sorting - ---------------------------------------------------------------------- */ - - // Document order sorting - sortOrder = hasCompare ? - function( a, b ) { - - // Flag for duplicate removal - if ( a === b ) { - hasDuplicate = true; - return 0; - } - - // Sort on method existence if only one input has compareDocumentPosition - var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; - if ( compare ) { - return compare; - } - - // Calculate position if both inputs belong to the same document - compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ? - a.compareDocumentPosition( b ) : - - // Otherwise we know they are disconnected - 1; - - // Disconnected nodes - if ( compare & 1 || - (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) { - - // Choose the first element that is related to our preferred document - if ( a === document || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) { - return -1; - } - if ( b === document || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) { - return 1; - } - - // Maintain original order - return sortInput ? - ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : - 0; - } - - return compare & 4 ? -1 : 1; - } : - function( a, b ) { - // Exit early if the nodes are identical - if ( a === b ) { - hasDuplicate = true; - return 0; - } - - var cur, - i = 0, - aup = a.parentNode, - bup = b.parentNode, - ap = [ a ], - bp = [ b ]; - - // Parentless nodes are either documents or disconnected - if ( !aup || !bup ) { - return a === document ? -1 : - b === document ? 1 : - aup ? -1 : - bup ? 1 : - sortInput ? - ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : - 0; - - // If the nodes are siblings, we can do a quick check - } else if ( aup === bup ) { - return siblingCheck( a, b ); - } - - // Otherwise we need full lists of their ancestors for comparison - cur = a; - while ( (cur = cur.parentNode) ) { - ap.unshift( cur ); - } - cur = b; - while ( (cur = cur.parentNode) ) { - bp.unshift( cur ); - } - - // Walk down the tree looking for a discrepancy - while ( ap[i] === bp[i] ) { - i++; - } - - return i ? - // Do a sibling check if the nodes have a common ancestor - siblingCheck( ap[i], bp[i] ) : - - // Otherwise nodes in our document sort first - ap[i] === preferredDoc ? -1 : - bp[i] === preferredDoc ? 1 : - 0; - }; - - return document; -}; - -Sizzle.matches = function( expr, elements ) { - return Sizzle( expr, null, null, elements ); -}; - -Sizzle.matchesSelector = function( elem, expr ) { - // Set document vars if needed - if ( ( elem.ownerDocument || elem ) !== document ) { - setDocument( elem ); - } - - // Make sure that attribute selectors are quoted - expr = expr.replace( rattributeQuotes, "='$1']" ); - - if ( support.matchesSelector && documentIsHTML && - !compilerCache[ expr + " " ] && - ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && - ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { - - try { - var ret = matches.call( elem, expr ); - - // IE 9's matchesSelector returns false on disconnected nodes - if ( ret || support.disconnectedMatch || - // As well, disconnected nodes are said to be in a document - // fragment in IE 9 - elem.document && elem.document.nodeType !== 11 ) { - return ret; - } - } catch (e) {} - } - - return Sizzle( expr, document, null, [ elem ] ).length > 0; -}; - -Sizzle.contains = function( context, elem ) { - // Set document vars if needed - if ( ( context.ownerDocument || context ) !== document ) { - setDocument( context ); - } - return contains( context, elem ); -}; - -Sizzle.attr = function( elem, name ) { - // Set document vars if needed - if ( ( elem.ownerDocument || elem ) !== document ) { - setDocument( elem ); - } - - var fn = Expr.attrHandle[ name.toLowerCase() ], - // Don't get fooled by Object.prototype properties (jQuery #13807) - val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? - fn( elem, name, !documentIsHTML ) : - undefined; - - return val !== undefined ? - val : - support.attributes || !documentIsHTML ? - elem.getAttribute( name ) : - (val = elem.getAttributeNode(name)) && val.specified ? - val.value : - null; -}; - -Sizzle.escape = function( sel ) { - return (sel + "").replace( rcssescape, fcssescape ); -}; - -Sizzle.error = function( msg ) { - throw new Error( "Syntax error, unrecognized expression: " + msg ); -}; - -/** - * Document sorting and removing duplicates - * @param {ArrayLike} results - */ -Sizzle.uniqueSort = function( results ) { - var elem, - duplicates = [], - j = 0, - i = 0; - - // Unless we *know* we can detect duplicates, assume their presence - hasDuplicate = !support.detectDuplicates; - sortInput = !support.sortStable && results.slice( 0 ); - results.sort( sortOrder ); - - if ( hasDuplicate ) { - while ( (elem = results[i++]) ) { - if ( elem === results[ i ] ) { - j = duplicates.push( i ); - } - } - while ( j-- ) { - results.splice( duplicates[ j ], 1 ); - } - } - - // Clear input after sorting to release objects - // See https://github.com/jquery/sizzle/pull/225 - sortInput = null; - - return results; -}; - -/** - * Utility function for retrieving the text value of an array of DOM nodes - * @param {Array|Element} elem - */ -getText = Sizzle.getText = function( elem ) { - var node, - ret = "", - i = 0, - nodeType = elem.nodeType; - - if ( !nodeType ) { - // If no nodeType, this is expected to be an array - while ( (node = elem[i++]) ) { - // Do not traverse comment nodes - ret += getText( node ); - } - } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { - // Use textContent for elements - // innerText usage removed for consistency of new lines (jQuery #11153) - if ( typeof elem.textContent === "string" ) { - return elem.textContent; - } else { - // Traverse its children - for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { - ret += getText( elem ); - } - } - } else if ( nodeType === 3 || nodeType === 4 ) { - return elem.nodeValue; - } - // Do not include comment or processing instruction nodes - - return ret; -}; - -Expr = Sizzle.selectors = { - - // Can be adjusted by the user - cacheLength: 50, - - createPseudo: markFunction, - - match: matchExpr, - - attrHandle: {}, - - find: {}, - - relative: { - ">": { dir: "parentNode", first: true }, - " ": { dir: "parentNode" }, - "+": { dir: "previousSibling", first: true }, - "~": { dir: "previousSibling" } - }, - - preFilter: { - "ATTR": function( match ) { - match[1] = match[1].replace( runescape, funescape ); - - // Move the given value to match[3] whether quoted or unquoted - match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape ); - - if ( match[2] === "~=" ) { - match[3] = " " + match[3] + " "; - } - - return match.slice( 0, 4 ); - }, - - "CHILD": function( match ) { - /* matches from matchExpr["CHILD"] - 1 type (only|nth|...) - 2 what (child|of-type) - 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) - 4 xn-component of xn+y argument ([+-]?\d*n|) - 5 sign of xn-component - 6 x of xn-component - 7 sign of y-component - 8 y of y-component - */ - match[1] = match[1].toLowerCase(); - - if ( match[1].slice( 0, 3 ) === "nth" ) { - // nth-* requires argument - if ( !match[3] ) { - Sizzle.error( match[0] ); - } - - // numeric x and y parameters for Expr.filter.CHILD - // remember that false/true cast respectively to 0/1 - match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) ); - match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" ); - - // other types prohibit arguments - } else if ( match[3] ) { - Sizzle.error( match[0] ); - } - - return match; - }, - - "PSEUDO": function( match ) { - var excess, - unquoted = !match[6] && match[2]; - - if ( matchExpr["CHILD"].test( match[0] ) ) { - return null; - } - - // Accept quoted arguments as-is - if ( match[3] ) { - match[2] = match[4] || match[5] || ""; - - // Strip excess characters from unquoted arguments - } else if ( unquoted && rpseudo.test( unquoted ) && - // Get excess from tokenize (recursively) - (excess = tokenize( unquoted, true )) && - // advance to the next closing parenthesis - (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) { - - // excess is a negative index - match[0] = match[0].slice( 0, excess ); - match[2] = unquoted.slice( 0, excess ); - } - - // Return only captures needed by the pseudo filter method (type and argument) - return match.slice( 0, 3 ); - } - }, - - filter: { - - "TAG": function( nodeNameSelector ) { - var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); - return nodeNameSelector === "*" ? - function() { return true; } : - function( elem ) { - return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; - }; - }, - - "CLASS": function( className ) { - var pattern = classCache[ className + " " ]; - - return pattern || - (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) && - classCache( className, function( elem ) { - return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== "undefined" && elem.getAttribute("class") || "" ); - }); - }, - - "ATTR": function( name, operator, check ) { - return function( elem ) { - var result = Sizzle.attr( elem, name ); - - if ( result == null ) { - return operator === "!="; - } - if ( !operator ) { - return true; - } - - result += ""; - - return operator === "=" ? result === check : - operator === "!=" ? result !== check : - operator === "^=" ? check && result.indexOf( check ) === 0 : - operator === "*=" ? check && result.indexOf( check ) > -1 : - operator === "$=" ? check && result.slice( -check.length ) === check : - operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 : - operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : - false; - }; - }, - - "CHILD": function( type, what, argument, first, last ) { - var simple = type.slice( 0, 3 ) !== "nth", - forward = type.slice( -4 ) !== "last", - ofType = what === "of-type"; - - return first === 1 && last === 0 ? - - // Shortcut for :nth-*(n) - function( elem ) { - return !!elem.parentNode; - } : - - function( elem, context, xml ) { - var cache, uniqueCache, outerCache, node, nodeIndex, start, - dir = simple !== forward ? "nextSibling" : "previousSibling", - parent = elem.parentNode, - name = ofType && elem.nodeName.toLowerCase(), - useCache = !xml && !ofType, - diff = false; - - if ( parent ) { - - // :(first|last|only)-(child|of-type) - if ( simple ) { - while ( dir ) { - node = elem; - while ( (node = node[ dir ]) ) { - if ( ofType ? - node.nodeName.toLowerCase() === name : - node.nodeType === 1 ) { - - return false; - } - } - // Reverse direction for :only-* (if we haven't yet done so) - start = dir = type === "only" && !start && "nextSibling"; - } - return true; - } - - start = [ forward ? parent.firstChild : parent.lastChild ]; - - // non-xml :nth-child(...) stores cache data on `parent` - if ( forward && useCache ) { - - // Seek `elem` from a previously-cached index - - // ...in a gzip-friendly way - node = parent; - outerCache = node[ expando ] || (node[ expando ] = {}); - - // Support: IE <9 only - // Defend against cloned attroperties (jQuery gh-1709) - uniqueCache = outerCache[ node.uniqueID ] || - (outerCache[ node.uniqueID ] = {}); - - cache = uniqueCache[ type ] || []; - nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; - diff = nodeIndex && cache[ 2 ]; - node = nodeIndex && parent.childNodes[ nodeIndex ]; - - while ( (node = ++nodeIndex && node && node[ dir ] || - - // Fallback to seeking `elem` from the start - (diff = nodeIndex = 0) || start.pop()) ) { - - // When found, cache indexes on `parent` and break - if ( node.nodeType === 1 && ++diff && node === elem ) { - uniqueCache[ type ] = [ dirruns, nodeIndex, diff ]; - break; - } - } - - } else { - // Use previously-cached element index if available - if ( useCache ) { - // ...in a gzip-friendly way - node = elem; - outerCache = node[ expando ] || (node[ expando ] = {}); - - // Support: IE <9 only - // Defend against cloned attroperties (jQuery gh-1709) - uniqueCache = outerCache[ node.uniqueID ] || - (outerCache[ node.uniqueID ] = {}); - - cache = uniqueCache[ type ] || []; - nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; - diff = nodeIndex; - } - - // xml :nth-child(...) - // or :nth-last-child(...) or :nth(-last)?-of-type(...) - if ( diff === false ) { - // Use the same loop as above to seek `elem` from the start - while ( (node = ++nodeIndex && node && node[ dir ] || - (diff = nodeIndex = 0) || start.pop()) ) { - - if ( ( ofType ? - node.nodeName.toLowerCase() === name : - node.nodeType === 1 ) && - ++diff ) { - - // Cache the index of each encountered element - if ( useCache ) { - outerCache = node[ expando ] || (node[ expando ] = {}); - - // Support: IE <9 only - // Defend against cloned attroperties (jQuery gh-1709) - uniqueCache = outerCache[ node.uniqueID ] || - (outerCache[ node.uniqueID ] = {}); - - uniqueCache[ type ] = [ dirruns, diff ]; - } - - if ( node === elem ) { - break; - } - } - } - } - } - - // Incorporate the offset, then check against cycle size - diff -= last; - return diff === first || ( diff % first === 0 && diff / first >= 0 ); - } - }; - }, - - "PSEUDO": function( pseudo, argument ) { - // pseudo-class names are case-insensitive - // http://www.w3.org/TR/selectors/#pseudo-classes - // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters - // Remember that setFilters inherits from pseudos - var args, - fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || - Sizzle.error( "unsupported pseudo: " + pseudo ); - - // The user may use createPseudo to indicate that - // arguments are needed to create the filter function - // just as Sizzle does - if ( fn[ expando ] ) { - return fn( argument ); - } - - // But maintain support for old signatures - if ( fn.length > 1 ) { - args = [ pseudo, pseudo, "", argument ]; - return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? - markFunction(function( seed, matches ) { - var idx, - matched = fn( seed, argument ), - i = matched.length; - while ( i-- ) { - idx = indexOf( seed, matched[i] ); - seed[ idx ] = !( matches[ idx ] = matched[i] ); - } - }) : - function( elem ) { - return fn( elem, 0, args ); - }; - } - - return fn; - } - }, - - pseudos: { - // Potentially complex pseudos - "not": markFunction(function( selector ) { - // Trim the selector passed to compile - // to avoid treating leading and trailing - // spaces as combinators - var input = [], - results = [], - matcher = compile( selector.replace( rtrim, "$1" ) ); - - return matcher[ expando ] ? - markFunction(function( seed, matches, context, xml ) { - var elem, - unmatched = matcher( seed, null, xml, [] ), - i = seed.length; - - // Match elements unmatched by `matcher` - while ( i-- ) { - if ( (elem = unmatched[i]) ) { - seed[i] = !(matches[i] = elem); - } - } - }) : - function( elem, context, xml ) { - input[0] = elem; - matcher( input, null, xml, results ); - // Don't keep the element (issue #299) - input[0] = null; - return !results.pop(); - }; - }), - - "has": markFunction(function( selector ) { - return function( elem ) { - return Sizzle( selector, elem ).length > 0; - }; - }), - - "contains": markFunction(function( text ) { - text = text.replace( runescape, funescape ); - return function( elem ) { - return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1; - }; - }), - - // "Whether an element is represented by a :lang() selector - // is based solely on the element's language value - // being equal to the identifier C, - // or beginning with the identifier C immediately followed by "-". - // The matching of C against the element's language value is performed case-insensitively. - // The identifier C does not have to be a valid language name." - // http://www.w3.org/TR/selectors/#lang-pseudo - "lang": markFunction( function( lang ) { - // lang value must be a valid identifier - if ( !ridentifier.test(lang || "") ) { - Sizzle.error( "unsupported lang: " + lang ); - } - lang = lang.replace( runescape, funescape ).toLowerCase(); - return function( elem ) { - var elemLang; - do { - if ( (elemLang = documentIsHTML ? - elem.lang : - elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) { - - elemLang = elemLang.toLowerCase(); - return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; - } - } while ( (elem = elem.parentNode) && elem.nodeType === 1 ); - return false; - }; - }), - - // Miscellaneous - "target": function( elem ) { - var hash = window.location && window.location.hash; - return hash && hash.slice( 1 ) === elem.id; - }, - - "root": function( elem ) { - return elem === docElem; - }, - - "focus": function( elem ) { - return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex); - }, - - // Boolean properties - "enabled": createDisabledPseudo( false ), - "disabled": createDisabledPseudo( true ), - - "checked": function( elem ) { - // In CSS3, :checked should return both checked and selected elements - // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked - var nodeName = elem.nodeName.toLowerCase(); - return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected); - }, - - "selected": function( elem ) { - // Accessing this property makes selected-by-default - // options in Safari work properly - if ( elem.parentNode ) { - elem.parentNode.selectedIndex; - } - - return elem.selected === true; - }, - - // Contents - "empty": function( elem ) { - // http://www.w3.org/TR/selectors/#empty-pseudo - // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), - // but not by others (comment: 8; processing instruction: 7; etc.) - // nodeType < 6 works because attributes (2) do not appear as children - for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { - if ( elem.nodeType < 6 ) { - return false; - } - } - return true; - }, - - "parent": function( elem ) { - return !Expr.pseudos["empty"]( elem ); - }, - - // Element/input types - "header": function( elem ) { - return rheader.test( elem.nodeName ); - }, - - "input": function( elem ) { - return rinputs.test( elem.nodeName ); - }, - - "button": function( elem ) { - var name = elem.nodeName.toLowerCase(); - return name === "input" && elem.type === "button" || name === "button"; - }, - - "text": function( elem ) { - var attr; - return elem.nodeName.toLowerCase() === "input" && - elem.type === "text" && - - // Support: IE<8 - // New HTML5 attribute values (e.g., "search") appear with elem.type === "text" - ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" ); - }, - - // Position-in-collection - "first": createPositionalPseudo(function() { - return [ 0 ]; - }), - - "last": createPositionalPseudo(function( matchIndexes, length ) { - return [ length - 1 ]; - }), - - "eq": createPositionalPseudo(function( matchIndexes, length, argument ) { - return [ argument < 0 ? argument + length : argument ]; - }), - - "even": createPositionalPseudo(function( matchIndexes, length ) { - var i = 0; - for ( ; i < length; i += 2 ) { - matchIndexes.push( i ); - } - return matchIndexes; - }), - - "odd": createPositionalPseudo(function( matchIndexes, length ) { - var i = 1; - for ( ; i < length; i += 2 ) { - matchIndexes.push( i ); - } - return matchIndexes; - }), - - "lt": createPositionalPseudo(function( matchIndexes, length, argument ) { - var i = argument < 0 ? argument + length : argument; - for ( ; --i >= 0; ) { - matchIndexes.push( i ); - } - return matchIndexes; - }), - - "gt": createPositionalPseudo(function( matchIndexes, length, argument ) { - var i = argument < 0 ? argument + length : argument; - for ( ; ++i < length; ) { - matchIndexes.push( i ); - } - return matchIndexes; - }) - } -}; - -Expr.pseudos["nth"] = Expr.pseudos["eq"]; - -// Add button/input type pseudos -for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { - Expr.pseudos[ i ] = createInputPseudo( i ); -} -for ( i in { submit: true, reset: true } ) { - Expr.pseudos[ i ] = createButtonPseudo( i ); -} - -// Easy API for creating new setFilters -function setFilters() {} -setFilters.prototype = Expr.filters = Expr.pseudos; -Expr.setFilters = new setFilters(); - -tokenize = Sizzle.tokenize = function( selector, parseOnly ) { - var matched, match, tokens, type, - soFar, groups, preFilters, - cached = tokenCache[ selector + " " ]; - - if ( cached ) { - return parseOnly ? 0 : cached.slice( 0 ); - } - - soFar = selector; - groups = []; - preFilters = Expr.preFilter; - - while ( soFar ) { - - // Comma and first run - if ( !matched || (match = rcomma.exec( soFar )) ) { - if ( match ) { - // Don't consume trailing commas as valid - soFar = soFar.slice( match[0].length ) || soFar; - } - groups.push( (tokens = []) ); - } - - matched = false; - - // Combinators - if ( (match = rcombinators.exec( soFar )) ) { - matched = match.shift(); - tokens.push({ - value: matched, - // Cast descendant combinators to space - type: match[0].replace( rtrim, " " ) - }); - soFar = soFar.slice( matched.length ); - } - - // Filters - for ( type in Expr.filter ) { - if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] || - (match = preFilters[ type ]( match ))) ) { - matched = match.shift(); - tokens.push({ - value: matched, - type: type, - matches: match - }); - soFar = soFar.slice( matched.length ); - } - } - - if ( !matched ) { - break; - } - } - - // Return the length of the invalid excess - // if we're just parsing - // Otherwise, throw an error or return tokens - return parseOnly ? - soFar.length : - soFar ? - Sizzle.error( selector ) : - // Cache the tokens - tokenCache( selector, groups ).slice( 0 ); -}; - -function toSelector( tokens ) { - var i = 0, - len = tokens.length, - selector = ""; - for ( ; i < len; i++ ) { - selector += tokens[i].value; - } - return selector; -} - -function addCombinator( matcher, combinator, base ) { - var dir = combinator.dir, - skip = combinator.next, - key = skip || dir, - checkNonElements = base && key === "parentNode", - doneName = done++; - - return combinator.first ? - // Check against closest ancestor/preceding element - function( elem, context, xml ) { - while ( (elem = elem[ dir ]) ) { - if ( elem.nodeType === 1 || checkNonElements ) { - return matcher( elem, context, xml ); - } - } - return false; - } : - - // Check against all ancestor/preceding elements - function( elem, context, xml ) { - var oldCache, uniqueCache, outerCache, - newCache = [ dirruns, doneName ]; - - // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching - if ( xml ) { - while ( (elem = elem[ dir ]) ) { - if ( elem.nodeType === 1 || checkNonElements ) { - if ( matcher( elem, context, xml ) ) { - return true; - } - } - } - } else { - while ( (elem = elem[ dir ]) ) { - if ( elem.nodeType === 1 || checkNonElements ) { - outerCache = elem[ expando ] || (elem[ expando ] = {}); - - // Support: IE <9 only - // Defend against cloned attroperties (jQuery gh-1709) - uniqueCache = outerCache[ elem.uniqueID ] || (outerCache[ elem.uniqueID ] = {}); - - if ( skip && skip === elem.nodeName.toLowerCase() ) { - elem = elem[ dir ] || elem; - } else if ( (oldCache = uniqueCache[ key ]) && - oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) { - - // Assign to newCache so results back-propagate to previous elements - return (newCache[ 2 ] = oldCache[ 2 ]); - } else { - // Reuse newcache so results back-propagate to previous elements - uniqueCache[ key ] = newCache; - - // A match means we're done; a fail means we have to keep checking - if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) { - return true; - } - } - } - } - } - return false; - }; -} - -function elementMatcher( matchers ) { - return matchers.length > 1 ? - function( elem, context, xml ) { - var i = matchers.length; - while ( i-- ) { - if ( !matchers[i]( elem, context, xml ) ) { - return false; - } - } - return true; - } : - matchers[0]; -} - -function multipleContexts( selector, contexts, results ) { - var i = 0, - len = contexts.length; - for ( ; i < len; i++ ) { - Sizzle( selector, contexts[i], results ); - } - return results; -} - -function condense( unmatched, map, filter, context, xml ) { - var elem, - newUnmatched = [], - i = 0, - len = unmatched.length, - mapped = map != null; - - for ( ; i < len; i++ ) { - if ( (elem = unmatched[i]) ) { - if ( !filter || filter( elem, context, xml ) ) { - newUnmatched.push( elem ); - if ( mapped ) { - map.push( i ); - } - } - } - } - - return newUnmatched; -} - -function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { - if ( postFilter && !postFilter[ expando ] ) { - postFilter = setMatcher( postFilter ); - } - if ( postFinder && !postFinder[ expando ] ) { - postFinder = setMatcher( postFinder, postSelector ); - } - return markFunction(function( seed, results, context, xml ) { - var temp, i, elem, - preMap = [], - postMap = [], - preexisting = results.length, - - // Get initial elements from seed or context - elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ), - - // Prefilter to get matcher input, preserving a map for seed-results synchronization - matcherIn = preFilter && ( seed || !selector ) ? - condense( elems, preMap, preFilter, context, xml ) : - elems, - - matcherOut = matcher ? - // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, - postFinder || ( seed ? preFilter : preexisting || postFilter ) ? - - // ...intermediate processing is necessary - [] : - - // ...otherwise use results directly - results : - matcherIn; - - // Find primary matches - if ( matcher ) { - matcher( matcherIn, matcherOut, context, xml ); - } - - // Apply postFilter - if ( postFilter ) { - temp = condense( matcherOut, postMap ); - postFilter( temp, [], context, xml ); - - // Un-match failing elements by moving them back to matcherIn - i = temp.length; - while ( i-- ) { - if ( (elem = temp[i]) ) { - matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem); - } - } - } - - if ( seed ) { - if ( postFinder || preFilter ) { - if ( postFinder ) { - // Get the final matcherOut by condensing this intermediate into postFinder contexts - temp = []; - i = matcherOut.length; - while ( i-- ) { - if ( (elem = matcherOut[i]) ) { - // Restore matcherIn since elem is not yet a final match - temp.push( (matcherIn[i] = elem) ); - } - } - postFinder( null, (matcherOut = []), temp, xml ); - } - - // Move matched elements from seed to results to keep them synchronized - i = matcherOut.length; - while ( i-- ) { - if ( (elem = matcherOut[i]) && - (temp = postFinder ? indexOf( seed, elem ) : preMap[i]) > -1 ) { - - seed[temp] = !(results[temp] = elem); - } - } - } - - // Add elements to results, through postFinder if defined - } else { - matcherOut = condense( - matcherOut === results ? - matcherOut.splice( preexisting, matcherOut.length ) : - matcherOut - ); - if ( postFinder ) { - postFinder( null, results, matcherOut, xml ); - } else { - push.apply( results, matcherOut ); - } - } - }); -} - -function matcherFromTokens( tokens ) { - var checkContext, matcher, j, - len = tokens.length, - leadingRelative = Expr.relative[ tokens[0].type ], - implicitRelative = leadingRelative || Expr.relative[" "], - i = leadingRelative ? 1 : 0, - - // The foundational matcher ensures that elements are reachable from top-level context(s) - matchContext = addCombinator( function( elem ) { - return elem === checkContext; - }, implicitRelative, true ), - matchAnyContext = addCombinator( function( elem ) { - return indexOf( checkContext, elem ) > -1; - }, implicitRelative, true ), - matchers = [ function( elem, context, xml ) { - var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( - (checkContext = context).nodeType ? - matchContext( elem, context, xml ) : - matchAnyContext( elem, context, xml ) ); - // Avoid hanging onto element (issue #299) - checkContext = null; - return ret; - } ]; - - for ( ; i < len; i++ ) { - if ( (matcher = Expr.relative[ tokens[i].type ]) ) { - matchers = [ addCombinator(elementMatcher( matchers ), matcher) ]; - } else { - matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches ); - - // Return special upon seeing a positional matcher - if ( matcher[ expando ] ) { - // Find the next relative operator (if any) for proper handling - j = ++i; - for ( ; j < len; j++ ) { - if ( Expr.relative[ tokens[j].type ] ) { - break; - } - } - return setMatcher( - i > 1 && elementMatcher( matchers ), - i > 1 && toSelector( - // If the preceding token was a descendant combinator, insert an implicit any-element `*` - tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" }) - ).replace( rtrim, "$1" ), - matcher, - i < j && matcherFromTokens( tokens.slice( i, j ) ), - j < len && matcherFromTokens( (tokens = tokens.slice( j )) ), - j < len && toSelector( tokens ) - ); - } - matchers.push( matcher ); - } - } - - return elementMatcher( matchers ); -} - -function matcherFromGroupMatchers( elementMatchers, setMatchers ) { - var bySet = setMatchers.length > 0, - byElement = elementMatchers.length > 0, - superMatcher = function( seed, context, xml, results, outermost ) { - var elem, j, matcher, - matchedCount = 0, - i = "0", - unmatched = seed && [], - setMatched = [], - contextBackup = outermostContext, - // We must always have either seed elements or outermost context - elems = seed || byElement && Expr.find["TAG"]( "*", outermost ), - // Use integer dirruns iff this is the outermost matcher - dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1), - len = elems.length; - - if ( outermost ) { - outermostContext = context === document || context || outermost; - } - - // Add elements passing elementMatchers directly to results - // Support: IE<9, Safari - // Tolerate NodeList properties (IE: "length"; Safari: ) matching elements by id - for ( ; i !== len && (elem = elems[i]) != null; i++ ) { - if ( byElement && elem ) { - j = 0; - if ( !context && elem.ownerDocument !== document ) { - setDocument( elem ); - xml = !documentIsHTML; - } - while ( (matcher = elementMatchers[j++]) ) { - if ( matcher( elem, context || document, xml) ) { - results.push( elem ); - break; - } - } - if ( outermost ) { - dirruns = dirrunsUnique; - } - } - - // Track unmatched elements for set filters - if ( bySet ) { - // They will have gone through all possible matchers - if ( (elem = !matcher && elem) ) { - matchedCount--; - } - - // Lengthen the array for every element, matched or not - if ( seed ) { - unmatched.push( elem ); - } - } - } - - // `i` is now the count of elements visited above, and adding it to `matchedCount` - // makes the latter nonnegative. - matchedCount += i; - - // Apply set filters to unmatched elements - // NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount` - // equals `i`), unless we didn't visit _any_ elements in the above loop because we have - // no element matchers and no seed. - // Incrementing an initially-string "0" `i` allows `i` to remain a string only in that - // case, which will result in a "00" `matchedCount` that differs from `i` but is also - // numerically zero. - if ( bySet && i !== matchedCount ) { - j = 0; - while ( (matcher = setMatchers[j++]) ) { - matcher( unmatched, setMatched, context, xml ); - } - - if ( seed ) { - // Reintegrate element matches to eliminate the need for sorting - if ( matchedCount > 0 ) { - while ( i-- ) { - if ( !(unmatched[i] || setMatched[i]) ) { - setMatched[i] = pop.call( results ); - } - } - } - - // Discard index placeholder values to get only actual matches - setMatched = condense( setMatched ); - } - - // Add matches to results - push.apply( results, setMatched ); - - // Seedless set matches succeeding multiple successful matchers stipulate sorting - if ( outermost && !seed && setMatched.length > 0 && - ( matchedCount + setMatchers.length ) > 1 ) { - - Sizzle.uniqueSort( results ); - } - } - - // Override manipulation of globals by nested matchers - if ( outermost ) { - dirruns = dirrunsUnique; - outermostContext = contextBackup; - } - - return unmatched; - }; - - return bySet ? - markFunction( superMatcher ) : - superMatcher; -} - -compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { - var i, - setMatchers = [], - elementMatchers = [], - cached = compilerCache[ selector + " " ]; - - if ( !cached ) { - // Generate a function of recursive functions that can be used to check each element - if ( !match ) { - match = tokenize( selector ); - } - i = match.length; - while ( i-- ) { - cached = matcherFromTokens( match[i] ); - if ( cached[ expando ] ) { - setMatchers.push( cached ); - } else { - elementMatchers.push( cached ); - } - } - - // Cache the compiled function - cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) ); - - // Save selector and tokenization - cached.selector = selector; - } - return cached; -}; - -/** - * A low-level selection function that works with Sizzle's compiled - * selector functions - * @param {String|Function} selector A selector or a pre-compiled - * selector function built with Sizzle.compile - * @param {Element} context - * @param {Array} [results] - * @param {Array} [seed] A set of elements to match against - */ -select = Sizzle.select = function( selector, context, results, seed ) { - var i, tokens, token, type, find, - compiled = typeof selector === "function" && selector, - match = !seed && tokenize( (selector = compiled.selector || selector) ); - - results = results || []; - - // Try to minimize operations if there is only one selector in the list and no seed - // (the latter of which guarantees us context) - if ( match.length === 1 ) { - - // Reduce context if the leading compound selector is an ID - tokens = match[0] = match[0].slice( 0 ); - if ( tokens.length > 2 && (token = tokens[0]).type === "ID" && - context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[1].type ] ) { - - context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0]; - if ( !context ) { - return results; - - // Precompiled matchers will still verify ancestry, so step up a level - } else if ( compiled ) { - context = context.parentNode; - } - - selector = selector.slice( tokens.shift().value.length ); - } - - // Fetch a seed set for right-to-left matching - i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length; - while ( i-- ) { - token = tokens[i]; - - // Abort if we hit a combinator - if ( Expr.relative[ (type = token.type) ] ) { - break; - } - if ( (find = Expr.find[ type ]) ) { - // Search, expanding context for leading sibling combinators - if ( (seed = find( - token.matches[0].replace( runescape, funescape ), - rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context - )) ) { - - // If seed is empty or no tokens remain, we can return early - tokens.splice( i, 1 ); - selector = seed.length && toSelector( tokens ); - if ( !selector ) { - push.apply( results, seed ); - return results; - } - - break; - } - } - } - } - - // Compile and execute a filtering function if one is not provided - // Provide `match` to avoid retokenization if we modified the selector above - ( compiled || compile( selector, match ) )( - seed, - context, - !documentIsHTML, - results, - !context || rsibling.test( selector ) && testContext( context.parentNode ) || context - ); - return results; -}; - -// One-time assignments - -// Sort stability -support.sortStable = expando.split("").sort( sortOrder ).join("") === expando; - -// Support: Chrome 14-35+ -// Always assume duplicates if they aren't passed to the comparison function -support.detectDuplicates = !!hasDuplicate; - -// Initialize against the default document -setDocument(); - -// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27) -// Detached nodes confoundingly follow *each other* -support.sortDetached = assert(function( el ) { - // Should return 1, but returns 4 (following) - return el.compareDocumentPosition( document.createElement("fieldset") ) & 1; -}); - -// Support: IE<8 -// Prevent attribute/property "interpolation" -// https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx -if ( !assert(function( el ) { - el.innerHTML = ""; - return el.firstChild.getAttribute("href") === "#" ; -}) ) { - addHandle( "type|href|height|width", function( elem, name, isXML ) { - if ( !isXML ) { - return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 ); - } - }); -} - -// Support: IE<9 -// Use defaultValue in place of getAttribute("value") -if ( !support.attributes || !assert(function( el ) { - el.innerHTML = ""; - el.firstChild.setAttribute( "value", "" ); - return el.firstChild.getAttribute( "value" ) === ""; -}) ) { - addHandle( "value", function( elem, name, isXML ) { - if ( !isXML && elem.nodeName.toLowerCase() === "input" ) { - return elem.defaultValue; - } - }); -} - -// Support: IE<9 -// Use getAttributeNode to fetch booleans when getAttribute lies -if ( !assert(function( el ) { - return el.getAttribute("disabled") == null; -}) ) { - addHandle( booleans, function( elem, name, isXML ) { - var val; - if ( !isXML ) { - return elem[ name ] === true ? name.toLowerCase() : - (val = elem.getAttributeNode( name )) && val.specified ? - val.value : - null; - } - }); -} - -return Sizzle; - -})( window ); - - - -jQuery.find = Sizzle; -jQuery.expr = Sizzle.selectors; - -// Deprecated -jQuery.expr[ ":" ] = jQuery.expr.pseudos; -jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort; -jQuery.text = Sizzle.getText; -jQuery.isXMLDoc = Sizzle.isXML; -jQuery.contains = Sizzle.contains; -jQuery.escapeSelector = Sizzle.escape; - - - - -var dir = function( elem, dir, until ) { - var matched = [], - truncate = until !== undefined; - - while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) { - if ( elem.nodeType === 1 ) { - if ( truncate && jQuery( elem ).is( until ) ) { - break; - } - matched.push( elem ); - } - } - return matched; -}; - - -var siblings = function( n, elem ) { - var matched = []; - - for ( ; n; n = n.nextSibling ) { - if ( n.nodeType === 1 && n !== elem ) { - matched.push( n ); - } - } - - return matched; -}; - - -var rneedsContext = jQuery.expr.match.needsContext; - - - -function nodeName( elem, name ) { - - return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); - -}; -var rsingleTag = ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i ); - - - -var risSimple = /^.[^:#\[\.,]*$/; - -// Implement the identical functionality for filter and not -function winnow( elements, qualifier, not ) { - if ( jQuery.isFunction( qualifier ) ) { - return jQuery.grep( elements, function( elem, i ) { - return !!qualifier.call( elem, i, elem ) !== not; - } ); - } - - // Single element - if ( qualifier.nodeType ) { - return jQuery.grep( elements, function( elem ) { - return ( elem === qualifier ) !== not; - } ); - } - - // Arraylike of elements (jQuery, arguments, Array) - if ( typeof qualifier !== "string" ) { - return jQuery.grep( elements, function( elem ) { - return ( indexOf.call( qualifier, elem ) > -1 ) !== not; - } ); - } - - // Simple selector that can be filtered directly, removing non-Elements - if ( risSimple.test( qualifier ) ) { - return jQuery.filter( qualifier, elements, not ); - } - - // Complex selector, compare the two sets, removing non-Elements - qualifier = jQuery.filter( qualifier, elements ); - return jQuery.grep( elements, function( elem ) { - return ( indexOf.call( qualifier, elem ) > -1 ) !== not && elem.nodeType === 1; - } ); -} - -jQuery.filter = function( expr, elems, not ) { - var elem = elems[ 0 ]; - - if ( not ) { - expr = ":not(" + expr + ")"; - } - - if ( elems.length === 1 && elem.nodeType === 1 ) { - return jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : []; - } - - return jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { - return elem.nodeType === 1; - } ) ); -}; - -jQuery.fn.extend( { - find: function( selector ) { - var i, ret, - len = this.length, - self = this; - - if ( typeof selector !== "string" ) { - return this.pushStack( jQuery( selector ).filter( function() { - for ( i = 0; i < len; i++ ) { - if ( jQuery.contains( self[ i ], this ) ) { - return true; - } - } - } ) ); - } - - ret = this.pushStack( [] ); - - for ( i = 0; i < len; i++ ) { - jQuery.find( selector, self[ i ], ret ); - } - - return len > 1 ? jQuery.uniqueSort( ret ) : ret; - }, - filter: function( selector ) { - return this.pushStack( winnow( this, selector || [], false ) ); - }, - not: function( selector ) { - return this.pushStack( winnow( this, selector || [], true ) ); - }, - is: function( selector ) { - return !!winnow( - this, - - // If this is a positional/relative selector, check membership in the returned set - // so $("p:first").is("p:last") won't return true for a doc with two "p". - typeof selector === "string" && rneedsContext.test( selector ) ? - jQuery( selector ) : - selector || [], - false - ).length; - } -} ); - - -// Initialize a jQuery object - - -// A central reference to the root jQuery(document) -var rootjQuery, - - // A simple way to check for HTML strings - // Prioritize #id over to avoid XSS via location.hash (#9521) - // Strict HTML recognition (#11290: must start with <) - // Shortcut simple #id case for speed - rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/, - - init = jQuery.fn.init = function( selector, context, root ) { - var match, elem; - - // HANDLE: $(""), $(null), $(undefined), $(false) - if ( !selector ) { - return this; - } - - // Method init() accepts an alternate rootjQuery - // so migrate can support jQuery.sub (gh-2101) - root = root || rootjQuery; - - // Handle HTML strings - if ( typeof selector === "string" ) { - if ( selector[ 0 ] === "<" && - selector[ selector.length - 1 ] === ">" && - selector.length >= 3 ) { - - // Assume that strings that start and end with <> are HTML and skip the regex check - match = [ null, selector, null ]; - - } else { - match = rquickExpr.exec( selector ); - } - - // Match html or make sure no context is specified for #id - if ( match && ( match[ 1 ] || !context ) ) { - - // HANDLE: $(html) -> $(array) - if ( match[ 1 ] ) { - context = context instanceof jQuery ? context[ 0 ] : context; - - // Option to run scripts is true for back-compat - // Intentionally let the error be thrown if parseHTML is not present - jQuery.merge( this, jQuery.parseHTML( - match[ 1 ], - context && context.nodeType ? context.ownerDocument || context : document, - true - ) ); - - // HANDLE: $(html, props) - if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) { - for ( match in context ) { - - // Properties of context are called as methods if possible - if ( jQuery.isFunction( this[ match ] ) ) { - this[ match ]( context[ match ] ); - - // ...and otherwise set as attributes - } else { - this.attr( match, context[ match ] ); - } - } - } - - return this; - - // HANDLE: $(#id) - } else { - elem = document.getElementById( match[ 2 ] ); - - if ( elem ) { - - // Inject the element directly into the jQuery object - this[ 0 ] = elem; - this.length = 1; - } - return this; - } - - // HANDLE: $(expr, $(...)) - } else if ( !context || context.jquery ) { - return ( context || root ).find( selector ); - - // HANDLE: $(expr, context) - // (which is just equivalent to: $(context).find(expr) - } else { - return this.constructor( context ).find( selector ); - } - - // HANDLE: $(DOMElement) - } else if ( selector.nodeType ) { - this[ 0 ] = selector; - this.length = 1; - return this; - - // HANDLE: $(function) - // Shortcut for document ready - } else if ( jQuery.isFunction( selector ) ) { - return root.ready !== undefined ? - root.ready( selector ) : - - // Execute immediately if ready is not present - selector( jQuery ); - } - - return jQuery.makeArray( selector, this ); - }; - -// Give the init function the jQuery prototype for later instantiation -init.prototype = jQuery.fn; - -// Initialize central reference -rootjQuery = jQuery( document ); - - -var rparentsprev = /^(?:parents|prev(?:Until|All))/, - - // Methods guaranteed to produce a unique set when starting from a unique set - guaranteedUnique = { - children: true, - contents: true, - next: true, - prev: true - }; - -jQuery.fn.extend( { - has: function( target ) { - var targets = jQuery( target, this ), - l = targets.length; - - return this.filter( function() { - var i = 0; - for ( ; i < l; i++ ) { - if ( jQuery.contains( this, targets[ i ] ) ) { - return true; - } - } - } ); - }, - - closest: function( selectors, context ) { - var cur, - i = 0, - l = this.length, - matched = [], - targets = typeof selectors !== "string" && jQuery( selectors ); - - // Positional selectors never match, since there's no _selection_ context - if ( !rneedsContext.test( selectors ) ) { - for ( ; i < l; i++ ) { - for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) { - - // Always skip document fragments - if ( cur.nodeType < 11 && ( targets ? - targets.index( cur ) > -1 : - - // Don't pass non-elements to Sizzle - cur.nodeType === 1 && - jQuery.find.matchesSelector( cur, selectors ) ) ) { - - matched.push( cur ); - break; - } - } - } - } - - return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched ); - }, - - // Determine the position of an element within the set - index: function( elem ) { - - // No argument, return index in parent - if ( !elem ) { - return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1; - } - - // Index in selector - if ( typeof elem === "string" ) { - return indexOf.call( jQuery( elem ), this[ 0 ] ); - } - - // Locate the position of the desired element - return indexOf.call( this, - - // If it receives a jQuery object, the first element is used - elem.jquery ? elem[ 0 ] : elem - ); - }, - - add: function( selector, context ) { - return this.pushStack( - jQuery.uniqueSort( - jQuery.merge( this.get(), jQuery( selector, context ) ) - ) - ); - }, - - addBack: function( selector ) { - return this.add( selector == null ? - this.prevObject : this.prevObject.filter( selector ) - ); - } -} ); - -function sibling( cur, dir ) { - while ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {} - return cur; -} - -jQuery.each( { - parent: function( elem ) { - var parent = elem.parentNode; - return parent && parent.nodeType !== 11 ? parent : null; - }, - parents: function( elem ) { - return dir( elem, "parentNode" ); - }, - parentsUntil: function( elem, i, until ) { - return dir( elem, "parentNode", until ); - }, - next: function( elem ) { - return sibling( elem, "nextSibling" ); - }, - prev: function( elem ) { - return sibling( elem, "previousSibling" ); - }, - nextAll: function( elem ) { - return dir( elem, "nextSibling" ); - }, - prevAll: function( elem ) { - return dir( elem, "previousSibling" ); - }, - nextUntil: function( elem, i, until ) { - return dir( elem, "nextSibling", until ); - }, - prevUntil: function( elem, i, until ) { - return dir( elem, "previousSibling", until ); - }, - siblings: function( elem ) { - return siblings( ( elem.parentNode || {} ).firstChild, elem ); - }, - children: function( elem ) { - return siblings( elem.firstChild ); - }, - contents: function( elem ) { - if ( nodeName( elem, "iframe" ) ) { - return elem.contentDocument; - } - - // Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only - // Treat the template element as a regular one in browsers that - // don't support it. - if ( nodeName( elem, "template" ) ) { - elem = elem.content || elem; - } - - return jQuery.merge( [], elem.childNodes ); - } -}, function( name, fn ) { - jQuery.fn[ name ] = function( until, selector ) { - var matched = jQuery.map( this, fn, until ); - - if ( name.slice( -5 ) !== "Until" ) { - selector = until; - } - - if ( selector && typeof selector === "string" ) { - matched = jQuery.filter( selector, matched ); - } - - if ( this.length > 1 ) { - - // Remove duplicates - if ( !guaranteedUnique[ name ] ) { - jQuery.uniqueSort( matched ); - } - - // Reverse order for parents* and prev-derivatives - if ( rparentsprev.test( name ) ) { - matched.reverse(); - } - } - - return this.pushStack( matched ); - }; -} ); -var rnothtmlwhite = ( /[^\x20\t\r\n\f]+/g ); - - - -// Convert String-formatted options into Object-formatted ones -function createOptions( options ) { - var object = {}; - jQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) { - object[ flag ] = true; - } ); - return object; -} - -/* - * Create a callback list using the following parameters: - * - * options: an optional list of space-separated options that will change how - * the callback list behaves or a more traditional option object - * - * By default a callback list will act like an event callback list and can be - * "fired" multiple times. - * - * Possible options: - * - * once: will ensure the callback list can only be fired once (like a Deferred) - * - * memory: will keep track of previous values and will call any callback added - * after the list has been fired right away with the latest "memorized" - * values (like a Deferred) - * - * unique: will ensure a callback can only be added once (no duplicate in the list) - * - * stopOnFalse: interrupt callings when a callback returns false - * - */ -jQuery.Callbacks = function( options ) { - - // Convert options from String-formatted to Object-formatted if needed - // (we check in cache first) - options = typeof options === "string" ? - createOptions( options ) : - jQuery.extend( {}, options ); - - var // Flag to know if list is currently firing - firing, - - // Last fire value for non-forgettable lists - memory, - - // Flag to know if list was already fired - fired, - - // Flag to prevent firing - locked, - - // Actual callback list - list = [], - - // Queue of execution data for repeatable lists - queue = [], - - // Index of currently firing callback (modified by add/remove as needed) - firingIndex = -1, - - // Fire callbacks - fire = function() { - - // Enforce single-firing - locked = locked || options.once; - - // Execute callbacks for all pending executions, - // respecting firingIndex overrides and runtime changes - fired = firing = true; - for ( ; queue.length; firingIndex = -1 ) { - memory = queue.shift(); - while ( ++firingIndex < list.length ) { - - // Run callback and check for early termination - if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false && - options.stopOnFalse ) { - - // Jump to end and forget the data so .add doesn't re-fire - firingIndex = list.length; - memory = false; - } - } - } - - // Forget the data if we're done with it - if ( !options.memory ) { - memory = false; - } - - firing = false; - - // Clean up if we're done firing for good - if ( locked ) { - - // Keep an empty list if we have data for future add calls - if ( memory ) { - list = []; - - // Otherwise, this object is spent - } else { - list = ""; - } - } - }, - - // Actual Callbacks object - self = { - - // Add a callback or a collection of callbacks to the list - add: function() { - if ( list ) { - - // If we have memory from a past run, we should fire after adding - if ( memory && !firing ) { - firingIndex = list.length - 1; - queue.push( memory ); - } - - ( function add( args ) { - jQuery.each( args, function( _, arg ) { - if ( jQuery.isFunction( arg ) ) { - if ( !options.unique || !self.has( arg ) ) { - list.push( arg ); - } - } else if ( arg && arg.length && jQuery.type( arg ) !== "string" ) { - - // Inspect recursively - add( arg ); - } - } ); - } )( arguments ); - - if ( memory && !firing ) { - fire(); - } - } - return this; - }, - - // Remove a callback from the list - remove: function() { - jQuery.each( arguments, function( _, arg ) { - var index; - while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { - list.splice( index, 1 ); - - // Handle firing indexes - if ( index <= firingIndex ) { - firingIndex--; - } - } - } ); - return this; - }, - - // Check if a given callback is in the list. - // If no argument is given, return whether or not list has callbacks attached. - has: function( fn ) { - return fn ? - jQuery.inArray( fn, list ) > -1 : - list.length > 0; - }, - - // Remove all callbacks from the list - empty: function() { - if ( list ) { - list = []; - } - return this; - }, - - // Disable .fire and .add - // Abort any current/pending executions - // Clear all callbacks and values - disable: function() { - locked = queue = []; - list = memory = ""; - return this; - }, - disabled: function() { - return !list; - }, - - // Disable .fire - // Also disable .add unless we have memory (since it would have no effect) - // Abort any pending executions - lock: function() { - locked = queue = []; - if ( !memory && !firing ) { - list = memory = ""; - } - return this; - }, - locked: function() { - return !!locked; - }, - - // Call all callbacks with the given context and arguments - fireWith: function( context, args ) { - if ( !locked ) { - args = args || []; - args = [ context, args.slice ? args.slice() : args ]; - queue.push( args ); - if ( !firing ) { - fire(); - } - } - return this; - }, - - // Call all the callbacks with the given arguments - fire: function() { - self.fireWith( this, arguments ); - return this; - }, - - // To know if the callbacks have already been called at least once - fired: function() { - return !!fired; - } - }; - - return self; -}; - - -function Identity( v ) { - return v; -} -function Thrower( ex ) { - throw ex; -} - -function adoptValue( value, resolve, reject, noValue ) { - var method; - - try { - - // Check for promise aspect first to privilege synchronous behavior - if ( value && jQuery.isFunction( ( method = value.promise ) ) ) { - method.call( value ).done( resolve ).fail( reject ); - - // Other thenables - } else if ( value && jQuery.isFunction( ( method = value.then ) ) ) { - method.call( value, resolve, reject ); - - // Other non-thenables - } else { - - // Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer: - // * false: [ value ].slice( 0 ) => resolve( value ) - // * true: [ value ].slice( 1 ) => resolve() - resolve.apply( undefined, [ value ].slice( noValue ) ); - } - - // For Promises/A+, convert exceptions into rejections - // Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in - // Deferred#then to conditionally suppress rejection. - } catch ( value ) { - - // Support: Android 4.0 only - // Strict mode functions invoked without .call/.apply get global-object context - reject.apply( undefined, [ value ] ); - } -} - -jQuery.extend( { - - Deferred: function( func ) { - var tuples = [ - - // action, add listener, callbacks, - // ... .then handlers, argument index, [final state] - [ "notify", "progress", jQuery.Callbacks( "memory" ), - jQuery.Callbacks( "memory" ), 2 ], - [ "resolve", "done", jQuery.Callbacks( "once memory" ), - jQuery.Callbacks( "once memory" ), 0, "resolved" ], - [ "reject", "fail", jQuery.Callbacks( "once memory" ), - jQuery.Callbacks( "once memory" ), 1, "rejected" ] - ], - state = "pending", - promise = { - state: function() { - return state; - }, - always: function() { - deferred.done( arguments ).fail( arguments ); - return this; - }, - "catch": function( fn ) { - return promise.then( null, fn ); - }, - - // Keep pipe for back-compat - pipe: function( /* fnDone, fnFail, fnProgress */ ) { - var fns = arguments; - - return jQuery.Deferred( function( newDefer ) { - jQuery.each( tuples, function( i, tuple ) { - - // Map tuples (progress, done, fail) to arguments (done, fail, progress) - var fn = jQuery.isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ]; - - // deferred.progress(function() { bind to newDefer or newDefer.notify }) - // deferred.done(function() { bind to newDefer or newDefer.resolve }) - // deferred.fail(function() { bind to newDefer or newDefer.reject }) - deferred[ tuple[ 1 ] ]( function() { - var returned = fn && fn.apply( this, arguments ); - if ( returned && jQuery.isFunction( returned.promise ) ) { - returned.promise() - .progress( newDefer.notify ) - .done( newDefer.resolve ) - .fail( newDefer.reject ); - } else { - newDefer[ tuple[ 0 ] + "With" ]( - this, - fn ? [ returned ] : arguments - ); - } - } ); - } ); - fns = null; - } ).promise(); - }, - then: function( onFulfilled, onRejected, onProgress ) { - var maxDepth = 0; - function resolve( depth, deferred, handler, special ) { - return function() { - var that = this, - args = arguments, - mightThrow = function() { - var returned, then; - - // Support: Promises/A+ section 2.3.3.3.3 - // https://promisesaplus.com/#point-59 - // Ignore double-resolution attempts - if ( depth < maxDepth ) { - return; - } - - returned = handler.apply( that, args ); - - // Support: Promises/A+ section 2.3.1 - // https://promisesaplus.com/#point-48 - if ( returned === deferred.promise() ) { - throw new TypeError( "Thenable self-resolution" ); - } - - // Support: Promises/A+ sections 2.3.3.1, 3.5 - // https://promisesaplus.com/#point-54 - // https://promisesaplus.com/#point-75 - // Retrieve `then` only once - then = returned && - - // Support: Promises/A+ section 2.3.4 - // https://promisesaplus.com/#point-64 - // Only check objects and functions for thenability - ( typeof returned === "object" || - typeof returned === "function" ) && - returned.then; - - // Handle a returned thenable - if ( jQuery.isFunction( then ) ) { - - // Special processors (notify) just wait for resolution - if ( special ) { - then.call( - returned, - resolve( maxDepth, deferred, Identity, special ), - resolve( maxDepth, deferred, Thrower, special ) - ); - - // Normal processors (resolve) also hook into progress - } else { - - // ...and disregard older resolution values - maxDepth++; - - then.call( - returned, - resolve( maxDepth, deferred, Identity, special ), - resolve( maxDepth, deferred, Thrower, special ), - resolve( maxDepth, deferred, Identity, - deferred.notifyWith ) - ); - } - - // Handle all other returned values - } else { - - // Only substitute handlers pass on context - // and multiple values (non-spec behavior) - if ( handler !== Identity ) { - that = undefined; - args = [ returned ]; - } - - // Process the value(s) - // Default process is resolve - ( special || deferred.resolveWith )( that, args ); - } - }, - - // Only normal processors (resolve) catch and reject exceptions - process = special ? - mightThrow : - function() { - try { - mightThrow(); - } catch ( e ) { - - if ( jQuery.Deferred.exceptionHook ) { - jQuery.Deferred.exceptionHook( e, - process.stackTrace ); - } - - // Support: Promises/A+ section 2.3.3.3.4.1 - // https://promisesaplus.com/#point-61 - // Ignore post-resolution exceptions - if ( depth + 1 >= maxDepth ) { - - // Only substitute handlers pass on context - // and multiple values (non-spec behavior) - if ( handler !== Thrower ) { - that = undefined; - args = [ e ]; - } - - deferred.rejectWith( that, args ); - } - } - }; - - // Support: Promises/A+ section 2.3.3.3.1 - // https://promisesaplus.com/#point-57 - // Re-resolve promises immediately to dodge false rejection from - // subsequent errors - if ( depth ) { - process(); - } else { - - // Call an optional hook to record the stack, in case of exception - // since it's otherwise lost when execution goes async - if ( jQuery.Deferred.getStackHook ) { - process.stackTrace = jQuery.Deferred.getStackHook(); - } - window.setTimeout( process ); - } - }; - } - - return jQuery.Deferred( function( newDefer ) { - - // progress_handlers.add( ... ) - tuples[ 0 ][ 3 ].add( - resolve( - 0, - newDefer, - jQuery.isFunction( onProgress ) ? - onProgress : - Identity, - newDefer.notifyWith - ) - ); - - // fulfilled_handlers.add( ... ) - tuples[ 1 ][ 3 ].add( - resolve( - 0, - newDefer, - jQuery.isFunction( onFulfilled ) ? - onFulfilled : - Identity - ) - ); - - // rejected_handlers.add( ... ) - tuples[ 2 ][ 3 ].add( - resolve( - 0, - newDefer, - jQuery.isFunction( onRejected ) ? - onRejected : - Thrower - ) - ); - } ).promise(); - }, - - // Get a promise for this deferred - // If obj is provided, the promise aspect is added to the object - promise: function( obj ) { - return obj != null ? jQuery.extend( obj, promise ) : promise; - } - }, - deferred = {}; - - // Add list-specific methods - jQuery.each( tuples, function( i, tuple ) { - var list = tuple[ 2 ], - stateString = tuple[ 5 ]; - - // promise.progress = list.add - // promise.done = list.add - // promise.fail = list.add - promise[ tuple[ 1 ] ] = list.add; - - // Handle state - if ( stateString ) { - list.add( - function() { - - // state = "resolved" (i.e., fulfilled) - // state = "rejected" - state = stateString; - }, - - // rejected_callbacks.disable - // fulfilled_callbacks.disable - tuples[ 3 - i ][ 2 ].disable, - - // progress_callbacks.lock - tuples[ 0 ][ 2 ].lock - ); - } - - // progress_handlers.fire - // fulfilled_handlers.fire - // rejected_handlers.fire - list.add( tuple[ 3 ].fire ); - - // deferred.notify = function() { deferred.notifyWith(...) } - // deferred.resolve = function() { deferred.resolveWith(...) } - // deferred.reject = function() { deferred.rejectWith(...) } - deferred[ tuple[ 0 ] ] = function() { - deferred[ tuple[ 0 ] + "With" ]( this === deferred ? undefined : this, arguments ); - return this; - }; - - // deferred.notifyWith = list.fireWith - // deferred.resolveWith = list.fireWith - // deferred.rejectWith = list.fireWith - deferred[ tuple[ 0 ] + "With" ] = list.fireWith; - } ); - - // Make the deferred a promise - promise.promise( deferred ); - - // Call given func if any - if ( func ) { - func.call( deferred, deferred ); - } - - // All done! - return deferred; - }, - - // Deferred helper - when: function( singleValue ) { - var - - // count of uncompleted subordinates - remaining = arguments.length, - - // count of unprocessed arguments - i = remaining, - - // subordinate fulfillment data - resolveContexts = Array( i ), - resolveValues = slice.call( arguments ), - - // the master Deferred - master = jQuery.Deferred(), - - // subordinate callback factory - updateFunc = function( i ) { - return function( value ) { - resolveContexts[ i ] = this; - resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; - if ( !( --remaining ) ) { - master.resolveWith( resolveContexts, resolveValues ); - } - }; - }; - - // Single- and empty arguments are adopted like Promise.resolve - if ( remaining <= 1 ) { - adoptValue( singleValue, master.done( updateFunc( i ) ).resolve, master.reject, - !remaining ); - - // Use .then() to unwrap secondary thenables (cf. gh-3000) - if ( master.state() === "pending" || - jQuery.isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) { - - return master.then(); - } - } - - // Multiple arguments are aggregated like Promise.all array elements - while ( i-- ) { - adoptValue( resolveValues[ i ], updateFunc( i ), master.reject ); - } - - return master.promise(); - } -} ); - - -// These usually indicate a programmer mistake during development, -// warn about them ASAP rather than swallowing them by default. -var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/; - -jQuery.Deferred.exceptionHook = function( error, stack ) { - - // Support: IE 8 - 9 only - // Console exists when dev tools are open, which can happen at any time - if ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) { - window.console.warn( "jQuery.Deferred exception: " + error.message, error.stack, stack ); - } -}; - - - - -jQuery.readyException = function( error ) { - window.setTimeout( function() { - throw error; - } ); -}; - - - - -// The deferred used on DOM ready -var readyList = jQuery.Deferred(); - -jQuery.fn.ready = function( fn ) { - - readyList - .then( fn ) - - // Wrap jQuery.readyException in a function so that the lookup - // happens at the time of error handling instead of callback - // registration. - .catch( function( error ) { - jQuery.readyException( error ); - } ); - - return this; -}; - -jQuery.extend( { - - // Is the DOM ready to be used? Set to true once it occurs. - isReady: false, - - // A counter to track how many items to wait for before - // the ready event fires. See #6781 - readyWait: 1, - - // Handle when the DOM is ready - ready: function( wait ) { - - // Abort if there are pending holds or we're already ready - if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { - return; - } - - // Remember that the DOM is ready - jQuery.isReady = true; - - // If a normal DOM Ready event fired, decrement, and wait if need be - if ( wait !== true && --jQuery.readyWait > 0 ) { - return; - } - - // If there are functions bound, to execute - readyList.resolveWith( document, [ jQuery ] ); - } -} ); - -jQuery.ready.then = readyList.then; - -// The ready event handler and self cleanup method -function completed() { - document.removeEventListener( "DOMContentLoaded", completed ); - window.removeEventListener( "load", completed ); - jQuery.ready(); -} - -// Catch cases where $(document).ready() is called -// after the browser event has already occurred. -// Support: IE <=9 - 10 only -// Older IE sometimes signals "interactive" too soon -if ( document.readyState === "complete" || - ( document.readyState !== "loading" && !document.documentElement.doScroll ) ) { - - // Handle it asynchronously to allow scripts the opportunity to delay ready - window.setTimeout( jQuery.ready ); - -} else { - - // Use the handy event callback - document.addEventListener( "DOMContentLoaded", completed ); - - // A fallback to window.onload, that will always work - window.addEventListener( "load", completed ); -} - - - - -// Multifunctional method to get and set values of a collection -// The value/s can optionally be executed if it's a function -var access = function( elems, fn, key, value, chainable, emptyGet, raw ) { - var i = 0, - len = elems.length, - bulk = key == null; - - // Sets many values - if ( jQuery.type( key ) === "object" ) { - chainable = true; - for ( i in key ) { - access( elems, fn, i, key[ i ], true, emptyGet, raw ); - } - - // Sets one value - } else if ( value !== undefined ) { - chainable = true; - - if ( !jQuery.isFunction( value ) ) { - raw = true; - } - - if ( bulk ) { - - // Bulk operations run against the entire set - if ( raw ) { - fn.call( elems, value ); - fn = null; - - // ...except when executing function values - } else { - bulk = fn; - fn = function( elem, key, value ) { - return bulk.call( jQuery( elem ), value ); - }; - } - } - - if ( fn ) { - for ( ; i < len; i++ ) { - fn( - elems[ i ], key, raw ? - value : - value.call( elems[ i ], i, fn( elems[ i ], key ) ) - ); - } - } - } - - if ( chainable ) { - return elems; - } - - // Gets - if ( bulk ) { - return fn.call( elems ); - } - - return len ? fn( elems[ 0 ], key ) : emptyGet; -}; -var acceptData = function( owner ) { - - // Accepts only: - // - Node - // - Node.ELEMENT_NODE - // - Node.DOCUMENT_NODE - // - Object - // - Any - return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType ); -}; - - - - -function Data() { - this.expando = jQuery.expando + Data.uid++; -} - -Data.uid = 1; - -Data.prototype = { - - cache: function( owner ) { - - // Check if the owner object already has a cache - var value = owner[ this.expando ]; - - // If not, create one - if ( !value ) { - value = {}; - - // We can accept data for non-element nodes in modern browsers, - // but we should not, see #8335. - // Always return an empty object. - if ( acceptData( owner ) ) { - - // If it is a node unlikely to be stringify-ed or looped over - // use plain assignment - if ( owner.nodeType ) { - owner[ this.expando ] = value; - - // Otherwise secure it in a non-enumerable property - // configurable must be true to allow the property to be - // deleted when data is removed - } else { - Object.defineProperty( owner, this.expando, { - value: value, - configurable: true - } ); - } - } - } - - return value; - }, - set: function( owner, data, value ) { - var prop, - cache = this.cache( owner ); - - // Handle: [ owner, key, value ] args - // Always use camelCase key (gh-2257) - if ( typeof data === "string" ) { - cache[ jQuery.camelCase( data ) ] = value; - - // Handle: [ owner, { properties } ] args - } else { - - // Copy the properties one-by-one to the cache object - for ( prop in data ) { - cache[ jQuery.camelCase( prop ) ] = data[ prop ]; - } - } - return cache; - }, - get: function( owner, key ) { - return key === undefined ? - this.cache( owner ) : - - // Always use camelCase key (gh-2257) - owner[ this.expando ] && owner[ this.expando ][ jQuery.camelCase( key ) ]; - }, - access: function( owner, key, value ) { - - // In cases where either: - // - // 1. No key was specified - // 2. A string key was specified, but no value provided - // - // Take the "read" path and allow the get method to determine - // which value to return, respectively either: - // - // 1. The entire cache object - // 2. The data stored at the key - // - if ( key === undefined || - ( ( key && typeof key === "string" ) && value === undefined ) ) { - - return this.get( owner, key ); - } - - // When the key is not a string, or both a key and value - // are specified, set or extend (existing objects) with either: - // - // 1. An object of properties - // 2. A key and value - // - this.set( owner, key, value ); - - // Since the "set" path can have two possible entry points - // return the expected data based on which path was taken[*] - return value !== undefined ? value : key; - }, - remove: function( owner, key ) { - var i, - cache = owner[ this.expando ]; - - if ( cache === undefined ) { - return; - } - - if ( key !== undefined ) { - - // Support array or space separated string of keys - if ( Array.isArray( key ) ) { - - // If key is an array of keys... - // We always set camelCase keys, so remove that. - key = key.map( jQuery.camelCase ); - } else { - key = jQuery.camelCase( key ); - - // If a key with the spaces exists, use it. - // Otherwise, create an array by matching non-whitespace - key = key in cache ? - [ key ] : - ( key.match( rnothtmlwhite ) || [] ); - } - - i = key.length; - - while ( i-- ) { - delete cache[ key[ i ] ]; - } - } - - // Remove the expando if there's no more data - if ( key === undefined || jQuery.isEmptyObject( cache ) ) { - - // Support: Chrome <=35 - 45 - // Webkit & Blink performance suffers when deleting properties - // from DOM nodes, so set to undefined instead - // https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted) - if ( owner.nodeType ) { - owner[ this.expando ] = undefined; - } else { - delete owner[ this.expando ]; - } - } - }, - hasData: function( owner ) { - var cache = owner[ this.expando ]; - return cache !== undefined && !jQuery.isEmptyObject( cache ); - } -}; -var dataPriv = new Data(); - -var dataUser = new Data(); - - - -// Implementation Summary -// -// 1. Enforce API surface and semantic compatibility with 1.9.x branch -// 2. Improve the module's maintainability by reducing the storage -// paths to a single mechanism. -// 3. Use the same single mechanism to support "private" and "user" data. -// 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData) -// 5. Avoid exposing implementation details on user objects (eg. expando properties) -// 6. Provide a clear path for implementation upgrade to WeakMap in 2014 - -var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, - rmultiDash = /[A-Z]/g; - -function getData( data ) { - if ( data === "true" ) { - return true; - } - - if ( data === "false" ) { - return false; - } - - if ( data === "null" ) { - return null; - } - - // Only convert to a number if it doesn't change the string - if ( data === +data + "" ) { - return +data; - } - - if ( rbrace.test( data ) ) { - return JSON.parse( data ); - } - - return data; -} - -function dataAttr( elem, key, data ) { - var name; - - // If nothing was found internally, try to fetch any - // data from the HTML5 data-* attribute - if ( data === undefined && elem.nodeType === 1 ) { - name = "data-" + key.replace( rmultiDash, "-$&" ).toLowerCase(); - data = elem.getAttribute( name ); - - if ( typeof data === "string" ) { - try { - data = getData( data ); - } catch ( e ) {} - - // Make sure we set the data so it isn't changed later - dataUser.set( elem, key, data ); - } else { - data = undefined; - } - } - return data; -} - -jQuery.extend( { - hasData: function( elem ) { - return dataUser.hasData( elem ) || dataPriv.hasData( elem ); - }, - - data: function( elem, name, data ) { - return dataUser.access( elem, name, data ); - }, - - removeData: function( elem, name ) { - dataUser.remove( elem, name ); - }, - - // TODO: Now that all calls to _data and _removeData have been replaced - // with direct calls to dataPriv methods, these can be deprecated. - _data: function( elem, name, data ) { - return dataPriv.access( elem, name, data ); - }, - - _removeData: function( elem, name ) { - dataPriv.remove( elem, name ); - } -} ); - -jQuery.fn.extend( { - data: function( key, value ) { - var i, name, data, - elem = this[ 0 ], - attrs = elem && elem.attributes; - - // Gets all values - if ( key === undefined ) { - if ( this.length ) { - data = dataUser.get( elem ); - - if ( elem.nodeType === 1 && !dataPriv.get( elem, "hasDataAttrs" ) ) { - i = attrs.length; - while ( i-- ) { - - // Support: IE 11 only - // The attrs elements can be null (#14894) - if ( attrs[ i ] ) { - name = attrs[ i ].name; - if ( name.indexOf( "data-" ) === 0 ) { - name = jQuery.camelCase( name.slice( 5 ) ); - dataAttr( elem, name, data[ name ] ); - } - } - } - dataPriv.set( elem, "hasDataAttrs", true ); - } - } - - return data; - } - - // Sets multiple values - if ( typeof key === "object" ) { - return this.each( function() { - dataUser.set( this, key ); - } ); - } - - return access( this, function( value ) { - var data; - - // The calling jQuery object (element matches) is not empty - // (and therefore has an element appears at this[ 0 ]) and the - // `value` parameter was not undefined. An empty jQuery object - // will result in `undefined` for elem = this[ 0 ] which will - // throw an exception if an attempt to read a data cache is made. - if ( elem && value === undefined ) { - - // Attempt to get data from the cache - // The key will always be camelCased in Data - data = dataUser.get( elem, key ); - if ( data !== undefined ) { - return data; - } - - // Attempt to "discover" the data in - // HTML5 custom data-* attrs - data = dataAttr( elem, key ); - if ( data !== undefined ) { - return data; - } - - // We tried really hard, but the data doesn't exist. - return; - } - - // Set the data... - this.each( function() { - - // We always store the camelCased key - dataUser.set( this, key, value ); - } ); - }, null, value, arguments.length > 1, null, true ); - }, - - removeData: function( key ) { - return this.each( function() { - dataUser.remove( this, key ); - } ); - } -} ); - - -jQuery.extend( { - queue: function( elem, type, data ) { - var queue; - - if ( elem ) { - type = ( type || "fx" ) + "queue"; - queue = dataPriv.get( elem, type ); - - // Speed up dequeue by getting out quickly if this is just a lookup - if ( data ) { - if ( !queue || Array.isArray( data ) ) { - queue = dataPriv.access( elem, type, jQuery.makeArray( data ) ); - } else { - queue.push( data ); - } - } - return queue || []; - } - }, - - dequeue: function( elem, type ) { - type = type || "fx"; - - var queue = jQuery.queue( elem, type ), - startLength = queue.length, - fn = queue.shift(), - hooks = jQuery._queueHooks( elem, type ), - next = function() { - jQuery.dequeue( elem, type ); - }; - - // If the fx queue is dequeued, always remove the progress sentinel - if ( fn === "inprogress" ) { - fn = queue.shift(); - startLength--; - } - - if ( fn ) { - - // Add a progress sentinel to prevent the fx queue from being - // automatically dequeued - if ( type === "fx" ) { - queue.unshift( "inprogress" ); - } - - // Clear up the last queue stop function - delete hooks.stop; - fn.call( elem, next, hooks ); - } - - if ( !startLength && hooks ) { - hooks.empty.fire(); - } - }, - - // Not public - generate a queueHooks object, or return the current one - _queueHooks: function( elem, type ) { - var key = type + "queueHooks"; - return dataPriv.get( elem, key ) || dataPriv.access( elem, key, { - empty: jQuery.Callbacks( "once memory" ).add( function() { - dataPriv.remove( elem, [ type + "queue", key ] ); - } ) - } ); - } -} ); - -jQuery.fn.extend( { - queue: function( type, data ) { - var setter = 2; - - if ( typeof type !== "string" ) { - data = type; - type = "fx"; - setter--; - } - - if ( arguments.length < setter ) { - return jQuery.queue( this[ 0 ], type ); - } - - return data === undefined ? - this : - this.each( function() { - var queue = jQuery.queue( this, type, data ); - - // Ensure a hooks for this queue - jQuery._queueHooks( this, type ); - - if ( type === "fx" && queue[ 0 ] !== "inprogress" ) { - jQuery.dequeue( this, type ); - } - } ); - }, - dequeue: function( type ) { - return this.each( function() { - jQuery.dequeue( this, type ); - } ); - }, - clearQueue: function( type ) { - return this.queue( type || "fx", [] ); - }, - - // Get a promise resolved when queues of a certain type - // are emptied (fx is the type by default) - promise: function( type, obj ) { - var tmp, - count = 1, - defer = jQuery.Deferred(), - elements = this, - i = this.length, - resolve = function() { - if ( !( --count ) ) { - defer.resolveWith( elements, [ elements ] ); - } - }; - - if ( typeof type !== "string" ) { - obj = type; - type = undefined; - } - type = type || "fx"; - - while ( i-- ) { - tmp = dataPriv.get( elements[ i ], type + "queueHooks" ); - if ( tmp && tmp.empty ) { - count++; - tmp.empty.add( resolve ); - } - } - resolve(); - return defer.promise( obj ); - } -} ); -var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source; - -var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ); - - -var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; - -var isHiddenWithinTree = function( elem, el ) { - - // isHiddenWithinTree might be called from jQuery#filter function; - // in that case, element will be second argument - elem = el || elem; - - // Inline style trumps all - return elem.style.display === "none" || - elem.style.display === "" && - - // Otherwise, check computed style - // Support: Firefox <=43 - 45 - // Disconnected elements can have computed display: none, so first confirm that elem is - // in the document. - jQuery.contains( elem.ownerDocument, elem ) && - - jQuery.css( elem, "display" ) === "none"; - }; - -var swap = function( elem, options, callback, args ) { - var ret, name, - old = {}; - - // Remember the old values, and insert the new ones - for ( name in options ) { - old[ name ] = elem.style[ name ]; - elem.style[ name ] = options[ name ]; - } - - ret = callback.apply( elem, args || [] ); - - // Revert the old values - for ( name in options ) { - elem.style[ name ] = old[ name ]; - } - - return ret; -}; - - - - -function adjustCSS( elem, prop, valueParts, tween ) { - var adjusted, - scale = 1, - maxIterations = 20, - currentValue = tween ? - function() { - return tween.cur(); - } : - function() { - return jQuery.css( elem, prop, "" ); - }, - initial = currentValue(), - unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ), - - // Starting value computation is required for potential unit mismatches - initialInUnit = ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) && - rcssNum.exec( jQuery.css( elem, prop ) ); - - if ( initialInUnit && initialInUnit[ 3 ] !== unit ) { - - // Trust units reported by jQuery.css - unit = unit || initialInUnit[ 3 ]; - - // Make sure we update the tween properties later on - valueParts = valueParts || []; - - // Iteratively approximate from a nonzero starting point - initialInUnit = +initial || 1; - - do { - - // If previous iteration zeroed out, double until we get *something*. - // Use string for doubling so we don't accidentally see scale as unchanged below - scale = scale || ".5"; - - // Adjust and apply - initialInUnit = initialInUnit / scale; - jQuery.style( elem, prop, initialInUnit + unit ); - - // Update scale, tolerating zero or NaN from tween.cur() - // Break the loop if scale is unchanged or perfect, or if we've just had enough. - } while ( - scale !== ( scale = currentValue() / initial ) && scale !== 1 && --maxIterations - ); - } - - if ( valueParts ) { - initialInUnit = +initialInUnit || +initial || 0; - - // Apply relative offset (+=/-=) if specified - adjusted = valueParts[ 1 ] ? - initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] : - +valueParts[ 2 ]; - if ( tween ) { - tween.unit = unit; - tween.start = initialInUnit; - tween.end = adjusted; - } - } - return adjusted; -} - - -var defaultDisplayMap = {}; - -function getDefaultDisplay( elem ) { - var temp, - doc = elem.ownerDocument, - nodeName = elem.nodeName, - display = defaultDisplayMap[ nodeName ]; - - if ( display ) { - return display; - } - - temp = doc.body.appendChild( doc.createElement( nodeName ) ); - display = jQuery.css( temp, "display" ); - - temp.parentNode.removeChild( temp ); - - if ( display === "none" ) { - display = "block"; - } - defaultDisplayMap[ nodeName ] = display; - - return display; -} - -function showHide( elements, show ) { - var display, elem, - values = [], - index = 0, - length = elements.length; - - // Determine new display value for elements that need to change - for ( ; index < length; index++ ) { - elem = elements[ index ]; - if ( !elem.style ) { - continue; - } - - display = elem.style.display; - if ( show ) { - - // Since we force visibility upon cascade-hidden elements, an immediate (and slow) - // check is required in this first loop unless we have a nonempty display value (either - // inline or about-to-be-restored) - if ( display === "none" ) { - values[ index ] = dataPriv.get( elem, "display" ) || null; - if ( !values[ index ] ) { - elem.style.display = ""; - } - } - if ( elem.style.display === "" && isHiddenWithinTree( elem ) ) { - values[ index ] = getDefaultDisplay( elem ); - } - } else { - if ( display !== "none" ) { - values[ index ] = "none"; - - // Remember what we're overwriting - dataPriv.set( elem, "display", display ); - } - } - } - - // Set the display of the elements in a second loop to avoid constant reflow - for ( index = 0; index < length; index++ ) { - if ( values[ index ] != null ) { - elements[ index ].style.display = values[ index ]; - } - } - - return elements; -} - -jQuery.fn.extend( { - show: function() { - return showHide( this, true ); - }, - hide: function() { - return showHide( this ); - }, - toggle: function( state ) { - if ( typeof state === "boolean" ) { - return state ? this.show() : this.hide(); - } - - return this.each( function() { - if ( isHiddenWithinTree( this ) ) { - jQuery( this ).show(); - } else { - jQuery( this ).hide(); - } - } ); - } -} ); -var rcheckableType = ( /^(?:checkbox|radio)$/i ); - -var rtagName = ( /<([a-z][^\/\0>\x20\t\r\n\f]+)/i ); - -var rscriptType = ( /^$|\/(?:java|ecma)script/i ); - - - -// We have to close these tags to support XHTML (#13200) -var wrapMap = { - - // Support: IE <=9 only - option: [ 1, "" ], - - // XHTML parsers do not magically insert elements in the - // same way that tag soup parsers do. So we cannot shorten - // this by omitting or other required elements. - thead: [ 1, "", "
" ], - col: [ 2, "", "
" ], - tr: [ 2, "", "
" ], - td: [ 3, "", "
" ], - - _default: [ 0, "", "" ] -}; - -// Support: IE <=9 only -wrapMap.optgroup = wrapMap.option; - -wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; -wrapMap.th = wrapMap.td; - - -function getAll( context, tag ) { - - // Support: IE <=9 - 11 only - // Use typeof to avoid zero-argument method invocation on host objects (#15151) - var ret; - - if ( typeof context.getElementsByTagName !== "undefined" ) { - ret = context.getElementsByTagName( tag || "*" ); - - } else if ( typeof context.querySelectorAll !== "undefined" ) { - ret = context.querySelectorAll( tag || "*" ); - - } else { - ret = []; - } - - if ( tag === undefined || tag && nodeName( context, tag ) ) { - return jQuery.merge( [ context ], ret ); - } - - return ret; -} - - -// Mark scripts as having already been evaluated -function setGlobalEval( elems, refElements ) { - var i = 0, - l = elems.length; - - for ( ; i < l; i++ ) { - dataPriv.set( - elems[ i ], - "globalEval", - !refElements || dataPriv.get( refElements[ i ], "globalEval" ) - ); - } -} - - -var rhtml = /<|&#?\w+;/; - -function buildFragment( elems, context, scripts, selection, ignored ) { - var elem, tmp, tag, wrap, contains, j, - fragment = context.createDocumentFragment(), - nodes = [], - i = 0, - l = elems.length; - - for ( ; i < l; i++ ) { - elem = elems[ i ]; - - if ( elem || elem === 0 ) { - - // Add nodes directly - if ( jQuery.type( elem ) === "object" ) { - - // Support: Android <=4.0 only, PhantomJS 1 only - // push.apply(_, arraylike) throws on ancient WebKit - jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); - - // Convert non-html into a text node - } else if ( !rhtml.test( elem ) ) { - nodes.push( context.createTextNode( elem ) ); - - // Convert html into DOM nodes - } else { - tmp = tmp || fragment.appendChild( context.createElement( "div" ) ); - - // Deserialize a standard representation - tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase(); - wrap = wrapMap[ tag ] || wrapMap._default; - tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ]; - - // Descend through wrappers to the right content - j = wrap[ 0 ]; - while ( j-- ) { - tmp = tmp.lastChild; - } - - // Support: Android <=4.0 only, PhantomJS 1 only - // push.apply(_, arraylike) throws on ancient WebKit - jQuery.merge( nodes, tmp.childNodes ); - - // Remember the top-level container - tmp = fragment.firstChild; - - // Ensure the created nodes are orphaned (#12392) - tmp.textContent = ""; - } - } - } - - // Remove wrapper from fragment - fragment.textContent = ""; - - i = 0; - while ( ( elem = nodes[ i++ ] ) ) { - - // Skip elements already in the context collection (trac-4087) - if ( selection && jQuery.inArray( elem, selection ) > -1 ) { - if ( ignored ) { - ignored.push( elem ); - } - continue; - } - - contains = jQuery.contains( elem.ownerDocument, elem ); - - // Append to fragment - tmp = getAll( fragment.appendChild( elem ), "script" ); - - // Preserve script evaluation history - if ( contains ) { - setGlobalEval( tmp ); - } - - // Capture executables - if ( scripts ) { - j = 0; - while ( ( elem = tmp[ j++ ] ) ) { - if ( rscriptType.test( elem.type || "" ) ) { - scripts.push( elem ); - } - } - } - } - - return fragment; -} - - -( function() { - var fragment = document.createDocumentFragment(), - div = fragment.appendChild( document.createElement( "div" ) ), - input = document.createElement( "input" ); - - // Support: Android 4.0 - 4.3 only - // Check state lost if the name is set (#11217) - // Support: Windows Web Apps (WWA) - // `name` and `type` must use .setAttribute for WWA (#14901) - input.setAttribute( "type", "radio" ); - input.setAttribute( "checked", "checked" ); - input.setAttribute( "name", "t" ); - - div.appendChild( input ); - - // Support: Android <=4.1 only - // Older WebKit doesn't clone checked state correctly in fragments - support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; - - // Support: IE <=11 only - // Make sure textarea (and checkbox) defaultValue is properly cloned - div.innerHTML = ""; - support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; -} )(); -var documentElement = document.documentElement; - - - -var - rkeyEvent = /^key/, - rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/, - rtypenamespace = /^([^.]*)(?:\.(.+)|)/; - -function returnTrue() { - return true; -} - -function returnFalse() { - return false; -} - -// Support: IE <=9 only -// See #13393 for more info -function safeActiveElement() { - try { - return document.activeElement; - } catch ( err ) { } -} - -function on( elem, types, selector, data, fn, one ) { - var origFn, type; - - // Types can be a map of types/handlers - if ( typeof types === "object" ) { - - // ( types-Object, selector, data ) - if ( typeof selector !== "string" ) { - - // ( types-Object, data ) - data = data || selector; - selector = undefined; - } - for ( type in types ) { - on( elem, type, selector, data, types[ type ], one ); - } - return elem; - } - - if ( data == null && fn == null ) { - - // ( types, fn ) - fn = selector; - data = selector = undefined; - } else if ( fn == null ) { - if ( typeof selector === "string" ) { - - // ( types, selector, fn ) - fn = data; - data = undefined; - } else { - - // ( types, data, fn ) - fn = data; - data = selector; - selector = undefined; - } - } - if ( fn === false ) { - fn = returnFalse; - } else if ( !fn ) { - return elem; - } - - if ( one === 1 ) { - origFn = fn; - fn = function( event ) { - - // Can use an empty set, since event contains the info - jQuery().off( event ); - return origFn.apply( this, arguments ); - }; - - // Use same guid so caller can remove using origFn - fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); - } - return elem.each( function() { - jQuery.event.add( this, types, fn, data, selector ); - } ); -} - -/* - * Helper functions for managing events -- not part of the public interface. - * Props to Dean Edwards' addEvent library for many of the ideas. - */ -jQuery.event = { - - global: {}, - - add: function( elem, types, handler, data, selector ) { - - var handleObjIn, eventHandle, tmp, - events, t, handleObj, - special, handlers, type, namespaces, origType, - elemData = dataPriv.get( elem ); - - // Don't attach events to noData or text/comment nodes (but allow plain objects) - if ( !elemData ) { - return; - } - - // Caller can pass in an object of custom data in lieu of the handler - if ( handler.handler ) { - handleObjIn = handler; - handler = handleObjIn.handler; - selector = handleObjIn.selector; - } - - // Ensure that invalid selectors throw exceptions at attach time - // Evaluate against documentElement in case elem is a non-element node (e.g., document) - if ( selector ) { - jQuery.find.matchesSelector( documentElement, selector ); - } - - // Make sure that the handler has a unique ID, used to find/remove it later - if ( !handler.guid ) { - handler.guid = jQuery.guid++; - } - - // Init the element's event structure and main handler, if this is the first - if ( !( events = elemData.events ) ) { - events = elemData.events = {}; - } - if ( !( eventHandle = elemData.handle ) ) { - eventHandle = elemData.handle = function( e ) { - - // Discard the second event of a jQuery.event.trigger() and - // when an event is called after a page has unloaded - return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ? - jQuery.event.dispatch.apply( elem, arguments ) : undefined; - }; - } - - // Handle multiple events separated by a space - types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; - t = types.length; - while ( t-- ) { - tmp = rtypenamespace.exec( types[ t ] ) || []; - type = origType = tmp[ 1 ]; - namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); - - // There *must* be a type, no attaching namespace-only handlers - if ( !type ) { - continue; - } - - // If event changes its type, use the special event handlers for the changed type - special = jQuery.event.special[ type ] || {}; - - // If selector defined, determine special event api type, otherwise given type - type = ( selector ? special.delegateType : special.bindType ) || type; - - // Update special based on newly reset type - special = jQuery.event.special[ type ] || {}; - - // handleObj is passed to all event handlers - handleObj = jQuery.extend( { - type: type, - origType: origType, - data: data, - handler: handler, - guid: handler.guid, - selector: selector, - needsContext: selector && jQuery.expr.match.needsContext.test( selector ), - namespace: namespaces.join( "." ) - }, handleObjIn ); - - // Init the event handler queue if we're the first - if ( !( handlers = events[ type ] ) ) { - handlers = events[ type ] = []; - handlers.delegateCount = 0; - - // Only use addEventListener if the special events handler returns false - if ( !special.setup || - special.setup.call( elem, data, namespaces, eventHandle ) === false ) { - - if ( elem.addEventListener ) { - elem.addEventListener( type, eventHandle ); - } - } - } - - if ( special.add ) { - special.add.call( elem, handleObj ); - - if ( !handleObj.handler.guid ) { - handleObj.handler.guid = handler.guid; - } - } - - // Add to the element's handler list, delegates in front - if ( selector ) { - handlers.splice( handlers.delegateCount++, 0, handleObj ); - } else { - handlers.push( handleObj ); - } - - // Keep track of which events have ever been used, for event optimization - jQuery.event.global[ type ] = true; - } - - }, - - // Detach an event or set of events from an element - remove: function( elem, types, handler, selector, mappedTypes ) { - - var j, origCount, tmp, - events, t, handleObj, - special, handlers, type, namespaces, origType, - elemData = dataPriv.hasData( elem ) && dataPriv.get( elem ); - - if ( !elemData || !( events = elemData.events ) ) { - return; - } - - // Once for each type.namespace in types; type may be omitted - types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; - t = types.length; - while ( t-- ) { - tmp = rtypenamespace.exec( types[ t ] ) || []; - type = origType = tmp[ 1 ]; - namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); - - // Unbind all events (on this namespace, if provided) for the element - if ( !type ) { - for ( type in events ) { - jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); - } - continue; - } - - special = jQuery.event.special[ type ] || {}; - type = ( selector ? special.delegateType : special.bindType ) || type; - handlers = events[ type ] || []; - tmp = tmp[ 2 ] && - new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ); - - // Remove matching events - origCount = j = handlers.length; - while ( j-- ) { - handleObj = handlers[ j ]; - - if ( ( mappedTypes || origType === handleObj.origType ) && - ( !handler || handler.guid === handleObj.guid ) && - ( !tmp || tmp.test( handleObj.namespace ) ) && - ( !selector || selector === handleObj.selector || - selector === "**" && handleObj.selector ) ) { - handlers.splice( j, 1 ); - - if ( handleObj.selector ) { - handlers.delegateCount--; - } - if ( special.remove ) { - special.remove.call( elem, handleObj ); - } - } - } - - // Remove generic event handler if we removed something and no more handlers exist - // (avoids potential for endless recursion during removal of special event handlers) - if ( origCount && !handlers.length ) { - if ( !special.teardown || - special.teardown.call( elem, namespaces, elemData.handle ) === false ) { - - jQuery.removeEvent( elem, type, elemData.handle ); - } - - delete events[ type ]; - } - } - - // Remove data and the expando if it's no longer used - if ( jQuery.isEmptyObject( events ) ) { - dataPriv.remove( elem, "handle events" ); - } - }, - - dispatch: function( nativeEvent ) { - - // Make a writable jQuery.Event from the native event object - var event = jQuery.event.fix( nativeEvent ); - - var i, j, ret, matched, handleObj, handlerQueue, - args = new Array( arguments.length ), - handlers = ( dataPriv.get( this, "events" ) || {} )[ event.type ] || [], - special = jQuery.event.special[ event.type ] || {}; - - // Use the fix-ed jQuery.Event rather than the (read-only) native event - args[ 0 ] = event; - - for ( i = 1; i < arguments.length; i++ ) { - args[ i ] = arguments[ i ]; - } - - event.delegateTarget = this; - - // Call the preDispatch hook for the mapped type, and let it bail if desired - if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { - return; - } - - // Determine handlers - handlerQueue = jQuery.event.handlers.call( this, event, handlers ); - - // Run delegates first; they may want to stop propagation beneath us - i = 0; - while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) { - event.currentTarget = matched.elem; - - j = 0; - while ( ( handleObj = matched.handlers[ j++ ] ) && - !event.isImmediatePropagationStopped() ) { - - // Triggered event must either 1) have no namespace, or 2) have namespace(s) - // a subset or equal to those in the bound event (both can have no namespace). - if ( !event.rnamespace || event.rnamespace.test( handleObj.namespace ) ) { - - event.handleObj = handleObj; - event.data = handleObj.data; - - ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle || - handleObj.handler ).apply( matched.elem, args ); - - if ( ret !== undefined ) { - if ( ( event.result = ret ) === false ) { - event.preventDefault(); - event.stopPropagation(); - } - } - } - } - } - - // Call the postDispatch hook for the mapped type - if ( special.postDispatch ) { - special.postDispatch.call( this, event ); - } - - return event.result; - }, - - handlers: function( event, handlers ) { - var i, handleObj, sel, matchedHandlers, matchedSelectors, - handlerQueue = [], - delegateCount = handlers.delegateCount, - cur = event.target; - - // Find delegate handlers - if ( delegateCount && - - // Support: IE <=9 - // Black-hole SVG instance trees (trac-13180) - cur.nodeType && - - // Support: Firefox <=42 - // Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861) - // https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click - // Support: IE 11 only - // ...but not arrow key "clicks" of radio inputs, which can have `button` -1 (gh-2343) - !( event.type === "click" && event.button >= 1 ) ) { - - for ( ; cur !== this; cur = cur.parentNode || this ) { - - // Don't check non-elements (#13208) - // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) - if ( cur.nodeType === 1 && !( event.type === "click" && cur.disabled === true ) ) { - matchedHandlers = []; - matchedSelectors = {}; - for ( i = 0; i < delegateCount; i++ ) { - handleObj = handlers[ i ]; - - // Don't conflict with Object.prototype properties (#13203) - sel = handleObj.selector + " "; - - if ( matchedSelectors[ sel ] === undefined ) { - matchedSelectors[ sel ] = handleObj.needsContext ? - jQuery( sel, this ).index( cur ) > -1 : - jQuery.find( sel, this, null, [ cur ] ).length; - } - if ( matchedSelectors[ sel ] ) { - matchedHandlers.push( handleObj ); - } - } - if ( matchedHandlers.length ) { - handlerQueue.push( { elem: cur, handlers: matchedHandlers } ); - } - } - } - } - - // Add the remaining (directly-bound) handlers - cur = this; - if ( delegateCount < handlers.length ) { - handlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } ); - } - - return handlerQueue; - }, - - addProp: function( name, hook ) { - Object.defineProperty( jQuery.Event.prototype, name, { - enumerable: true, - configurable: true, - - get: jQuery.isFunction( hook ) ? - function() { - if ( this.originalEvent ) { - return hook( this.originalEvent ); - } - } : - function() { - if ( this.originalEvent ) { - return this.originalEvent[ name ]; - } - }, - - set: function( value ) { - Object.defineProperty( this, name, { - enumerable: true, - configurable: true, - writable: true, - value: value - } ); - } - } ); - }, - - fix: function( originalEvent ) { - return originalEvent[ jQuery.expando ] ? - originalEvent : - new jQuery.Event( originalEvent ); - }, - - special: { - load: { - - // Prevent triggered image.load events from bubbling to window.load - noBubble: true - }, - focus: { - - // Fire native event if possible so blur/focus sequence is correct - trigger: function() { - if ( this !== safeActiveElement() && this.focus ) { - this.focus(); - return false; - } - }, - delegateType: "focusin" - }, - blur: { - trigger: function() { - if ( this === safeActiveElement() && this.blur ) { - this.blur(); - return false; - } - }, - delegateType: "focusout" - }, - click: { - - // For checkbox, fire native event so checked state will be right - trigger: function() { - if ( this.type === "checkbox" && this.click && nodeName( this, "input" ) ) { - this.click(); - return false; - } - }, - - // For cross-browser consistency, don't fire native .click() on links - _default: function( event ) { - return nodeName( event.target, "a" ); - } - }, - - beforeunload: { - postDispatch: function( event ) { - - // Support: Firefox 20+ - // Firefox doesn't alert if the returnValue field is not set. - if ( event.result !== undefined && event.originalEvent ) { - event.originalEvent.returnValue = event.result; - } - } - } - } -}; - -jQuery.removeEvent = function( elem, type, handle ) { - - // This "if" is needed for plain objects - if ( elem.removeEventListener ) { - elem.removeEventListener( type, handle ); - } -}; - -jQuery.Event = function( src, props ) { - - // Allow instantiation without the 'new' keyword - if ( !( this instanceof jQuery.Event ) ) { - return new jQuery.Event( src, props ); - } - - // Event object - if ( src && src.type ) { - this.originalEvent = src; - this.type = src.type; - - // Events bubbling up the document may have been marked as prevented - // by a handler lower down the tree; reflect the correct value. - this.isDefaultPrevented = src.defaultPrevented || - src.defaultPrevented === undefined && - - // Support: Android <=2.3 only - src.returnValue === false ? - returnTrue : - returnFalse; - - // Create target properties - // Support: Safari <=6 - 7 only - // Target should not be a text node (#504, #13143) - this.target = ( src.target && src.target.nodeType === 3 ) ? - src.target.parentNode : - src.target; - - this.currentTarget = src.currentTarget; - this.relatedTarget = src.relatedTarget; - - // Event type - } else { - this.type = src; - } - - // Put explicitly provided properties onto the event object - if ( props ) { - jQuery.extend( this, props ); - } - - // Create a timestamp if incoming event doesn't have one - this.timeStamp = src && src.timeStamp || jQuery.now(); - - // Mark it as fixed - this[ jQuery.expando ] = true; -}; - -// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding -// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html -jQuery.Event.prototype = { - constructor: jQuery.Event, - isDefaultPrevented: returnFalse, - isPropagationStopped: returnFalse, - isImmediatePropagationStopped: returnFalse, - isSimulated: false, - - preventDefault: function() { - var e = this.originalEvent; - - this.isDefaultPrevented = returnTrue; - - if ( e && !this.isSimulated ) { - e.preventDefault(); - } - }, - stopPropagation: function() { - var e = this.originalEvent; - - this.isPropagationStopped = returnTrue; - - if ( e && !this.isSimulated ) { - e.stopPropagation(); - } - }, - stopImmediatePropagation: function() { - var e = this.originalEvent; - - this.isImmediatePropagationStopped = returnTrue; - - if ( e && !this.isSimulated ) { - e.stopImmediatePropagation(); - } - - this.stopPropagation(); - } -}; - -// Includes all common event props including KeyEvent and MouseEvent specific props -jQuery.each( { - altKey: true, - bubbles: true, - cancelable: true, - changedTouches: true, - ctrlKey: true, - detail: true, - eventPhase: true, - metaKey: true, - pageX: true, - pageY: true, - shiftKey: true, - view: true, - "char": true, - charCode: true, - key: true, - keyCode: true, - button: true, - buttons: true, - clientX: true, - clientY: true, - offsetX: true, - offsetY: true, - pointerId: true, - pointerType: true, - screenX: true, - screenY: true, - targetTouches: true, - toElement: true, - touches: true, - - which: function( event ) { - var button = event.button; - - // Add which for key events - if ( event.which == null && rkeyEvent.test( event.type ) ) { - return event.charCode != null ? event.charCode : event.keyCode; - } - - // Add which for click: 1 === left; 2 === middle; 3 === right - if ( !event.which && button !== undefined && rmouseEvent.test( event.type ) ) { - if ( button & 1 ) { - return 1; - } - - if ( button & 2 ) { - return 3; - } - - if ( button & 4 ) { - return 2; - } - - return 0; - } - - return event.which; - } -}, jQuery.event.addProp ); - -// Create mouseenter/leave events using mouseover/out and event-time checks -// so that event delegation works in jQuery. -// Do the same for pointerenter/pointerleave and pointerover/pointerout -// -// Support: Safari 7 only -// Safari sends mouseenter too often; see: -// https://bugs.chromium.org/p/chromium/issues/detail?id=470258 -// for the description of the bug (it existed in older Chrome versions as well). -jQuery.each( { - mouseenter: "mouseover", - mouseleave: "mouseout", - pointerenter: "pointerover", - pointerleave: "pointerout" -}, function( orig, fix ) { - jQuery.event.special[ orig ] = { - delegateType: fix, - bindType: fix, - - handle: function( event ) { - var ret, - target = this, - related = event.relatedTarget, - handleObj = event.handleObj; - - // For mouseenter/leave call the handler if related is outside the target. - // NB: No relatedTarget if the mouse left/entered the browser window - if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) { - event.type = handleObj.origType; - ret = handleObj.handler.apply( this, arguments ); - event.type = fix; - } - return ret; - } - }; -} ); - -jQuery.fn.extend( { - - on: function( types, selector, data, fn ) { - return on( this, types, selector, data, fn ); - }, - one: function( types, selector, data, fn ) { - return on( this, types, selector, data, fn, 1 ); - }, - off: function( types, selector, fn ) { - var handleObj, type; - if ( types && types.preventDefault && types.handleObj ) { - - // ( event ) dispatched jQuery.Event - handleObj = types.handleObj; - jQuery( types.delegateTarget ).off( - handleObj.namespace ? - handleObj.origType + "." + handleObj.namespace : - handleObj.origType, - handleObj.selector, - handleObj.handler - ); - return this; - } - if ( typeof types === "object" ) { - - // ( types-object [, selector] ) - for ( type in types ) { - this.off( type, selector, types[ type ] ); - } - return this; - } - if ( selector === false || typeof selector === "function" ) { - - // ( types [, fn] ) - fn = selector; - selector = undefined; - } - if ( fn === false ) { - fn = returnFalse; - } - return this.each( function() { - jQuery.event.remove( this, types, fn, selector ); - } ); - } -} ); - - -var - - /* eslint-disable max-len */ - - // See https://github.com/eslint/eslint/issues/3229 - rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\/\0>\x20\t\r\n\f]*)[^>]*)\/>/gi, - - /* eslint-enable */ - - // Support: IE <=10 - 11, Edge 12 - 13 - // In IE/Edge using regex groups here causes severe slowdowns. - // See https://connect.microsoft.com/IE/feedback/details/1736512/ - rnoInnerhtml = /\s*$/g; - -// Prefer a tbody over its parent table for containing new rows -function manipulationTarget( elem, content ) { - if ( nodeName( elem, "table" ) && - nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ) { - - return jQuery( ">tbody", elem )[ 0 ] || elem; - } - - return elem; -} - -// Replace/restore the type attribute of script elements for safe DOM manipulation -function disableScript( elem ) { - elem.type = ( elem.getAttribute( "type" ) !== null ) + "/" + elem.type; - return elem; -} -function restoreScript( elem ) { - var match = rscriptTypeMasked.exec( elem.type ); - - if ( match ) { - elem.type = match[ 1 ]; - } else { - elem.removeAttribute( "type" ); - } - - return elem; -} - -function cloneCopyEvent( src, dest ) { - var i, l, type, pdataOld, pdataCur, udataOld, udataCur, events; - - if ( dest.nodeType !== 1 ) { - return; - } - - // 1. Copy private data: events, handlers, etc. - if ( dataPriv.hasData( src ) ) { - pdataOld = dataPriv.access( src ); - pdataCur = dataPriv.set( dest, pdataOld ); - events = pdataOld.events; - - if ( events ) { - delete pdataCur.handle; - pdataCur.events = {}; - - for ( type in events ) { - for ( i = 0, l = events[ type ].length; i < l; i++ ) { - jQuery.event.add( dest, type, events[ type ][ i ] ); - } - } - } - } - - // 2. Copy user data - if ( dataUser.hasData( src ) ) { - udataOld = dataUser.access( src ); - udataCur = jQuery.extend( {}, udataOld ); - - dataUser.set( dest, udataCur ); - } -} - -// Fix IE bugs, see support tests -function fixInput( src, dest ) { - var nodeName = dest.nodeName.toLowerCase(); - - // Fails to persist the checked state of a cloned checkbox or radio button. - if ( nodeName === "input" && rcheckableType.test( src.type ) ) { - dest.checked = src.checked; - - // Fails to return the selected option to the default selected state when cloning options - } else if ( nodeName === "input" || nodeName === "textarea" ) { - dest.defaultValue = src.defaultValue; - } -} - -function domManip( collection, args, callback, ignored ) { - - // Flatten any nested arrays - args = concat.apply( [], args ); - - var fragment, first, scripts, hasScripts, node, doc, - i = 0, - l = collection.length, - iNoClone = l - 1, - value = args[ 0 ], - isFunction = jQuery.isFunction( value ); - - // We can't cloneNode fragments that contain checked, in WebKit - if ( isFunction || - ( l > 1 && typeof value === "string" && - !support.checkClone && rchecked.test( value ) ) ) { - return collection.each( function( index ) { - var self = collection.eq( index ); - if ( isFunction ) { - args[ 0 ] = value.call( this, index, self.html() ); - } - domManip( self, args, callback, ignored ); - } ); - } - - if ( l ) { - fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored ); - first = fragment.firstChild; - - if ( fragment.childNodes.length === 1 ) { - fragment = first; - } - - // Require either new content or an interest in ignored elements to invoke the callback - if ( first || ignored ) { - scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); - hasScripts = scripts.length; - - // Use the original fragment for the last item - // instead of the first because it can end up - // being emptied incorrectly in certain situations (#8070). - for ( ; i < l; i++ ) { - node = fragment; - - if ( i !== iNoClone ) { - node = jQuery.clone( node, true, true ); - - // Keep references to cloned scripts for later restoration - if ( hasScripts ) { - - // Support: Android <=4.0 only, PhantomJS 1 only - // push.apply(_, arraylike) throws on ancient WebKit - jQuery.merge( scripts, getAll( node, "script" ) ); - } - } - - callback.call( collection[ i ], node, i ); - } - - if ( hasScripts ) { - doc = scripts[ scripts.length - 1 ].ownerDocument; - - // Reenable scripts - jQuery.map( scripts, restoreScript ); - - // Evaluate executable scripts on first document insertion - for ( i = 0; i < hasScripts; i++ ) { - node = scripts[ i ]; - if ( rscriptType.test( node.type || "" ) && - !dataPriv.access( node, "globalEval" ) && - jQuery.contains( doc, node ) ) { - - if ( node.src ) { - - // Optional AJAX dependency, but won't run scripts if not present - if ( jQuery._evalUrl ) { - jQuery._evalUrl( node.src ); - } - } else { - DOMEval( node.textContent.replace( rcleanScript, "" ), doc ); - } - } - } - } - } - } - - return collection; -} - -function remove( elem, selector, keepData ) { - var node, - nodes = selector ? jQuery.filter( selector, elem ) : elem, - i = 0; - - for ( ; ( node = nodes[ i ] ) != null; i++ ) { - if ( !keepData && node.nodeType === 1 ) { - jQuery.cleanData( getAll( node ) ); - } - - if ( node.parentNode ) { - if ( keepData && jQuery.contains( node.ownerDocument, node ) ) { - setGlobalEval( getAll( node, "script" ) ); - } - node.parentNode.removeChild( node ); - } - } - - return elem; -} - -jQuery.extend( { - htmlPrefilter: function( html ) { - return html.replace( rxhtmlTag, "<$1>" ); - }, - - clone: function( elem, dataAndEvents, deepDataAndEvents ) { - var i, l, srcElements, destElements, - clone = elem.cloneNode( true ), - inPage = jQuery.contains( elem.ownerDocument, elem ); - - // Fix IE cloning issues - if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) && - !jQuery.isXMLDoc( elem ) ) { - - // We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2 - destElements = getAll( clone ); - srcElements = getAll( elem ); - - for ( i = 0, l = srcElements.length; i < l; i++ ) { - fixInput( srcElements[ i ], destElements[ i ] ); - } - } - - // Copy the events from the original to the clone - if ( dataAndEvents ) { - if ( deepDataAndEvents ) { - srcElements = srcElements || getAll( elem ); - destElements = destElements || getAll( clone ); - - for ( i = 0, l = srcElements.length; i < l; i++ ) { - cloneCopyEvent( srcElements[ i ], destElements[ i ] ); - } - } else { - cloneCopyEvent( elem, clone ); - } - } - - // Preserve script evaluation history - destElements = getAll( clone, "script" ); - if ( destElements.length > 0 ) { - setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); - } - - // Return the cloned set - return clone; - }, - - cleanData: function( elems ) { - var data, elem, type, - special = jQuery.event.special, - i = 0; - - for ( ; ( elem = elems[ i ] ) !== undefined; i++ ) { - if ( acceptData( elem ) ) { - if ( ( data = elem[ dataPriv.expando ] ) ) { - if ( data.events ) { - for ( type in data.events ) { - if ( special[ type ] ) { - jQuery.event.remove( elem, type ); - - // This is a shortcut to avoid jQuery.event.remove's overhead - } else { - jQuery.removeEvent( elem, type, data.handle ); - } - } - } - - // Support: Chrome <=35 - 45+ - // Assign undefined instead of using delete, see Data#remove - elem[ dataPriv.expando ] = undefined; - } - if ( elem[ dataUser.expando ] ) { - - // Support: Chrome <=35 - 45+ - // Assign undefined instead of using delete, see Data#remove - elem[ dataUser.expando ] = undefined; - } - } - } - } -} ); - -jQuery.fn.extend( { - detach: function( selector ) { - return remove( this, selector, true ); - }, - - remove: function( selector ) { - return remove( this, selector ); - }, - - text: function( value ) { - return access( this, function( value ) { - return value === undefined ? - jQuery.text( this ) : - this.empty().each( function() { - if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { - this.textContent = value; - } - } ); - }, null, value, arguments.length ); - }, - - append: function() { - return domManip( this, arguments, function( elem ) { - if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { - var target = manipulationTarget( this, elem ); - target.appendChild( elem ); - } - } ); - }, - - prepend: function() { - return domManip( this, arguments, function( elem ) { - if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { - var target = manipulationTarget( this, elem ); - target.insertBefore( elem, target.firstChild ); - } - } ); - }, - - before: function() { - return domManip( this, arguments, function( elem ) { - if ( this.parentNode ) { - this.parentNode.insertBefore( elem, this ); - } - } ); - }, - - after: function() { - return domManip( this, arguments, function( elem ) { - if ( this.parentNode ) { - this.parentNode.insertBefore( elem, this.nextSibling ); - } - } ); - }, - - empty: function() { - var elem, - i = 0; - - for ( ; ( elem = this[ i ] ) != null; i++ ) { - if ( elem.nodeType === 1 ) { - - // Prevent memory leaks - jQuery.cleanData( getAll( elem, false ) ); - - // Remove any remaining nodes - elem.textContent = ""; - } - } - - return this; - }, - - clone: function( dataAndEvents, deepDataAndEvents ) { - dataAndEvents = dataAndEvents == null ? false : dataAndEvents; - deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; - - return this.map( function() { - return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); - } ); - }, - - html: function( value ) { - return access( this, function( value ) { - var elem = this[ 0 ] || {}, - i = 0, - l = this.length; - - if ( value === undefined && elem.nodeType === 1 ) { - return elem.innerHTML; - } - - // See if we can take a shortcut and just use innerHTML - if ( typeof value === "string" && !rnoInnerhtml.test( value ) && - !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) { - - value = jQuery.htmlPrefilter( value ); - - try { - for ( ; i < l; i++ ) { - elem = this[ i ] || {}; - - // Remove element nodes and prevent memory leaks - if ( elem.nodeType === 1 ) { - jQuery.cleanData( getAll( elem, false ) ); - elem.innerHTML = value; - } - } - - elem = 0; - - // If using innerHTML throws an exception, use the fallback method - } catch ( e ) {} - } - - if ( elem ) { - this.empty().append( value ); - } - }, null, value, arguments.length ); - }, - - replaceWith: function() { - var ignored = []; - - // Make the changes, replacing each non-ignored context element with the new content - return domManip( this, arguments, function( elem ) { - var parent = this.parentNode; - - if ( jQuery.inArray( this, ignored ) < 0 ) { - jQuery.cleanData( getAll( this ) ); - if ( parent ) { - parent.replaceChild( elem, this ); - } - } - - // Force callback invocation - }, ignored ); - } -} ); - -jQuery.each( { - appendTo: "append", - prependTo: "prepend", - insertBefore: "before", - insertAfter: "after", - replaceAll: "replaceWith" -}, function( name, original ) { - jQuery.fn[ name ] = function( selector ) { - var elems, - ret = [], - insert = jQuery( selector ), - last = insert.length - 1, - i = 0; - - for ( ; i <= last; i++ ) { - elems = i === last ? this : this.clone( true ); - jQuery( insert[ i ] )[ original ]( elems ); - - // Support: Android <=4.0 only, PhantomJS 1 only - // .get() because push.apply(_, arraylike) throws on ancient WebKit - push.apply( ret, elems.get() ); - } - - return this.pushStack( ret ); - }; -} ); -var rmargin = ( /^margin/ ); - -var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" ); - -var getStyles = function( elem ) { - - // Support: IE <=11 only, Firefox <=30 (#15098, #14150) - // IE throws on elements created in popups - // FF meanwhile throws on frame elements through "defaultView.getComputedStyle" - var view = elem.ownerDocument.defaultView; - - if ( !view || !view.opener ) { - view = window; - } - - return view.getComputedStyle( elem ); - }; - - - -( function() { - - // Executing both pixelPosition & boxSizingReliable tests require only one layout - // so they're executed at the same time to save the second computation. - function computeStyleTests() { - - // This is a singleton, we need to execute it only once - if ( !div ) { - return; - } - - div.style.cssText = - "box-sizing:border-box;" + - "position:relative;display:block;" + - "margin:auto;border:1px;padding:1px;" + - "top:1%;width:50%"; - div.innerHTML = ""; - documentElement.appendChild( container ); - - var divStyle = window.getComputedStyle( div ); - pixelPositionVal = divStyle.top !== "1%"; - - // Support: Android 4.0 - 4.3 only, Firefox <=3 - 44 - reliableMarginLeftVal = divStyle.marginLeft === "2px"; - boxSizingReliableVal = divStyle.width === "4px"; - - // Support: Android 4.0 - 4.3 only - // Some styles come back with percentage values, even though they shouldn't - div.style.marginRight = "50%"; - pixelMarginRightVal = divStyle.marginRight === "4px"; - - documentElement.removeChild( container ); - - // Nullify the div so it wouldn't be stored in the memory and - // it will also be a sign that checks already performed - div = null; - } - - var pixelPositionVal, boxSizingReliableVal, pixelMarginRightVal, reliableMarginLeftVal, - container = document.createElement( "div" ), - div = document.createElement( "div" ); - - // Finish early in limited (non-browser) environments - if ( !div.style ) { - return; - } - - // Support: IE <=9 - 11 only - // Style of cloned element affects source element cloned (#8908) - div.style.backgroundClip = "content-box"; - div.cloneNode( true ).style.backgroundClip = ""; - support.clearCloneStyle = div.style.backgroundClip === "content-box"; - - container.style.cssText = "border:0;width:8px;height:0;top:0;left:-9999px;" + - "padding:0;margin-top:1px;position:absolute"; - container.appendChild( div ); - - jQuery.extend( support, { - pixelPosition: function() { - computeStyleTests(); - return pixelPositionVal; - }, - boxSizingReliable: function() { - computeStyleTests(); - return boxSizingReliableVal; - }, - pixelMarginRight: function() { - computeStyleTests(); - return pixelMarginRightVal; - }, - reliableMarginLeft: function() { - computeStyleTests(); - return reliableMarginLeftVal; - } - } ); -} )(); - - -function curCSS( elem, name, computed ) { - var width, minWidth, maxWidth, ret, - - // Support: Firefox 51+ - // Retrieving style before computed somehow - // fixes an issue with getting wrong values - // on detached elements - style = elem.style; - - computed = computed || getStyles( elem ); - - // getPropertyValue is needed for: - // .css('filter') (IE 9 only, #12537) - // .css('--customProperty) (#3144) - if ( computed ) { - ret = computed.getPropertyValue( name ) || computed[ name ]; - - if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) { - ret = jQuery.style( elem, name ); - } - - // A tribute to the "awesome hack by Dean Edwards" - // Android Browser returns percentage for some values, - // but width seems to be reliably pixels. - // This is against the CSSOM draft spec: - // https://drafts.csswg.org/cssom/#resolved-values - if ( !support.pixelMarginRight() && rnumnonpx.test( ret ) && rmargin.test( name ) ) { - - // Remember the original values - width = style.width; - minWidth = style.minWidth; - maxWidth = style.maxWidth; - - // Put in the new values to get a computed value out - style.minWidth = style.maxWidth = style.width = ret; - ret = computed.width; - - // Revert the changed values - style.width = width; - style.minWidth = minWidth; - style.maxWidth = maxWidth; - } - } - - return ret !== undefined ? - - // Support: IE <=9 - 11 only - // IE returns zIndex value as an integer. - ret + "" : - ret; -} - - -function addGetHookIf( conditionFn, hookFn ) { - - // Define the hook, we'll check on the first run if it's really needed. - return { - get: function() { - if ( conditionFn() ) { - - // Hook not needed (or it's not possible to use it due - // to missing dependency), remove it. - delete this.get; - return; - } - - // Hook needed; redefine it so that the support test is not executed again. - return ( this.get = hookFn ).apply( this, arguments ); - } - }; -} - - -var - - // Swappable if display is none or starts with table - // except "table", "table-cell", or "table-caption" - // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display - rdisplayswap = /^(none|table(?!-c[ea]).+)/, - rcustomProp = /^--/, - cssShow = { position: "absolute", visibility: "hidden", display: "block" }, - cssNormalTransform = { - letterSpacing: "0", - fontWeight: "400" - }, - - cssPrefixes = [ "Webkit", "Moz", "ms" ], - emptyStyle = document.createElement( "div" ).style; - -// Return a css property mapped to a potentially vendor prefixed property -function vendorPropName( name ) { - - // Shortcut for names that are not vendor prefixed - if ( name in emptyStyle ) { - return name; - } - - // Check for vendor prefixed names - var capName = name[ 0 ].toUpperCase() + name.slice( 1 ), - i = cssPrefixes.length; - - while ( i-- ) { - name = cssPrefixes[ i ] + capName; - if ( name in emptyStyle ) { - return name; - } - } -} - -// Return a property mapped along what jQuery.cssProps suggests or to -// a vendor prefixed property. -function finalPropName( name ) { - var ret = jQuery.cssProps[ name ]; - if ( !ret ) { - ret = jQuery.cssProps[ name ] = vendorPropName( name ) || name; - } - return ret; -} - -function setPositiveNumber( elem, value, subtract ) { - - // Any relative (+/-) values have already been - // normalized at this point - var matches = rcssNum.exec( value ); - return matches ? - - // Guard against undefined "subtract", e.g., when used as in cssHooks - Math.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || "px" ) : - value; -} - -function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) { - var i, - val = 0; - - // If we already have the right measurement, avoid augmentation - if ( extra === ( isBorderBox ? "border" : "content" ) ) { - i = 4; - - // Otherwise initialize for horizontal or vertical properties - } else { - i = name === "width" ? 1 : 0; - } - - for ( ; i < 4; i += 2 ) { - - // Both box models exclude margin, so add it if we want it - if ( extra === "margin" ) { - val += jQuery.css( elem, extra + cssExpand[ i ], true, styles ); - } - - if ( isBorderBox ) { - - // border-box includes padding, so remove it if we want content - if ( extra === "content" ) { - val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); - } - - // At this point, extra isn't border nor margin, so remove border - if ( extra !== "margin" ) { - val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); - } - } else { - - // At this point, extra isn't content, so add padding - val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); - - // At this point, extra isn't content nor padding, so add border - if ( extra !== "padding" ) { - val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); - } - } - } - - return val; -} - -function getWidthOrHeight( elem, name, extra ) { - - // Start with computed style - var valueIsBorderBox, - styles = getStyles( elem ), - val = curCSS( elem, name, styles ), - isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; - - // Computed unit is not pixels. Stop here and return. - if ( rnumnonpx.test( val ) ) { - return val; - } - - // Check for style in case a browser which returns unreliable values - // for getComputedStyle silently falls back to the reliable elem.style - valueIsBorderBox = isBorderBox && - ( support.boxSizingReliable() || val === elem.style[ name ] ); - - // Fall back to offsetWidth/Height when value is "auto" - // This happens for inline elements with no explicit setting (gh-3571) - if ( val === "auto" ) { - val = elem[ "offset" + name[ 0 ].toUpperCase() + name.slice( 1 ) ]; - } - - // Normalize "", auto, and prepare for extra - val = parseFloat( val ) || 0; - - // Use the active box-sizing model to add/subtract irrelevant styles - return ( val + - augmentWidthOrHeight( - elem, - name, - extra || ( isBorderBox ? "border" : "content" ), - valueIsBorderBox, - styles - ) - ) + "px"; -} - -jQuery.extend( { - - // Add in style property hooks for overriding the default - // behavior of getting and setting a style property - cssHooks: { - opacity: { - get: function( elem, computed ) { - if ( computed ) { - - // We should always get a number back from opacity - var ret = curCSS( elem, "opacity" ); - return ret === "" ? "1" : ret; - } - } - } - }, - - // Don't automatically add "px" to these possibly-unitless properties - cssNumber: { - "animationIterationCount": true, - "columnCount": true, - "fillOpacity": true, - "flexGrow": true, - "flexShrink": true, - "fontWeight": true, - "lineHeight": true, - "opacity": true, - "order": true, - "orphans": true, - "widows": true, - "zIndex": true, - "zoom": true - }, - - // Add in properties whose names you wish to fix before - // setting or getting the value - cssProps: { - "float": "cssFloat" - }, - - // Get and set the style property on a DOM Node - style: function( elem, name, value, extra ) { - - // Don't set styles on text and comment nodes - if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { - return; - } - - // Make sure that we're working with the right name - var ret, type, hooks, - origName = jQuery.camelCase( name ), - isCustomProp = rcustomProp.test( name ), - style = elem.style; - - // Make sure that we're working with the right name. We don't - // want to query the value if it is a CSS custom property - // since they are user-defined. - if ( !isCustomProp ) { - name = finalPropName( origName ); - } - - // Gets hook for the prefixed version, then unprefixed version - hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; - - // Check if we're setting a value - if ( value !== undefined ) { - type = typeof value; - - // Convert "+=" or "-=" to relative numbers (#7345) - if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) { - value = adjustCSS( elem, name, ret ); - - // Fixes bug #9237 - type = "number"; - } - - // Make sure that null and NaN values aren't set (#7116) - if ( value == null || value !== value ) { - return; - } - - // If a number was passed in, add the unit (except for certain CSS properties) - if ( type === "number" ) { - value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" ); - } - - // background-* props affect original clone's values - if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) { - style[ name ] = "inherit"; - } - - // If a hook was provided, use that value, otherwise just set the specified value - if ( !hooks || !( "set" in hooks ) || - ( value = hooks.set( elem, value, extra ) ) !== undefined ) { - - if ( isCustomProp ) { - style.setProperty( name, value ); - } else { - style[ name ] = value; - } - } - - } else { - - // If a hook was provided get the non-computed value from there - if ( hooks && "get" in hooks && - ( ret = hooks.get( elem, false, extra ) ) !== undefined ) { - - return ret; - } - - // Otherwise just get the value from the style object - return style[ name ]; - } - }, - - css: function( elem, name, extra, styles ) { - var val, num, hooks, - origName = jQuery.camelCase( name ), - isCustomProp = rcustomProp.test( name ); - - // Make sure that we're working with the right name. We don't - // want to modify the value if it is a CSS custom property - // since they are user-defined. - if ( !isCustomProp ) { - name = finalPropName( origName ); - } - - // Try prefixed name followed by the unprefixed name - hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; - - // If a hook was provided get the computed value from there - if ( hooks && "get" in hooks ) { - val = hooks.get( elem, true, extra ); - } - - // Otherwise, if a way to get the computed value exists, use that - if ( val === undefined ) { - val = curCSS( elem, name, styles ); - } - - // Convert "normal" to computed value - if ( val === "normal" && name in cssNormalTransform ) { - val = cssNormalTransform[ name ]; - } - - // Make numeric if forced or a qualifier was provided and val looks numeric - if ( extra === "" || extra ) { - num = parseFloat( val ); - return extra === true || isFinite( num ) ? num || 0 : val; - } - - return val; - } -} ); - -jQuery.each( [ "height", "width" ], function( i, name ) { - jQuery.cssHooks[ name ] = { - get: function( elem, computed, extra ) { - if ( computed ) { - - // Certain elements can have dimension info if we invisibly show them - // but it must have a current display style that would benefit - return rdisplayswap.test( jQuery.css( elem, "display" ) ) && - - // Support: Safari 8+ - // Table columns in Safari have non-zero offsetWidth & zero - // getBoundingClientRect().width unless display is changed. - // Support: IE <=11 only - // Running getBoundingClientRect on a disconnected node - // in IE throws an error. - ( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ? - swap( elem, cssShow, function() { - return getWidthOrHeight( elem, name, extra ); - } ) : - getWidthOrHeight( elem, name, extra ); - } - }, - - set: function( elem, value, extra ) { - var matches, - styles = extra && getStyles( elem ), - subtract = extra && augmentWidthOrHeight( - elem, - name, - extra, - jQuery.css( elem, "boxSizing", false, styles ) === "border-box", - styles - ); - - // Convert to pixels if value adjustment is needed - if ( subtract && ( matches = rcssNum.exec( value ) ) && - ( matches[ 3 ] || "px" ) !== "px" ) { - - elem.style[ name ] = value; - value = jQuery.css( elem, name ); - } - - return setPositiveNumber( elem, value, subtract ); - } - }; -} ); - -jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft, - function( elem, computed ) { - if ( computed ) { - return ( parseFloat( curCSS( elem, "marginLeft" ) ) || - elem.getBoundingClientRect().left - - swap( elem, { marginLeft: 0 }, function() { - return elem.getBoundingClientRect().left; - } ) - ) + "px"; - } - } -); - -// These hooks are used by animate to expand properties -jQuery.each( { - margin: "", - padding: "", - border: "Width" -}, function( prefix, suffix ) { - jQuery.cssHooks[ prefix + suffix ] = { - expand: function( value ) { - var i = 0, - expanded = {}, - - // Assumes a single number if not a string - parts = typeof value === "string" ? value.split( " " ) : [ value ]; - - for ( ; i < 4; i++ ) { - expanded[ prefix + cssExpand[ i ] + suffix ] = - parts[ i ] || parts[ i - 2 ] || parts[ 0 ]; - } - - return expanded; - } - }; - - if ( !rmargin.test( prefix ) ) { - jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber; - } -} ); - -jQuery.fn.extend( { - css: function( name, value ) { - return access( this, function( elem, name, value ) { - var styles, len, - map = {}, - i = 0; - - if ( Array.isArray( name ) ) { - styles = getStyles( elem ); - len = name.length; - - for ( ; i < len; i++ ) { - map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles ); - } - - return map; - } - - return value !== undefined ? - jQuery.style( elem, name, value ) : - jQuery.css( elem, name ); - }, name, value, arguments.length > 1 ); - } -} ); - - -function Tween( elem, options, prop, end, easing ) { - return new Tween.prototype.init( elem, options, prop, end, easing ); -} -jQuery.Tween = Tween; - -Tween.prototype = { - constructor: Tween, - init: function( elem, options, prop, end, easing, unit ) { - this.elem = elem; - this.prop = prop; - this.easing = easing || jQuery.easing._default; - this.options = options; - this.start = this.now = this.cur(); - this.end = end; - this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" ); - }, - cur: function() { - var hooks = Tween.propHooks[ this.prop ]; - - return hooks && hooks.get ? - hooks.get( this ) : - Tween.propHooks._default.get( this ); - }, - run: function( percent ) { - var eased, - hooks = Tween.propHooks[ this.prop ]; - - if ( this.options.duration ) { - this.pos = eased = jQuery.easing[ this.easing ]( - percent, this.options.duration * percent, 0, 1, this.options.duration - ); - } else { - this.pos = eased = percent; - } - this.now = ( this.end - this.start ) * eased + this.start; - - if ( this.options.step ) { - this.options.step.call( this.elem, this.now, this ); - } - - if ( hooks && hooks.set ) { - hooks.set( this ); - } else { - Tween.propHooks._default.set( this ); - } - return this; - } -}; - -Tween.prototype.init.prototype = Tween.prototype; - -Tween.propHooks = { - _default: { - get: function( tween ) { - var result; - - // Use a property on the element directly when it is not a DOM element, - // or when there is no matching style property that exists. - if ( tween.elem.nodeType !== 1 || - tween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) { - return tween.elem[ tween.prop ]; - } - - // Passing an empty string as a 3rd parameter to .css will automatically - // attempt a parseFloat and fallback to a string if the parse fails. - // Simple values such as "10px" are parsed to Float; - // complex values such as "rotate(1rad)" are returned as-is. - result = jQuery.css( tween.elem, tween.prop, "" ); - - // Empty strings, null, undefined and "auto" are converted to 0. - return !result || result === "auto" ? 0 : result; - }, - set: function( tween ) { - - // Use step hook for back compat. - // Use cssHook if its there. - // Use .style if available and use plain properties where available. - if ( jQuery.fx.step[ tween.prop ] ) { - jQuery.fx.step[ tween.prop ]( tween ); - } else if ( tween.elem.nodeType === 1 && - ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || - jQuery.cssHooks[ tween.prop ] ) ) { - jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); - } else { - tween.elem[ tween.prop ] = tween.now; - } - } - } -}; - -// Support: IE <=9 only -// Panic based approach to setting things on disconnected nodes -Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = { - set: function( tween ) { - if ( tween.elem.nodeType && tween.elem.parentNode ) { - tween.elem[ tween.prop ] = tween.now; - } - } -}; - -jQuery.easing = { - linear: function( p ) { - return p; - }, - swing: function( p ) { - return 0.5 - Math.cos( p * Math.PI ) / 2; - }, - _default: "swing" -}; - -jQuery.fx = Tween.prototype.init; - -// Back compat <1.8 extension point -jQuery.fx.step = {}; - - - - -var - fxNow, inProgress, - rfxtypes = /^(?:toggle|show|hide)$/, - rrun = /queueHooks$/; - -function schedule() { - if ( inProgress ) { - if ( document.hidden === false && window.requestAnimationFrame ) { - window.requestAnimationFrame( schedule ); - } else { - window.setTimeout( schedule, jQuery.fx.interval ); - } - - jQuery.fx.tick(); - } -} - -// Animations created synchronously will run synchronously -function createFxNow() { - window.setTimeout( function() { - fxNow = undefined; - } ); - return ( fxNow = jQuery.now() ); -} - -// Generate parameters to create a standard animation -function genFx( type, includeWidth ) { - var which, - i = 0, - attrs = { height: type }; - - // If we include width, step value is 1 to do all cssExpand values, - // otherwise step value is 2 to skip over Left and Right - includeWidth = includeWidth ? 1 : 0; - for ( ; i < 4; i += 2 - includeWidth ) { - which = cssExpand[ i ]; - attrs[ "margin" + which ] = attrs[ "padding" + which ] = type; - } - - if ( includeWidth ) { - attrs.opacity = attrs.width = type; - } - - return attrs; -} - -function createTween( value, prop, animation ) { - var tween, - collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ "*" ] ), - index = 0, - length = collection.length; - for ( ; index < length; index++ ) { - if ( ( tween = collection[ index ].call( animation, prop, value ) ) ) { - - // We're done with this property - return tween; - } - } -} - -function defaultPrefilter( elem, props, opts ) { - var prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display, - isBox = "width" in props || "height" in props, - anim = this, - orig = {}, - style = elem.style, - hidden = elem.nodeType && isHiddenWithinTree( elem ), - dataShow = dataPriv.get( elem, "fxshow" ); - - // Queue-skipping animations hijack the fx hooks - if ( !opts.queue ) { - hooks = jQuery._queueHooks( elem, "fx" ); - if ( hooks.unqueued == null ) { - hooks.unqueued = 0; - oldfire = hooks.empty.fire; - hooks.empty.fire = function() { - if ( !hooks.unqueued ) { - oldfire(); - } - }; - } - hooks.unqueued++; - - anim.always( function() { - - // Ensure the complete handler is called before this completes - anim.always( function() { - hooks.unqueued--; - if ( !jQuery.queue( elem, "fx" ).length ) { - hooks.empty.fire(); - } - } ); - } ); - } - - // Detect show/hide animations - for ( prop in props ) { - value = props[ prop ]; - if ( rfxtypes.test( value ) ) { - delete props[ prop ]; - toggle = toggle || value === "toggle"; - if ( value === ( hidden ? "hide" : "show" ) ) { - - // Pretend to be hidden if this is a "show" and - // there is still data from a stopped show/hide - if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) { - hidden = true; - - // Ignore all other no-op show/hide data - } else { - continue; - } - } - orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop ); - } - } - - // Bail out if this is a no-op like .hide().hide() - propTween = !jQuery.isEmptyObject( props ); - if ( !propTween && jQuery.isEmptyObject( orig ) ) { - return; - } - - // Restrict "overflow" and "display" styles during box animations - if ( isBox && elem.nodeType === 1 ) { - - // Support: IE <=9 - 11, Edge 12 - 13 - // Record all 3 overflow attributes because IE does not infer the shorthand - // from identically-valued overflowX and overflowY - opts.overflow = [ style.overflow, style.overflowX, style.overflowY ]; - - // Identify a display type, preferring old show/hide data over the CSS cascade - restoreDisplay = dataShow && dataShow.display; - if ( restoreDisplay == null ) { - restoreDisplay = dataPriv.get( elem, "display" ); - } - display = jQuery.css( elem, "display" ); - if ( display === "none" ) { - if ( restoreDisplay ) { - display = restoreDisplay; - } else { - - // Get nonempty value(s) by temporarily forcing visibility - showHide( [ elem ], true ); - restoreDisplay = elem.style.display || restoreDisplay; - display = jQuery.css( elem, "display" ); - showHide( [ elem ] ); - } - } - - // Animate inline elements as inline-block - if ( display === "inline" || display === "inline-block" && restoreDisplay != null ) { - if ( jQuery.css( elem, "float" ) === "none" ) { - - // Restore the original display value at the end of pure show/hide animations - if ( !propTween ) { - anim.done( function() { - style.display = restoreDisplay; - } ); - if ( restoreDisplay == null ) { - display = style.display; - restoreDisplay = display === "none" ? "" : display; - } - } - style.display = "inline-block"; - } - } - } - - if ( opts.overflow ) { - style.overflow = "hidden"; - anim.always( function() { - style.overflow = opts.overflow[ 0 ]; - style.overflowX = opts.overflow[ 1 ]; - style.overflowY = opts.overflow[ 2 ]; - } ); - } - - // Implement show/hide animations - propTween = false; - for ( prop in orig ) { - - // General show/hide setup for this element animation - if ( !propTween ) { - if ( dataShow ) { - if ( "hidden" in dataShow ) { - hidden = dataShow.hidden; - } - } else { - dataShow = dataPriv.access( elem, "fxshow", { display: restoreDisplay } ); - } - - // Store hidden/visible for toggle so `.stop().toggle()` "reverses" - if ( toggle ) { - dataShow.hidden = !hidden; - } - - // Show elements before animating them - if ( hidden ) { - showHide( [ elem ], true ); - } - - /* eslint-disable no-loop-func */ - - anim.done( function() { - - /* eslint-enable no-loop-func */ - - // The final step of a "hide" animation is actually hiding the element - if ( !hidden ) { - showHide( [ elem ] ); - } - dataPriv.remove( elem, "fxshow" ); - for ( prop in orig ) { - jQuery.style( elem, prop, orig[ prop ] ); - } - } ); - } - - // Per-property setup - propTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim ); - if ( !( prop in dataShow ) ) { - dataShow[ prop ] = propTween.start; - if ( hidden ) { - propTween.end = propTween.start; - propTween.start = 0; - } - } - } -} - -function propFilter( props, specialEasing ) { - var index, name, easing, value, hooks; - - // camelCase, specialEasing and expand cssHook pass - for ( index in props ) { - name = jQuery.camelCase( index ); - easing = specialEasing[ name ]; - value = props[ index ]; - if ( Array.isArray( value ) ) { - easing = value[ 1 ]; - value = props[ index ] = value[ 0 ]; - } - - if ( index !== name ) { - props[ name ] = value; - delete props[ index ]; - } - - hooks = jQuery.cssHooks[ name ]; - if ( hooks && "expand" in hooks ) { - value = hooks.expand( value ); - delete props[ name ]; - - // Not quite $.extend, this won't overwrite existing keys. - // Reusing 'index' because we have the correct "name" - for ( index in value ) { - if ( !( index in props ) ) { - props[ index ] = value[ index ]; - specialEasing[ index ] = easing; - } - } - } else { - specialEasing[ name ] = easing; - } - } -} - -function Animation( elem, properties, options ) { - var result, - stopped, - index = 0, - length = Animation.prefilters.length, - deferred = jQuery.Deferred().always( function() { - - // Don't match elem in the :animated selector - delete tick.elem; - } ), - tick = function() { - if ( stopped ) { - return false; - } - var currentTime = fxNow || createFxNow(), - remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ), - - // Support: Android 2.3 only - // Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497) - temp = remaining / animation.duration || 0, - percent = 1 - temp, - index = 0, - length = animation.tweens.length; - - for ( ; index < length; index++ ) { - animation.tweens[ index ].run( percent ); - } - - deferred.notifyWith( elem, [ animation, percent, remaining ] ); - - // If there's more to do, yield - if ( percent < 1 && length ) { - return remaining; - } - - // If this was an empty animation, synthesize a final progress notification - if ( !length ) { - deferred.notifyWith( elem, [ animation, 1, 0 ] ); - } - - // Resolve the animation and report its conclusion - deferred.resolveWith( elem, [ animation ] ); - return false; - }, - animation = deferred.promise( { - elem: elem, - props: jQuery.extend( {}, properties ), - opts: jQuery.extend( true, { - specialEasing: {}, - easing: jQuery.easing._default - }, options ), - originalProperties: properties, - originalOptions: options, - startTime: fxNow || createFxNow(), - duration: options.duration, - tweens: [], - createTween: function( prop, end ) { - var tween = jQuery.Tween( elem, animation.opts, prop, end, - animation.opts.specialEasing[ prop ] || animation.opts.easing ); - animation.tweens.push( tween ); - return tween; - }, - stop: function( gotoEnd ) { - var index = 0, - - // If we are going to the end, we want to run all the tweens - // otherwise we skip this part - length = gotoEnd ? animation.tweens.length : 0; - if ( stopped ) { - return this; - } - stopped = true; - for ( ; index < length; index++ ) { - animation.tweens[ index ].run( 1 ); - } - - // Resolve when we played the last frame; otherwise, reject - if ( gotoEnd ) { - deferred.notifyWith( elem, [ animation, 1, 0 ] ); - deferred.resolveWith( elem, [ animation, gotoEnd ] ); - } else { - deferred.rejectWith( elem, [ animation, gotoEnd ] ); - } - return this; - } - } ), - props = animation.props; - - propFilter( props, animation.opts.specialEasing ); - - for ( ; index < length; index++ ) { - result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts ); - if ( result ) { - if ( jQuery.isFunction( result.stop ) ) { - jQuery._queueHooks( animation.elem, animation.opts.queue ).stop = - jQuery.proxy( result.stop, result ); - } - return result; - } - } - - jQuery.map( props, createTween, animation ); - - if ( jQuery.isFunction( animation.opts.start ) ) { - animation.opts.start.call( elem, animation ); - } - - // Attach callbacks from options - animation - .progress( animation.opts.progress ) - .done( animation.opts.done, animation.opts.complete ) - .fail( animation.opts.fail ) - .always( animation.opts.always ); - - jQuery.fx.timer( - jQuery.extend( tick, { - elem: elem, - anim: animation, - queue: animation.opts.queue - } ) - ); - - return animation; -} - -jQuery.Animation = jQuery.extend( Animation, { - - tweeners: { - "*": [ function( prop, value ) { - var tween = this.createTween( prop, value ); - adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween ); - return tween; - } ] - }, - - tweener: function( props, callback ) { - if ( jQuery.isFunction( props ) ) { - callback = props; - props = [ "*" ]; - } else { - props = props.match( rnothtmlwhite ); - } - - var prop, - index = 0, - length = props.length; - - for ( ; index < length; index++ ) { - prop = props[ index ]; - Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || []; - Animation.tweeners[ prop ].unshift( callback ); - } - }, - - prefilters: [ defaultPrefilter ], - - prefilter: function( callback, prepend ) { - if ( prepend ) { - Animation.prefilters.unshift( callback ); - } else { - Animation.prefilters.push( callback ); - } - } -} ); - -jQuery.speed = function( speed, easing, fn ) { - var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : { - complete: fn || !fn && easing || - jQuery.isFunction( speed ) && speed, - duration: speed, - easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing - }; - - // Go to the end state if fx are off - if ( jQuery.fx.off ) { - opt.duration = 0; - - } else { - if ( typeof opt.duration !== "number" ) { - if ( opt.duration in jQuery.fx.speeds ) { - opt.duration = jQuery.fx.speeds[ opt.duration ]; - - } else { - opt.duration = jQuery.fx.speeds._default; - } - } - } - - // Normalize opt.queue - true/undefined/null -> "fx" - if ( opt.queue == null || opt.queue === true ) { - opt.queue = "fx"; - } - - // Queueing - opt.old = opt.complete; - - opt.complete = function() { - if ( jQuery.isFunction( opt.old ) ) { - opt.old.call( this ); - } - - if ( opt.queue ) { - jQuery.dequeue( this, opt.queue ); - } - }; - - return opt; -}; - -jQuery.fn.extend( { - fadeTo: function( speed, to, easing, callback ) { - - // Show any hidden elements after setting opacity to 0 - return this.filter( isHiddenWithinTree ).css( "opacity", 0 ).show() - - // Animate to the value specified - .end().animate( { opacity: to }, speed, easing, callback ); - }, - animate: function( prop, speed, easing, callback ) { - var empty = jQuery.isEmptyObject( prop ), - optall = jQuery.speed( speed, easing, callback ), - doAnimation = function() { - - // Operate on a copy of prop so per-property easing won't be lost - var anim = Animation( this, jQuery.extend( {}, prop ), optall ); - - // Empty animations, or finishing resolves immediately - if ( empty || dataPriv.get( this, "finish" ) ) { - anim.stop( true ); - } - }; - doAnimation.finish = doAnimation; - - return empty || optall.queue === false ? - this.each( doAnimation ) : - this.queue( optall.queue, doAnimation ); - }, - stop: function( type, clearQueue, gotoEnd ) { - var stopQueue = function( hooks ) { - var stop = hooks.stop; - delete hooks.stop; - stop( gotoEnd ); - }; - - if ( typeof type !== "string" ) { - gotoEnd = clearQueue; - clearQueue = type; - type = undefined; - } - if ( clearQueue && type !== false ) { - this.queue( type || "fx", [] ); - } - - return this.each( function() { - var dequeue = true, - index = type != null && type + "queueHooks", - timers = jQuery.timers, - data = dataPriv.get( this ); - - if ( index ) { - if ( data[ index ] && data[ index ].stop ) { - stopQueue( data[ index ] ); - } - } else { - for ( index in data ) { - if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) { - stopQueue( data[ index ] ); - } - } - } - - for ( index = timers.length; index--; ) { - if ( timers[ index ].elem === this && - ( type == null || timers[ index ].queue === type ) ) { - - timers[ index ].anim.stop( gotoEnd ); - dequeue = false; - timers.splice( index, 1 ); - } - } - - // Start the next in the queue if the last step wasn't forced. - // Timers currently will call their complete callbacks, which - // will dequeue but only if they were gotoEnd. - if ( dequeue || !gotoEnd ) { - jQuery.dequeue( this, type ); - } - } ); - }, - finish: function( type ) { - if ( type !== false ) { - type = type || "fx"; - } - return this.each( function() { - var index, - data = dataPriv.get( this ), - queue = data[ type + "queue" ], - hooks = data[ type + "queueHooks" ], - timers = jQuery.timers, - length = queue ? queue.length : 0; - - // Enable finishing flag on private data - data.finish = true; - - // Empty the queue first - jQuery.queue( this, type, [] ); - - if ( hooks && hooks.stop ) { - hooks.stop.call( this, true ); - } - - // Look for any active animations, and finish them - for ( index = timers.length; index--; ) { - if ( timers[ index ].elem === this && timers[ index ].queue === type ) { - timers[ index ].anim.stop( true ); - timers.splice( index, 1 ); - } - } - - // Look for any animations in the old queue and finish them - for ( index = 0; index < length; index++ ) { - if ( queue[ index ] && queue[ index ].finish ) { - queue[ index ].finish.call( this ); - } - } - - // Turn off finishing flag - delete data.finish; - } ); - } -} ); - -jQuery.each( [ "toggle", "show", "hide" ], function( i, name ) { - var cssFn = jQuery.fn[ name ]; - jQuery.fn[ name ] = function( speed, easing, callback ) { - return speed == null || typeof speed === "boolean" ? - cssFn.apply( this, arguments ) : - this.animate( genFx( name, true ), speed, easing, callback ); - }; -} ); - -// Generate shortcuts for custom animations -jQuery.each( { - slideDown: genFx( "show" ), - slideUp: genFx( "hide" ), - slideToggle: genFx( "toggle" ), - fadeIn: { opacity: "show" }, - fadeOut: { opacity: "hide" }, - fadeToggle: { opacity: "toggle" } -}, function( name, props ) { - jQuery.fn[ name ] = function( speed, easing, callback ) { - return this.animate( props, speed, easing, callback ); - }; -} ); - -jQuery.timers = []; -jQuery.fx.tick = function() { - var timer, - i = 0, - timers = jQuery.timers; - - fxNow = jQuery.now(); - - for ( ; i < timers.length; i++ ) { - timer = timers[ i ]; - - // Run the timer and safely remove it when done (allowing for external removal) - if ( !timer() && timers[ i ] === timer ) { - timers.splice( i--, 1 ); - } - } - - if ( !timers.length ) { - jQuery.fx.stop(); - } - fxNow = undefined; -}; - -jQuery.fx.timer = function( timer ) { - jQuery.timers.push( timer ); - jQuery.fx.start(); -}; - -jQuery.fx.interval = 13; -jQuery.fx.start = function() { - if ( inProgress ) { - return; - } - - inProgress = true; - schedule(); -}; - -jQuery.fx.stop = function() { - inProgress = null; -}; - -jQuery.fx.speeds = { - slow: 600, - fast: 200, - - // Default speed - _default: 400 -}; - - -// Based off of the plugin by Clint Helfers, with permission. -// https://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/ -jQuery.fn.delay = function( time, type ) { - time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; - type = type || "fx"; - - return this.queue( type, function( next, hooks ) { - var timeout = window.setTimeout( next, time ); - hooks.stop = function() { - window.clearTimeout( timeout ); - }; - } ); -}; - - -( function() { - var input = document.createElement( "input" ), - select = document.createElement( "select" ), - opt = select.appendChild( document.createElement( "option" ) ); - - input.type = "checkbox"; - - // Support: Android <=4.3 only - // Default value for a checkbox should be "on" - support.checkOn = input.value !== ""; - - // Support: IE <=11 only - // Must access selectedIndex to make default options select - support.optSelected = opt.selected; - - // Support: IE <=11 only - // An input loses its value after becoming a radio - input = document.createElement( "input" ); - input.value = "t"; - input.type = "radio"; - support.radioValue = input.value === "t"; -} )(); - - -var boolHook, - attrHandle = jQuery.expr.attrHandle; - -jQuery.fn.extend( { - attr: function( name, value ) { - return access( this, jQuery.attr, name, value, arguments.length > 1 ); - }, - - removeAttr: function( name ) { - return this.each( function() { - jQuery.removeAttr( this, name ); - } ); - } -} ); - -jQuery.extend( { - attr: function( elem, name, value ) { - var ret, hooks, - nType = elem.nodeType; - - // Don't get/set attributes on text, comment and attribute nodes - if ( nType === 3 || nType === 8 || nType === 2 ) { - return; - } - - // Fallback to prop when attributes are not supported - if ( typeof elem.getAttribute === "undefined" ) { - return jQuery.prop( elem, name, value ); - } - - // Attribute hooks are determined by the lowercase version - // Grab necessary hook if one is defined - if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { - hooks = jQuery.attrHooks[ name.toLowerCase() ] || - ( jQuery.expr.match.bool.test( name ) ? boolHook : undefined ); - } - - if ( value !== undefined ) { - if ( value === null ) { - jQuery.removeAttr( elem, name ); - return; - } - - if ( hooks && "set" in hooks && - ( ret = hooks.set( elem, value, name ) ) !== undefined ) { - return ret; - } - - elem.setAttribute( name, value + "" ); - return value; - } - - if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { - return ret; - } - - ret = jQuery.find.attr( elem, name ); - - // Non-existent attributes return null, we normalize to undefined - return ret == null ? undefined : ret; - }, - - attrHooks: { - type: { - set: function( elem, value ) { - if ( !support.radioValue && value === "radio" && - nodeName( elem, "input" ) ) { - var val = elem.value; - elem.setAttribute( "type", value ); - if ( val ) { - elem.value = val; - } - return value; - } - } - } - }, - - removeAttr: function( elem, value ) { - var name, - i = 0, - - // Attribute names can contain non-HTML whitespace characters - // https://html.spec.whatwg.org/multipage/syntax.html#attributes-2 - attrNames = value && value.match( rnothtmlwhite ); - - if ( attrNames && elem.nodeType === 1 ) { - while ( ( name = attrNames[ i++ ] ) ) { - elem.removeAttribute( name ); - } - } - } -} ); - -// Hooks for boolean attributes -boolHook = { - set: function( elem, value, name ) { - if ( value === false ) { - - // Remove boolean attributes when set to false - jQuery.removeAttr( elem, name ); - } else { - elem.setAttribute( name, name ); - } - return name; - } -}; - -jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( i, name ) { - var getter = attrHandle[ name ] || jQuery.find.attr; - - attrHandle[ name ] = function( elem, name, isXML ) { - var ret, handle, - lowercaseName = name.toLowerCase(); - - if ( !isXML ) { - - // Avoid an infinite loop by temporarily removing this function from the getter - handle = attrHandle[ lowercaseName ]; - attrHandle[ lowercaseName ] = ret; - ret = getter( elem, name, isXML ) != null ? - lowercaseName : - null; - attrHandle[ lowercaseName ] = handle; - } - return ret; - }; -} ); - - - - -var rfocusable = /^(?:input|select|textarea|button)$/i, - rclickable = /^(?:a|area)$/i; - -jQuery.fn.extend( { - prop: function( name, value ) { - return access( this, jQuery.prop, name, value, arguments.length > 1 ); - }, - - removeProp: function( name ) { - return this.each( function() { - delete this[ jQuery.propFix[ name ] || name ]; - } ); - } -} ); - -jQuery.extend( { - prop: function( elem, name, value ) { - var ret, hooks, - nType = elem.nodeType; - - // Don't get/set properties on text, comment and attribute nodes - if ( nType === 3 || nType === 8 || nType === 2 ) { - return; - } - - if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { - - // Fix name and attach hooks - name = jQuery.propFix[ name ] || name; - hooks = jQuery.propHooks[ name ]; - } - - if ( value !== undefined ) { - if ( hooks && "set" in hooks && - ( ret = hooks.set( elem, value, name ) ) !== undefined ) { - return ret; - } - - return ( elem[ name ] = value ); - } - - if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { - return ret; - } - - return elem[ name ]; - }, - - propHooks: { - tabIndex: { - get: function( elem ) { - - // Support: IE <=9 - 11 only - // elem.tabIndex doesn't always return the - // correct value when it hasn't been explicitly set - // https://web.archive.org/web/20141116233347/http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ - // Use proper attribute retrieval(#12072) - var tabindex = jQuery.find.attr( elem, "tabindex" ); - - if ( tabindex ) { - return parseInt( tabindex, 10 ); - } - - if ( - rfocusable.test( elem.nodeName ) || - rclickable.test( elem.nodeName ) && - elem.href - ) { - return 0; - } - - return -1; - } - } - }, - - propFix: { - "for": "htmlFor", - "class": "className" - } -} ); - -// Support: IE <=11 only -// Accessing the selectedIndex property -// forces the browser to respect setting selected -// on the option -// The getter ensures a default option is selected -// when in an optgroup -// eslint rule "no-unused-expressions" is disabled for this code -// since it considers such accessions noop -if ( !support.optSelected ) { - jQuery.propHooks.selected = { - get: function( elem ) { - - /* eslint no-unused-expressions: "off" */ - - var parent = elem.parentNode; - if ( parent && parent.parentNode ) { - parent.parentNode.selectedIndex; - } - return null; - }, - set: function( elem ) { - - /* eslint no-unused-expressions: "off" */ - - var parent = elem.parentNode; - if ( parent ) { - parent.selectedIndex; - - if ( parent.parentNode ) { - parent.parentNode.selectedIndex; - } - } - } - }; -} - -jQuery.each( [ - "tabIndex", - "readOnly", - "maxLength", - "cellSpacing", - "cellPadding", - "rowSpan", - "colSpan", - "useMap", - "frameBorder", - "contentEditable" -], function() { - jQuery.propFix[ this.toLowerCase() ] = this; -} ); - - - - - // Strip and collapse whitespace according to HTML spec - // https://html.spec.whatwg.org/multipage/infrastructure.html#strip-and-collapse-whitespace - function stripAndCollapse( value ) { - var tokens = value.match( rnothtmlwhite ) || []; - return tokens.join( " " ); - } - - -function getClass( elem ) { - return elem.getAttribute && elem.getAttribute( "class" ) || ""; -} - -jQuery.fn.extend( { - addClass: function( value ) { - var classes, elem, cur, curValue, clazz, j, finalValue, - i = 0; - - if ( jQuery.isFunction( value ) ) { - return this.each( function( j ) { - jQuery( this ).addClass( value.call( this, j, getClass( this ) ) ); - } ); - } - - if ( typeof value === "string" && value ) { - classes = value.match( rnothtmlwhite ) || []; - - while ( ( elem = this[ i++ ] ) ) { - curValue = getClass( elem ); - cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); - - if ( cur ) { - j = 0; - while ( ( clazz = classes[ j++ ] ) ) { - if ( cur.indexOf( " " + clazz + " " ) < 0 ) { - cur += clazz + " "; - } - } - - // Only assign if different to avoid unneeded rendering. - finalValue = stripAndCollapse( cur ); - if ( curValue !== finalValue ) { - elem.setAttribute( "class", finalValue ); - } - } - } - } - - return this; - }, - - removeClass: function( value ) { - var classes, elem, cur, curValue, clazz, j, finalValue, - i = 0; - - if ( jQuery.isFunction( value ) ) { - return this.each( function( j ) { - jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) ); - } ); - } - - if ( !arguments.length ) { - return this.attr( "class", "" ); - } - - if ( typeof value === "string" && value ) { - classes = value.match( rnothtmlwhite ) || []; - - while ( ( elem = this[ i++ ] ) ) { - curValue = getClass( elem ); - - // This expression is here for better compressibility (see addClass) - cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); - - if ( cur ) { - j = 0; - while ( ( clazz = classes[ j++ ] ) ) { - - // Remove *all* instances - while ( cur.indexOf( " " + clazz + " " ) > -1 ) { - cur = cur.replace( " " + clazz + " ", " " ); - } - } - - // Only assign if different to avoid unneeded rendering. - finalValue = stripAndCollapse( cur ); - if ( curValue !== finalValue ) { - elem.setAttribute( "class", finalValue ); - } - } - } - } - - return this; - }, - - toggleClass: function( value, stateVal ) { - var type = typeof value; - - if ( typeof stateVal === "boolean" && type === "string" ) { - return stateVal ? this.addClass( value ) : this.removeClass( value ); - } - - if ( jQuery.isFunction( value ) ) { - return this.each( function( i ) { - jQuery( this ).toggleClass( - value.call( this, i, getClass( this ), stateVal ), - stateVal - ); - } ); - } - - return this.each( function() { - var className, i, self, classNames; - - if ( type === "string" ) { - - // Toggle individual class names - i = 0; - self = jQuery( this ); - classNames = value.match( rnothtmlwhite ) || []; - - while ( ( className = classNames[ i++ ] ) ) { - - // Check each className given, space separated list - if ( self.hasClass( className ) ) { - self.removeClass( className ); - } else { - self.addClass( className ); - } - } - - // Toggle whole class name - } else if ( value === undefined || type === "boolean" ) { - className = getClass( this ); - if ( className ) { - - // Store className if set - dataPriv.set( this, "__className__", className ); - } - - // If the element has a class name or if we're passed `false`, - // then remove the whole classname (if there was one, the above saved it). - // Otherwise bring back whatever was previously saved (if anything), - // falling back to the empty string if nothing was stored. - if ( this.setAttribute ) { - this.setAttribute( "class", - className || value === false ? - "" : - dataPriv.get( this, "__className__" ) || "" - ); - } - } - } ); - }, - - hasClass: function( selector ) { - var className, elem, - i = 0; - - className = " " + selector + " "; - while ( ( elem = this[ i++ ] ) ) { - if ( elem.nodeType === 1 && - ( " " + stripAndCollapse( getClass( elem ) ) + " " ).indexOf( className ) > -1 ) { - return true; - } - } - - return false; - } -} ); - - - - -var rreturn = /\r/g; - -jQuery.fn.extend( { - val: function( value ) { - var hooks, ret, isFunction, - elem = this[ 0 ]; - - if ( !arguments.length ) { - if ( elem ) { - hooks = jQuery.valHooks[ elem.type ] || - jQuery.valHooks[ elem.nodeName.toLowerCase() ]; - - if ( hooks && - "get" in hooks && - ( ret = hooks.get( elem, "value" ) ) !== undefined - ) { - return ret; - } - - ret = elem.value; - - // Handle most common string cases - if ( typeof ret === "string" ) { - return ret.replace( rreturn, "" ); - } - - // Handle cases where value is null/undef or number - return ret == null ? "" : ret; - } - - return; - } - - isFunction = jQuery.isFunction( value ); - - return this.each( function( i ) { - var val; - - if ( this.nodeType !== 1 ) { - return; - } - - if ( isFunction ) { - val = value.call( this, i, jQuery( this ).val() ); - } else { - val = value; - } - - // Treat null/undefined as ""; convert numbers to string - if ( val == null ) { - val = ""; - - } else if ( typeof val === "number" ) { - val += ""; - - } else if ( Array.isArray( val ) ) { - val = jQuery.map( val, function( value ) { - return value == null ? "" : value + ""; - } ); - } - - hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; - - // If set returns undefined, fall back to normal setting - if ( !hooks || !( "set" in hooks ) || hooks.set( this, val, "value" ) === undefined ) { - this.value = val; - } - } ); - } -} ); - -jQuery.extend( { - valHooks: { - option: { - get: function( elem ) { - - var val = jQuery.find.attr( elem, "value" ); - return val != null ? - val : - - // Support: IE <=10 - 11 only - // option.text throws exceptions (#14686, #14858) - // Strip and collapse whitespace - // https://html.spec.whatwg.org/#strip-and-collapse-whitespace - stripAndCollapse( jQuery.text( elem ) ); - } - }, - select: { - get: function( elem ) { - var value, option, i, - options = elem.options, - index = elem.selectedIndex, - one = elem.type === "select-one", - values = one ? null : [], - max = one ? index + 1 : options.length; - - if ( index < 0 ) { - i = max; - - } else { - i = one ? index : 0; - } - - // Loop through all the selected options - for ( ; i < max; i++ ) { - option = options[ i ]; - - // Support: IE <=9 only - // IE8-9 doesn't update selected after form reset (#2551) - if ( ( option.selected || i === index ) && - - // Don't return options that are disabled or in a disabled optgroup - !option.disabled && - ( !option.parentNode.disabled || - !nodeName( option.parentNode, "optgroup" ) ) ) { - - // Get the specific value for the option - value = jQuery( option ).val(); - - // We don't need an array for one selects - if ( one ) { - return value; - } - - // Multi-Selects return an array - values.push( value ); - } - } - - return values; - }, - - set: function( elem, value ) { - var optionSet, option, - options = elem.options, - values = jQuery.makeArray( value ), - i = options.length; - - while ( i-- ) { - option = options[ i ]; - - /* eslint-disable no-cond-assign */ - - if ( option.selected = - jQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1 - ) { - optionSet = true; - } - - /* eslint-enable no-cond-assign */ - } - - // Force browsers to behave consistently when non-matching value is set - if ( !optionSet ) { - elem.selectedIndex = -1; - } - return values; - } - } - } -} ); - -// Radios and checkboxes getter/setter -jQuery.each( [ "radio", "checkbox" ], function() { - jQuery.valHooks[ this ] = { - set: function( elem, value ) { - if ( Array.isArray( value ) ) { - return ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 ); - } - } - }; - if ( !support.checkOn ) { - jQuery.valHooks[ this ].get = function( elem ) { - return elem.getAttribute( "value" ) === null ? "on" : elem.value; - }; - } -} ); - - - - -// Return jQuery for attributes-only inclusion - - -var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/; - -jQuery.extend( jQuery.event, { - - trigger: function( event, data, elem, onlyHandlers ) { - - var i, cur, tmp, bubbleType, ontype, handle, special, - eventPath = [ elem || document ], - type = hasOwn.call( event, "type" ) ? event.type : event, - namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : []; - - cur = tmp = elem = elem || document; - - // Don't do events on text and comment nodes - if ( elem.nodeType === 3 || elem.nodeType === 8 ) { - return; - } - - // focus/blur morphs to focusin/out; ensure we're not firing them right now - if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { - return; - } - - if ( type.indexOf( "." ) > -1 ) { - - // Namespaced trigger; create a regexp to match event type in handle() - namespaces = type.split( "." ); - type = namespaces.shift(); - namespaces.sort(); - } - ontype = type.indexOf( ":" ) < 0 && "on" + type; - - // Caller can pass in a jQuery.Event object, Object, or just an event type string - event = event[ jQuery.expando ] ? - event : - new jQuery.Event( type, typeof event === "object" && event ); - - // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) - event.isTrigger = onlyHandlers ? 2 : 3; - event.namespace = namespaces.join( "." ); - event.rnamespace = event.namespace ? - new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) : - null; - - // Clean up the event in case it is being reused - event.result = undefined; - if ( !event.target ) { - event.target = elem; - } - - // Clone any incoming data and prepend the event, creating the handler arg list - data = data == null ? - [ event ] : - jQuery.makeArray( data, [ event ] ); - - // Allow special events to draw outside the lines - special = jQuery.event.special[ type ] || {}; - if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { - return; - } - - // Determine event propagation path in advance, per W3C events spec (#9951) - // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) - if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { - - bubbleType = special.delegateType || type; - if ( !rfocusMorph.test( bubbleType + type ) ) { - cur = cur.parentNode; - } - for ( ; cur; cur = cur.parentNode ) { - eventPath.push( cur ); - tmp = cur; - } - - // Only add window if we got to document (e.g., not plain obj or detached DOM) - if ( tmp === ( elem.ownerDocument || document ) ) { - eventPath.push( tmp.defaultView || tmp.parentWindow || window ); - } - } - - // Fire handlers on the event path - i = 0; - while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) { - - event.type = i > 1 ? - bubbleType : - special.bindType || type; - - // jQuery handler - handle = ( dataPriv.get( cur, "events" ) || {} )[ event.type ] && - dataPriv.get( cur, "handle" ); - if ( handle ) { - handle.apply( cur, data ); - } - - // Native handler - handle = ontype && cur[ ontype ]; - if ( handle && handle.apply && acceptData( cur ) ) { - event.result = handle.apply( cur, data ); - if ( event.result === false ) { - event.preventDefault(); - } - } - } - event.type = type; - - // If nobody prevented the default action, do it now - if ( !onlyHandlers && !event.isDefaultPrevented() ) { - - if ( ( !special._default || - special._default.apply( eventPath.pop(), data ) === false ) && - acceptData( elem ) ) { - - // Call a native DOM method on the target with the same name as the event. - // Don't do default actions on window, that's where global variables be (#6170) - if ( ontype && jQuery.isFunction( elem[ type ] ) && !jQuery.isWindow( elem ) ) { - - // Don't re-trigger an onFOO event when we call its FOO() method - tmp = elem[ ontype ]; - - if ( tmp ) { - elem[ ontype ] = null; - } - - // Prevent re-triggering of the same event, since we already bubbled it above - jQuery.event.triggered = type; - elem[ type ](); - jQuery.event.triggered = undefined; - - if ( tmp ) { - elem[ ontype ] = tmp; - } - } - } - } - - return event.result; - }, - - // Piggyback on a donor event to simulate a different one - // Used only for `focus(in | out)` events - simulate: function( type, elem, event ) { - var e = jQuery.extend( - new jQuery.Event(), - event, - { - type: type, - isSimulated: true - } - ); - - jQuery.event.trigger( e, null, elem ); - } - -} ); - -jQuery.fn.extend( { - - trigger: function( type, data ) { - return this.each( function() { - jQuery.event.trigger( type, data, this ); - } ); - }, - triggerHandler: function( type, data ) { - var elem = this[ 0 ]; - if ( elem ) { - return jQuery.event.trigger( type, data, elem, true ); - } - } -} ); - - -jQuery.each( ( "blur focus focusin focusout resize scroll click dblclick " + - "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + - "change select submit keydown keypress keyup contextmenu" ).split( " " ), - function( i, name ) { - - // Handle event binding - jQuery.fn[ name ] = function( data, fn ) { - return arguments.length > 0 ? - this.on( name, null, data, fn ) : - this.trigger( name ); - }; -} ); - -jQuery.fn.extend( { - hover: function( fnOver, fnOut ) { - return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); - } -} ); - - - - -support.focusin = "onfocusin" in window; - - -// Support: Firefox <=44 -// Firefox doesn't have focus(in | out) events -// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787 -// -// Support: Chrome <=48 - 49, Safari <=9.0 - 9.1 -// focus(in | out) events fire after focus & blur events, -// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order -// Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857 -if ( !support.focusin ) { - jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) { - - // Attach a single capturing handler on the document while someone wants focusin/focusout - var handler = function( event ) { - jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) ); - }; - - jQuery.event.special[ fix ] = { - setup: function() { - var doc = this.ownerDocument || this, - attaches = dataPriv.access( doc, fix ); - - if ( !attaches ) { - doc.addEventListener( orig, handler, true ); - } - dataPriv.access( doc, fix, ( attaches || 0 ) + 1 ); - }, - teardown: function() { - var doc = this.ownerDocument || this, - attaches = dataPriv.access( doc, fix ) - 1; - - if ( !attaches ) { - doc.removeEventListener( orig, handler, true ); - dataPriv.remove( doc, fix ); - - } else { - dataPriv.access( doc, fix, attaches ); - } - } - }; - } ); -} -var location = window.location; - -var nonce = jQuery.now(); - -var rquery = ( /\?/ ); - - - -// Cross-browser xml parsing -jQuery.parseXML = function( data ) { - var xml; - if ( !data || typeof data !== "string" ) { - return null; - } - - // Support: IE 9 - 11 only - // IE throws on parseFromString with invalid input. - try { - xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" ); - } catch ( e ) { - xml = undefined; - } - - if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) { - jQuery.error( "Invalid XML: " + data ); - } - return xml; -}; - - -var - rbracket = /\[\]$/, - rCRLF = /\r?\n/g, - rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i, - rsubmittable = /^(?:input|select|textarea|keygen)/i; - -function buildParams( prefix, obj, traditional, add ) { - var name; - - if ( Array.isArray( obj ) ) { - - // Serialize array item. - jQuery.each( obj, function( i, v ) { - if ( traditional || rbracket.test( prefix ) ) { - - // Treat each array item as a scalar. - add( prefix, v ); - - } else { - - // Item is non-scalar (array or object), encode its numeric index. - buildParams( - prefix + "[" + ( typeof v === "object" && v != null ? i : "" ) + "]", - v, - traditional, - add - ); - } - } ); - - } else if ( !traditional && jQuery.type( obj ) === "object" ) { - - // Serialize object item. - for ( name in obj ) { - buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); - } - - } else { - - // Serialize scalar item. - add( prefix, obj ); - } -} - -// Serialize an array of form elements or a set of -// key/values into a query string -jQuery.param = function( a, traditional ) { - var prefix, - s = [], - add = function( key, valueOrFunction ) { - - // If value is a function, invoke it and use its return value - var value = jQuery.isFunction( valueOrFunction ) ? - valueOrFunction() : - valueOrFunction; - - s[ s.length ] = encodeURIComponent( key ) + "=" + - encodeURIComponent( value == null ? "" : value ); - }; - - // If an array was passed in, assume that it is an array of form elements. - if ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { - - // Serialize the form elements - jQuery.each( a, function() { - add( this.name, this.value ); - } ); - - } else { - - // If traditional, encode the "old" way (the way 1.3.2 or older - // did it), otherwise encode params recursively. - for ( prefix in a ) { - buildParams( prefix, a[ prefix ], traditional, add ); - } - } - - // Return the resulting serialization - return s.join( "&" ); -}; - -jQuery.fn.extend( { - serialize: function() { - return jQuery.param( this.serializeArray() ); - }, - serializeArray: function() { - return this.map( function() { - - // Can add propHook for "elements" to filter or add form elements - var elements = jQuery.prop( this, "elements" ); - return elements ? jQuery.makeArray( elements ) : this; - } ) - .filter( function() { - var type = this.type; - - // Use .is( ":disabled" ) so that fieldset[disabled] works - return this.name && !jQuery( this ).is( ":disabled" ) && - rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) && - ( this.checked || !rcheckableType.test( type ) ); - } ) - .map( function( i, elem ) { - var val = jQuery( this ).val(); - - if ( val == null ) { - return null; - } - - if ( Array.isArray( val ) ) { - return jQuery.map( val, function( val ) { - return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; - } ); - } - - return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; - } ).get(); - } -} ); - - -var - r20 = /%20/g, - rhash = /#.*$/, - rantiCache = /([?&])_=[^&]*/, - rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg, - - // #7653, #8125, #8152: local protocol detection - rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/, - rnoContent = /^(?:GET|HEAD)$/, - rprotocol = /^\/\//, - - /* Prefilters - * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example) - * 2) These are called: - * - BEFORE asking for a transport - * - AFTER param serialization (s.data is a string if s.processData is true) - * 3) key is the dataType - * 4) the catchall symbol "*" can be used - * 5) execution will start with transport dataType and THEN continue down to "*" if needed - */ - prefilters = {}, - - /* Transports bindings - * 1) key is the dataType - * 2) the catchall symbol "*" can be used - * 3) selection will start with transport dataType and THEN go to "*" if needed - */ - transports = {}, - - // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression - allTypes = "*/".concat( "*" ), - - // Anchor tag for parsing the document origin - originAnchor = document.createElement( "a" ); - originAnchor.href = location.href; - -// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport -function addToPrefiltersOrTransports( structure ) { - - // dataTypeExpression is optional and defaults to "*" - return function( dataTypeExpression, func ) { - - if ( typeof dataTypeExpression !== "string" ) { - func = dataTypeExpression; - dataTypeExpression = "*"; - } - - var dataType, - i = 0, - dataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || []; - - if ( jQuery.isFunction( func ) ) { - - // For each dataType in the dataTypeExpression - while ( ( dataType = dataTypes[ i++ ] ) ) { - - // Prepend if requested - if ( dataType[ 0 ] === "+" ) { - dataType = dataType.slice( 1 ) || "*"; - ( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func ); - - // Otherwise append - } else { - ( structure[ dataType ] = structure[ dataType ] || [] ).push( func ); - } - } - } - }; -} - -// Base inspection function for prefilters and transports -function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) { - - var inspected = {}, - seekingTransport = ( structure === transports ); - - function inspect( dataType ) { - var selected; - inspected[ dataType ] = true; - jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) { - var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR ); - if ( typeof dataTypeOrTransport === "string" && - !seekingTransport && !inspected[ dataTypeOrTransport ] ) { - - options.dataTypes.unshift( dataTypeOrTransport ); - inspect( dataTypeOrTransport ); - return false; - } else if ( seekingTransport ) { - return !( selected = dataTypeOrTransport ); - } - } ); - return selected; - } - - return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" ); -} - -// A special extend for ajax options -// that takes "flat" options (not to be deep extended) -// Fixes #9887 -function ajaxExtend( target, src ) { - var key, deep, - flatOptions = jQuery.ajaxSettings.flatOptions || {}; - - for ( key in src ) { - if ( src[ key ] !== undefined ) { - ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ]; - } - } - if ( deep ) { - jQuery.extend( true, target, deep ); - } - - return target; -} - -/* Handles responses to an ajax request: - * - finds the right dataType (mediates between content-type and expected dataType) - * - returns the corresponding response - */ -function ajaxHandleResponses( s, jqXHR, responses ) { - - var ct, type, finalDataType, firstDataType, - contents = s.contents, - dataTypes = s.dataTypes; - - // Remove auto dataType and get content-type in the process - while ( dataTypes[ 0 ] === "*" ) { - dataTypes.shift(); - if ( ct === undefined ) { - ct = s.mimeType || jqXHR.getResponseHeader( "Content-Type" ); - } - } - - // Check if we're dealing with a known content-type - if ( ct ) { - for ( type in contents ) { - if ( contents[ type ] && contents[ type ].test( ct ) ) { - dataTypes.unshift( type ); - break; - } - } - } - - // Check to see if we have a response for the expected dataType - if ( dataTypes[ 0 ] in responses ) { - finalDataType = dataTypes[ 0 ]; - } else { - - // Try convertible dataTypes - for ( type in responses ) { - if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[ 0 ] ] ) { - finalDataType = type; - break; - } - if ( !firstDataType ) { - firstDataType = type; - } - } - - // Or just use first one - finalDataType = finalDataType || firstDataType; - } - - // If we found a dataType - // We add the dataType to the list if needed - // and return the corresponding response - if ( finalDataType ) { - if ( finalDataType !== dataTypes[ 0 ] ) { - dataTypes.unshift( finalDataType ); - } - return responses[ finalDataType ]; - } -} - -/* Chain conversions given the request and the original response - * Also sets the responseXXX fields on the jqXHR instance - */ -function ajaxConvert( s, response, jqXHR, isSuccess ) { - var conv2, current, conv, tmp, prev, - converters = {}, - - // Work with a copy of dataTypes in case we need to modify it for conversion - dataTypes = s.dataTypes.slice(); - - // Create converters map with lowercased keys - if ( dataTypes[ 1 ] ) { - for ( conv in s.converters ) { - converters[ conv.toLowerCase() ] = s.converters[ conv ]; - } - } - - current = dataTypes.shift(); - - // Convert to each sequential dataType - while ( current ) { - - if ( s.responseFields[ current ] ) { - jqXHR[ s.responseFields[ current ] ] = response; - } - - // Apply the dataFilter if provided - if ( !prev && isSuccess && s.dataFilter ) { - response = s.dataFilter( response, s.dataType ); - } - - prev = current; - current = dataTypes.shift(); - - if ( current ) { - - // There's only work to do if current dataType is non-auto - if ( current === "*" ) { - - current = prev; - - // Convert response if prev dataType is non-auto and differs from current - } else if ( prev !== "*" && prev !== current ) { - - // Seek a direct converter - conv = converters[ prev + " " + current ] || converters[ "* " + current ]; - - // If none found, seek a pair - if ( !conv ) { - for ( conv2 in converters ) { - - // If conv2 outputs current - tmp = conv2.split( " " ); - if ( tmp[ 1 ] === current ) { - - // If prev can be converted to accepted input - conv = converters[ prev + " " + tmp[ 0 ] ] || - converters[ "* " + tmp[ 0 ] ]; - if ( conv ) { - - // Condense equivalence converters - if ( conv === true ) { - conv = converters[ conv2 ]; - - // Otherwise, insert the intermediate dataType - } else if ( converters[ conv2 ] !== true ) { - current = tmp[ 0 ]; - dataTypes.unshift( tmp[ 1 ] ); - } - break; - } - } - } - } - - // Apply converter (if not an equivalence) - if ( conv !== true ) { - - // Unless errors are allowed to bubble, catch and return them - if ( conv && s.throws ) { - response = conv( response ); - } else { - try { - response = conv( response ); - } catch ( e ) { - return { - state: "parsererror", - error: conv ? e : "No conversion from " + prev + " to " + current - }; - } - } - } - } - } - } - - return { state: "success", data: response }; -} - -jQuery.extend( { - - // Counter for holding the number of active queries - active: 0, - - // Last-Modified header cache for next request - lastModified: {}, - etag: {}, - - ajaxSettings: { - url: location.href, - type: "GET", - isLocal: rlocalProtocol.test( location.protocol ), - global: true, - processData: true, - async: true, - contentType: "application/x-www-form-urlencoded; charset=UTF-8", - - /* - timeout: 0, - data: null, - dataType: null, - username: null, - password: null, - cache: null, - throws: false, - traditional: false, - headers: {}, - */ - - accepts: { - "*": allTypes, - text: "text/plain", - html: "text/html", - xml: "application/xml, text/xml", - json: "application/json, text/javascript" - }, - - contents: { - xml: /\bxml\b/, - html: /\bhtml/, - json: /\bjson\b/ - }, - - responseFields: { - xml: "responseXML", - text: "responseText", - json: "responseJSON" - }, - - // Data converters - // Keys separate source (or catchall "*") and destination types with a single space - converters: { - - // Convert anything to text - "* text": String, - - // Text to html (true = no transformation) - "text html": true, - - // Evaluate text as a json expression - "text json": JSON.parse, - - // Parse text as xml - "text xml": jQuery.parseXML - }, - - // For options that shouldn't be deep extended: - // you can add your own custom options here if - // and when you create one that shouldn't be - // deep extended (see ajaxExtend) - flatOptions: { - url: true, - context: true - } - }, - - // Creates a full fledged settings object into target - // with both ajaxSettings and settings fields. - // If target is omitted, writes into ajaxSettings. - ajaxSetup: function( target, settings ) { - return settings ? - - // Building a settings object - ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) : - - // Extending ajaxSettings - ajaxExtend( jQuery.ajaxSettings, target ); - }, - - ajaxPrefilter: addToPrefiltersOrTransports( prefilters ), - ajaxTransport: addToPrefiltersOrTransports( transports ), - - // Main method - ajax: function( url, options ) { - - // If url is an object, simulate pre-1.5 signature - if ( typeof url === "object" ) { - options = url; - url = undefined; - } - - // Force options to be an object - options = options || {}; - - var transport, - - // URL without anti-cache param - cacheURL, - - // Response headers - responseHeadersString, - responseHeaders, - - // timeout handle - timeoutTimer, - - // Url cleanup var - urlAnchor, - - // Request state (becomes false upon send and true upon completion) - completed, - - // To know if global events are to be dispatched - fireGlobals, - - // Loop variable - i, - - // uncached part of the url - uncached, - - // Create the final options object - s = jQuery.ajaxSetup( {}, options ), - - // Callbacks context - callbackContext = s.context || s, - - // Context for global events is callbackContext if it is a DOM node or jQuery collection - globalEventContext = s.context && - ( callbackContext.nodeType || callbackContext.jquery ) ? - jQuery( callbackContext ) : - jQuery.event, - - // Deferreds - deferred = jQuery.Deferred(), - completeDeferred = jQuery.Callbacks( "once memory" ), - - // Status-dependent callbacks - statusCode = s.statusCode || {}, - - // Headers (they are sent all at once) - requestHeaders = {}, - requestHeadersNames = {}, - - // Default abort message - strAbort = "canceled", - - // Fake xhr - jqXHR = { - readyState: 0, - - // Builds headers hashtable if needed - getResponseHeader: function( key ) { - var match; - if ( completed ) { - if ( !responseHeaders ) { - responseHeaders = {}; - while ( ( match = rheaders.exec( responseHeadersString ) ) ) { - responseHeaders[ match[ 1 ].toLowerCase() ] = match[ 2 ]; - } - } - match = responseHeaders[ key.toLowerCase() ]; - } - return match == null ? null : match; - }, - - // Raw string - getAllResponseHeaders: function() { - return completed ? responseHeadersString : null; - }, - - // Caches the header - setRequestHeader: function( name, value ) { - if ( completed == null ) { - name = requestHeadersNames[ name.toLowerCase() ] = - requestHeadersNames[ name.toLowerCase() ] || name; - requestHeaders[ name ] = value; - } - return this; - }, - - // Overrides response content-type header - overrideMimeType: function( type ) { - if ( completed == null ) { - s.mimeType = type; - } - return this; - }, - - // Status-dependent callbacks - statusCode: function( map ) { - var code; - if ( map ) { - if ( completed ) { - - // Execute the appropriate callbacks - jqXHR.always( map[ jqXHR.status ] ); - } else { - - // Lazy-add the new callbacks in a way that preserves old ones - for ( code in map ) { - statusCode[ code ] = [ statusCode[ code ], map[ code ] ]; - } - } - } - return this; - }, - - // Cancel the request - abort: function( statusText ) { - var finalText = statusText || strAbort; - if ( transport ) { - transport.abort( finalText ); - } - done( 0, finalText ); - return this; - } - }; - - // Attach deferreds - deferred.promise( jqXHR ); - - // Add protocol if not provided (prefilters might expect it) - // Handle falsy url in the settings object (#10093: consistency with old signature) - // We also use the url parameter if available - s.url = ( ( url || s.url || location.href ) + "" ) - .replace( rprotocol, location.protocol + "//" ); - - // Alias method option to type as per ticket #12004 - s.type = options.method || options.type || s.method || s.type; - - // Extract dataTypes list - s.dataTypes = ( s.dataType || "*" ).toLowerCase().match( rnothtmlwhite ) || [ "" ]; - - // A cross-domain request is in order when the origin doesn't match the current origin. - if ( s.crossDomain == null ) { - urlAnchor = document.createElement( "a" ); - - // Support: IE <=8 - 11, Edge 12 - 13 - // IE throws exception on accessing the href property if url is malformed, - // e.g. http://example.com:80x/ - try { - urlAnchor.href = s.url; - - // Support: IE <=8 - 11 only - // Anchor's host property isn't correctly set when s.url is relative - urlAnchor.href = urlAnchor.href; - s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !== - urlAnchor.protocol + "//" + urlAnchor.host; - } catch ( e ) { - - // If there is an error parsing the URL, assume it is crossDomain, - // it can be rejected by the transport if it is invalid - s.crossDomain = true; - } - } - - // Convert data if not already a string - if ( s.data && s.processData && typeof s.data !== "string" ) { - s.data = jQuery.param( s.data, s.traditional ); - } - - // Apply prefilters - inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ); - - // If request was aborted inside a prefilter, stop there - if ( completed ) { - return jqXHR; - } - - // We can fire global events as of now if asked to - // Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118) - fireGlobals = jQuery.event && s.global; - - // Watch for a new set of requests - if ( fireGlobals && jQuery.active++ === 0 ) { - jQuery.event.trigger( "ajaxStart" ); - } - - // Uppercase the type - s.type = s.type.toUpperCase(); - - // Determine if request has content - s.hasContent = !rnoContent.test( s.type ); - - // Save the URL in case we're toying with the If-Modified-Since - // and/or If-None-Match header later on - // Remove hash to simplify url manipulation - cacheURL = s.url.replace( rhash, "" ); - - // More options handling for requests with no content - if ( !s.hasContent ) { - - // Remember the hash so we can put it back - uncached = s.url.slice( cacheURL.length ); - - // If data is available, append data to url - if ( s.data ) { - cacheURL += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data; - - // #9682: remove data so that it's not used in an eventual retry - delete s.data; - } - - // Add or update anti-cache param if needed - if ( s.cache === false ) { - cacheURL = cacheURL.replace( rantiCache, "$1" ); - uncached = ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ( nonce++ ) + uncached; - } - - // Put hash and anti-cache on the URL that will be requested (gh-1732) - s.url = cacheURL + uncached; - - // Change '%20' to '+' if this is encoded form body content (gh-2658) - } else if ( s.data && s.processData && - ( s.contentType || "" ).indexOf( "application/x-www-form-urlencoded" ) === 0 ) { - s.data = s.data.replace( r20, "+" ); - } - - // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. - if ( s.ifModified ) { - if ( jQuery.lastModified[ cacheURL ] ) { - jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] ); - } - if ( jQuery.etag[ cacheURL ] ) { - jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] ); - } - } - - // Set the correct header, if data is being sent - if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { - jqXHR.setRequestHeader( "Content-Type", s.contentType ); - } - - // Set the Accepts header for the server, depending on the dataType - jqXHR.setRequestHeader( - "Accept", - s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ? - s.accepts[ s.dataTypes[ 0 ] ] + - ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) : - s.accepts[ "*" ] - ); - - // Check for headers option - for ( i in s.headers ) { - jqXHR.setRequestHeader( i, s.headers[ i ] ); - } - - // Allow custom headers/mimetypes and early abort - if ( s.beforeSend && - ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) { - - // Abort if not done already and return - return jqXHR.abort(); - } - - // Aborting is no longer a cancellation - strAbort = "abort"; - - // Install callbacks on deferreds - completeDeferred.add( s.complete ); - jqXHR.done( s.success ); - jqXHR.fail( s.error ); - - // Get transport - transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR ); - - // If no transport, we auto-abort - if ( !transport ) { - done( -1, "No Transport" ); - } else { - jqXHR.readyState = 1; - - // Send global event - if ( fireGlobals ) { - globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] ); - } - - // If request was aborted inside ajaxSend, stop there - if ( completed ) { - return jqXHR; - } - - // Timeout - if ( s.async && s.timeout > 0 ) { - timeoutTimer = window.setTimeout( function() { - jqXHR.abort( "timeout" ); - }, s.timeout ); - } - - try { - completed = false; - transport.send( requestHeaders, done ); - } catch ( e ) { - - // Rethrow post-completion exceptions - if ( completed ) { - throw e; - } - - // Propagate others as results - done( -1, e ); - } - } - - // Callback for when everything is done - function done( status, nativeStatusText, responses, headers ) { - var isSuccess, success, error, response, modified, - statusText = nativeStatusText; - - // Ignore repeat invocations - if ( completed ) { - return; - } - - completed = true; - - // Clear timeout if it exists - if ( timeoutTimer ) { - window.clearTimeout( timeoutTimer ); - } - - // Dereference transport for early garbage collection - // (no matter how long the jqXHR object will be used) - transport = undefined; - - // Cache response headers - responseHeadersString = headers || ""; - - // Set readyState - jqXHR.readyState = status > 0 ? 4 : 0; - - // Determine if successful - isSuccess = status >= 200 && status < 300 || status === 304; - - // Get response data - if ( responses ) { - response = ajaxHandleResponses( s, jqXHR, responses ); - } - - // Convert no matter what (that way responseXXX fields are always set) - response = ajaxConvert( s, response, jqXHR, isSuccess ); - - // If successful, handle type chaining - if ( isSuccess ) { - - // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. - if ( s.ifModified ) { - modified = jqXHR.getResponseHeader( "Last-Modified" ); - if ( modified ) { - jQuery.lastModified[ cacheURL ] = modified; - } - modified = jqXHR.getResponseHeader( "etag" ); - if ( modified ) { - jQuery.etag[ cacheURL ] = modified; - } - } - - // if no content - if ( status === 204 || s.type === "HEAD" ) { - statusText = "nocontent"; - - // if not modified - } else if ( status === 304 ) { - statusText = "notmodified"; - - // If we have data, let's convert it - } else { - statusText = response.state; - success = response.data; - error = response.error; - isSuccess = !error; - } - } else { - - // Extract error from statusText and normalize for non-aborts - error = statusText; - if ( status || !statusText ) { - statusText = "error"; - if ( status < 0 ) { - status = 0; - } - } - } - - // Set data for the fake xhr object - jqXHR.status = status; - jqXHR.statusText = ( nativeStatusText || statusText ) + ""; - - // Success/Error - if ( isSuccess ) { - deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] ); - } else { - deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] ); - } - - // Status-dependent callbacks - jqXHR.statusCode( statusCode ); - statusCode = undefined; - - if ( fireGlobals ) { - globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError", - [ jqXHR, s, isSuccess ? success : error ] ); - } - - // Complete - completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] ); - - if ( fireGlobals ) { - globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] ); - - // Handle the global AJAX counter - if ( !( --jQuery.active ) ) { - jQuery.event.trigger( "ajaxStop" ); - } - } - } - - return jqXHR; - }, - - getJSON: function( url, data, callback ) { - return jQuery.get( url, data, callback, "json" ); - }, - - getScript: function( url, callback ) { - return jQuery.get( url, undefined, callback, "script" ); - } -} ); - -jQuery.each( [ "get", "post" ], function( i, method ) { - jQuery[ method ] = function( url, data, callback, type ) { - - // Shift arguments if data argument was omitted - if ( jQuery.isFunction( data ) ) { - type = type || callback; - callback = data; - data = undefined; - } - - // The url can be an options object (which then must have .url) - return jQuery.ajax( jQuery.extend( { - url: url, - type: method, - dataType: type, - data: data, - success: callback - }, jQuery.isPlainObject( url ) && url ) ); - }; -} ); - - -jQuery._evalUrl = function( url ) { - return jQuery.ajax( { - url: url, - - // Make this explicit, since user can override this through ajaxSetup (#11264) - type: "GET", - dataType: "script", - cache: true, - async: false, - global: false, - "throws": true - } ); -}; - - -jQuery.fn.extend( { - wrapAll: function( html ) { - var wrap; - - if ( this[ 0 ] ) { - if ( jQuery.isFunction( html ) ) { - html = html.call( this[ 0 ] ); - } - - // The elements to wrap the target around - wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true ); - - if ( this[ 0 ].parentNode ) { - wrap.insertBefore( this[ 0 ] ); - } - - wrap.map( function() { - var elem = this; - - while ( elem.firstElementChild ) { - elem = elem.firstElementChild; - } - - return elem; - } ).append( this ); - } - - return this; - }, - - wrapInner: function( html ) { - if ( jQuery.isFunction( html ) ) { - return this.each( function( i ) { - jQuery( this ).wrapInner( html.call( this, i ) ); - } ); - } - - return this.each( function() { - var self = jQuery( this ), - contents = self.contents(); - - if ( contents.length ) { - contents.wrapAll( html ); - - } else { - self.append( html ); - } - } ); - }, - - wrap: function( html ) { - var isFunction = jQuery.isFunction( html ); - - return this.each( function( i ) { - jQuery( this ).wrapAll( isFunction ? html.call( this, i ) : html ); - } ); - }, - - unwrap: function( selector ) { - this.parent( selector ).not( "body" ).each( function() { - jQuery( this ).replaceWith( this.childNodes ); - } ); - return this; - } -} ); - - -jQuery.expr.pseudos.hidden = function( elem ) { - return !jQuery.expr.pseudos.visible( elem ); -}; -jQuery.expr.pseudos.visible = function( elem ) { - return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length ); -}; - - - - -jQuery.ajaxSettings.xhr = function() { - try { - return new window.XMLHttpRequest(); - } catch ( e ) {} -}; - -var xhrSuccessStatus = { - - // File protocol always yields status code 0, assume 200 - 0: 200, - - // Support: IE <=9 only - // #1450: sometimes IE returns 1223 when it should be 204 - 1223: 204 - }, - xhrSupported = jQuery.ajaxSettings.xhr(); - -support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported ); -support.ajax = xhrSupported = !!xhrSupported; - -jQuery.ajaxTransport( function( options ) { - var callback, errorCallback; - - // Cross domain only allowed if supported through XMLHttpRequest - if ( support.cors || xhrSupported && !options.crossDomain ) { - return { - send: function( headers, complete ) { - var i, - xhr = options.xhr(); - - xhr.open( - options.type, - options.url, - options.async, - options.username, - options.password - ); - - // Apply custom fields if provided - if ( options.xhrFields ) { - for ( i in options.xhrFields ) { - xhr[ i ] = options.xhrFields[ i ]; - } - } - - // Override mime type if needed - if ( options.mimeType && xhr.overrideMimeType ) { - xhr.overrideMimeType( options.mimeType ); - } - - // X-Requested-With header - // For cross-domain requests, seeing as conditions for a preflight are - // akin to a jigsaw puzzle, we simply never set it to be sure. - // (it can always be set on a per-request basis or even using ajaxSetup) - // For same-domain requests, won't change header if already provided. - if ( !options.crossDomain && !headers[ "X-Requested-With" ] ) { - headers[ "X-Requested-With" ] = "XMLHttpRequest"; - } - - // Set headers - for ( i in headers ) { - xhr.setRequestHeader( i, headers[ i ] ); - } - - // Callback - callback = function( type ) { - return function() { - if ( callback ) { - callback = errorCallback = xhr.onload = - xhr.onerror = xhr.onabort = xhr.onreadystatechange = null; - - if ( type === "abort" ) { - xhr.abort(); - } else if ( type === "error" ) { - - // Support: IE <=9 only - // On a manual native abort, IE9 throws - // errors on any property access that is not readyState - if ( typeof xhr.status !== "number" ) { - complete( 0, "error" ); - } else { - complete( - - // File: protocol always yields status 0; see #8605, #14207 - xhr.status, - xhr.statusText - ); - } - } else { - complete( - xhrSuccessStatus[ xhr.status ] || xhr.status, - xhr.statusText, - - // Support: IE <=9 only - // IE9 has no XHR2 but throws on binary (trac-11426) - // For XHR2 non-text, let the caller handle it (gh-2498) - ( xhr.responseType || "text" ) !== "text" || - typeof xhr.responseText !== "string" ? - { binary: xhr.response } : - { text: xhr.responseText }, - xhr.getAllResponseHeaders() - ); - } - } - }; - }; - - // Listen to events - xhr.onload = callback(); - errorCallback = xhr.onerror = callback( "error" ); - - // Support: IE 9 only - // Use onreadystatechange to replace onabort - // to handle uncaught aborts - if ( xhr.onabort !== undefined ) { - xhr.onabort = errorCallback; - } else { - xhr.onreadystatechange = function() { - - // Check readyState before timeout as it changes - if ( xhr.readyState === 4 ) { - - // Allow onerror to be called first, - // but that will not handle a native abort - // Also, save errorCallback to a variable - // as xhr.onerror cannot be accessed - window.setTimeout( function() { - if ( callback ) { - errorCallback(); - } - } ); - } - }; - } - - // Create the abort callback - callback = callback( "abort" ); - - try { - - // Do send the request (this may raise an exception) - xhr.send( options.hasContent && options.data || null ); - } catch ( e ) { - - // #14683: Only rethrow if this hasn't been notified as an error yet - if ( callback ) { - throw e; - } - } - }, - - abort: function() { - if ( callback ) { - callback(); - } - } - }; - } -} ); - - - - -// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432) -jQuery.ajaxPrefilter( function( s ) { - if ( s.crossDomain ) { - s.contents.script = false; - } -} ); - -// Install script dataType -jQuery.ajaxSetup( { - accepts: { - script: "text/javascript, application/javascript, " + - "application/ecmascript, application/x-ecmascript" - }, - contents: { - script: /\b(?:java|ecma)script\b/ - }, - converters: { - "text script": function( text ) { - jQuery.globalEval( text ); - return text; - } - } -} ); - -// Handle cache's special case and crossDomain -jQuery.ajaxPrefilter( "script", function( s ) { - if ( s.cache === undefined ) { - s.cache = false; - } - if ( s.crossDomain ) { - s.type = "GET"; - } -} ); - -// Bind script tag hack transport -jQuery.ajaxTransport( "script", function( s ) { - - // This transport only deals with cross domain requests - if ( s.crossDomain ) { - var script, callback; - return { - send: function( _, complete ) { - script = jQuery( "