diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7316f21 --- /dev/null +++ b/.gitignore @@ -0,0 +1,48 @@ +################### +# LATEX +################### +*.aux +*.glo +*.idx +*.log +*.toc +*.ist +*.acn +*.acr +*.alg +*.bbl +*.blg +*.dvi +*.glg +*.gls +*.ilg +*.ind +*.lof +*.lot +*.maf +*.mtc +*.mtc1 +*.out +*.synctex.gz +*.brf +*.nav +*.snm +*.vrb + +################### +# Java +################### +src/site/markdown/index.md +target/* +.classpath +.project +.settings/ +moco.iml +.idea/* + +################### +# Editor +################### +*.swp + +dependency-reduced-pom.xml diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/COPYING @@ -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. + + + Copyright (C) + + 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: + + Copyright (C) + 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/COPYING_EXCEPTION b/COPYING_EXCEPTION new file mode 100644 index 0000000..40424cf --- /dev/null +++ b/COPYING_EXCEPTION @@ -0,0 +1,18 @@ +Linking this program and/or its accompanying libraries statically or +dynamically with other modules is making a combined work based on this +program. Thus, the terms and conditions of the GNU General Public License +cover the whole combination. + +As a special exception, the copyright holders of moco give +you permission to link this programm and/or its accompanying libraries +with independent modules to produce an executable, regardless of the +license terms of these independent modules, and to copy and distribute the +resulting executable under terms of your choice, provided that you also meet, +for each linked independent module, the terms and conditions of the +license of that module. + +An independent module is a module which is not +derived from or based on this program and/or its accompanying libraries. +If you modify this library, you may extend this exception to your version of +the program or library, but you are not obliged to do so. If you do not wish +to do so, delete this exception statement from your version. \ No newline at end of file diff --git a/COPYING_HEADER b/COPYING_HEADER new file mode 100644 index 0000000..27cf923 --- /dev/null +++ b/COPYING_HEADER @@ -0,0 +1,38 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..ddb07c5 --- /dev/null +++ b/README.md @@ -0,0 +1,70 @@ +Allgemeines +----------- + +Dieses Projekt setzt Java in der Version 7 ein. Stellt sicher, dass ihr keine +Features von Java 8 verwendet. Die Referenz ob das Projekt baut und die Tests +laufen sind die Maven-Runs. + +Es wird durch Maven automatisch ein Code-Formatter ausgeführt. Bitte +kompiliert also vor dem commiten einmal mit Maven oder konfiguriert eure IDE, +sodass diese den Code entsprechend formatiert. + +Zu installierende Software: + +- Java 7 +- Maven 3 http://maven.apache.org/ +- LLVM 3.4 http://llvm.org/ +- Graphviz http://www.graphviz.org/ + +Bei Windows benötigt ihr extra noch: + +- ein 32bit JDK +- Visual C++ Redistributable Packages für Visual Studio 2013 + http://www.microsoft.com/de-de/download/details.aspx?id=40784 + +Kompilation und Ausführen +------------------------- + +- `mvn package` + Generiert die nötigen ANTLR4 Dateien, kompiliert alle wichtigen Dateien, + führt die Tests aus und baut ein ausführbares JAR + (`target/moco-0.6.jar`). +- `mvn package -Dmaven.test.skip=true` + Führt die Tests nicht aus. +Habt ihr das JAR erstellt, könnt ihr die Main Klasse mit `java -jar +target/moco-0.6.jar` starten. + +Maven Reporting +--------------- + +Maven wurde eingerichtet Reports zu generieren. + +`mvn site` erstellt die Dokumentation und generiert Reports unter +[target/site/](project-reports.html). Besonders interessant: + + - [JavaDoc](apidocs/index.html) + - [Code Coverage Analysis](cobertura/index.html) + +Außerdem gibt es Analysen auf dem Code. Bitte beachtet, dass euer Code nicht +zu viele Einträge in folgenden Reports erzeugt: + +- [Checkstyle](checkstyle.html) +- [Findbugs](findbugs.html) + +Entwicklungsumgebungen +---------------------- + +###Eclipse: + +- Maven kann mit `mvn eclipse:eclipse` Eclipse Konfiguration generieren. + Ist dies erledigt kann man das Projekt einfach als existierendes Projekt + importieren. +- Es wird ein Code Formatter verwendet. Unter + `src/main/resources/java-code-conv.xml` findet sich ein in Eclipse + importierbares Profil. +- Alternativ: + - m2e in Eclipse installieren: http://download.eclipse.org/technology/m2e/releases + - File -> Import -> Maven -> Existing Maven Projects -> Browse... -> Auf Projekt Zeigen -> Next -> Finish -> OK + - Rechtsklick auf Projekt moco -> Maven -> Update Project Config... + - Ordner "target" -> generated-sources -> Rechtsklick auf "antlr4" -> Build Path -> Use as source Folder + - Run diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..fa20d65 --- /dev/null +++ b/pom.xml @@ -0,0 +1,281 @@ + + + 4.0.0 + + moco + moco + 0.6 + + + UTF-8 + ${project.basedir}/src/main/resources/checkstyle.xml + + + + + unix + + + !windows + + + + + + + org.codehaus.mojo + exec-maven-plugin + 1.3.2 + + + rm-trailing-ws + compile + + exec + + + ${basedir}/src/main/resources/rm_trailing_whitespace.sh + + ${basedir}/src + + + + + + + + + + + + + + org.apache.maven.plugins + maven-jar-plugin + 2.5 + + + + de.uni.bremen.monty.moco.Main + + + + + + + org.apache.maven.plugins + maven-shade-plugin + 2.3 + + + package + + shade + + + + + + + com.googlecode.maven-java-formatter-plugin + maven-java-formatter-plugin + 0.4 + + ${project.basedir}/src/main/resources/moco-code-conv.xml + true + 1.7 + 1.7 + 1.7 + LF + UTF-8 + + + + + format + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.1 + + 1.7 + 1.7 + + + + + org.antlr + antlr4-maven-plugin + 4.2.2 + + + + antlr4 + + + false + true + + + + + true + + + + + org.apache.maven.plugins + maven-antrun-plugin + 1.7 + + + pre-site + + run + + + + + + + + + + + + + org.apache.maven.plugins + maven-site-plugin + 3.3 + + + org.apache.maven.doxia + doxia-module-markdown + 1.3 + + + + + + + + + + + + org.apache.maven.plugins + maven-project-info-reports-plugin + 2.6 + + + + index + + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 2.9.1 + + + + javadoc + + + + + org.umlgraph.doclet.UmlGraphDoc + + org.umlgraph + umlgraph + 5.6 + + -views -all -horizontal + true + *antlr4* + + + + + org.apache.maven.plugins + maven-jxr-plugin + 2.3 + + + + org.apache.maven.plugins + maven-surefire-report-plugin + 2.17 + + + + org.codehaus.mojo + cobertura-maven-plugin + 2.6 + + + html + + + + + + org.apache.maven.plugins + maven-checkstyle-plugin + 2.12.1 + + + + + + + + org.antlr + antlr4-runtime + 4.2.2 + + + + junit + junit + 4.11 + test + + + + commons-io + commons-io + 2.4 + + + + org.apache.commons + commons-lang3 + 3.3.1 + + + + org.mockito + mockito-all + 1.9.5 + test + + + + org.hamcrest + hamcrest-all + 1.3 + test + + + diff --git a/src/main/antlr4/de/uni/bremen/monty/moco/antlr/Monty.g4 b/src/main/antlr4/de/uni/bremen/monty/moco/antlr/Monty.g4 new file mode 100644 index 0000000..39c6668 --- /dev/null +++ b/src/main/antlr4/de/uni/bremen/monty/moco/antlr/Monty.g4 @@ -0,0 +1,228 @@ +grammar Monty; + +import lex; + +compilationUnit + : EndOfLine* moduleDeclaration EOF + ; + +moduleDeclaration + : importLine* ((classDeclaration | statement) EndOfLine*)* + ; + +importLine + : 'import' Identifier EndOfLine+ + ; + +independentDeclaration + : variableDeclaration (':=' expression)? EndOfLine + | constantDeclaration (':=' expression)? EndOfLine + | functionDeclaration + | procedureDeclaration + ; + +classDeclaration + : 'abstract'? 'class' ClassIdentifier ('inherits' typeList)? + ':' EndOfLine + Indent + (memberDeclaration+ | 'pass' EndOfLine) + Dedent + ; + +memberDeclaration + : accessModifier independentDeclaration + ; + +accessModifier + : modifier='#' + | modifier='+' + | modifier='-' + | modifier='~' + ; + +variableDeclaration + : type Identifier + ; + +constantDeclaration + : type ConstantIdentifier + ; + +type + : ClassIdentifier ('<' typeList '>')? + ; + +typeList + : type (',' type)* + ; + +functionDeclaration + : type + (Identifier | 'operator' binaryOperation) + Lparenthesis parameterList? Rparenthesis ':' EndOfLine + statementBlock + ; + +procedureDeclaration + : Identifier Lparenthesis parameterList? Rparenthesis ':' EndOfLine + statementBlock + ; + +defaultParameter + : variableDeclaration ':=' expression + ; + +parameterList + : defaultParameter (',' defaultParameter)* + | variableDeclaration (',' variableDeclaration)* (',' defaultParameter)* + ; + +statementBlock + : Indent + (statement+ | 'pass' EndOfLine) + Dedent + ; + +statement + : whileStatement #whileStm + | ifStatement #ifStm + | tryStatement #tryStm + | assignment #assignStm + | compoundAssignment #compoundAssign + | independentDeclaration #independentDeclStm + | command='return' expression? EndOfLine #returnStm + | command='raise' expression? EndOfLine #raiseStm + | command='skip' EndOfLine #skipStm + | command='break' EndOfLine #breakStm + | functionCall EndOfLine #funcCallStm + | left=expression operator='.' right=functionCall EndOfLine #MemberAccessStmt + ; + +/* while loop: The expression must be a condition (i.e. Boolean expression). */ +whileStatement + : 'while' expression ':' EndOfLine statementBlock + ; + +ifStatement + : 'if' ifCondition=expression ':' EndOfLine thenBlock=statementBlock + elif* + ('else' ':' EndOfLine elseBlock=statementBlock)? + ; + +elif + : 'elif' elifCondition=expression ':' EndOfLine elifBlock=statementBlock + ; + +tryStatement + : 'try:' EndOfLine tryBlock=statementBlock + ('handle' variableDeclaration? ':' EndOfLine handleBlock=statementBlock)+ + ; + +assignment + : left=expression ':=' right=expression EndOfLine + ; + +compoundAssignment + : left=expression compoundSymbol right=expression EndOfLine + ; + +compoundSymbol + : operator=('+=' | '-=' | '*=' | '/=' | '%=' | '^=') + ; + +functionCall + : (ClassIdentifier | Identifier) '(' expressionList? ')' + ; + +expressionList + : expression (',' expression)* + ; + +expression + : primary + | ifExprThen=expression 'if' ifExpCondition=expression 'else' ifExprElse=expression + | functionCall + | array=expression Lbracket index=expression Rbracket + | left=expression accessOperator right=expression + | (plusMinusOperator | notOperator) singleExpression=expression + | left=expression powerOperator right=expression + | left=expression dotOperator right=expression + | left=expression plusMinusOperator right=expression + | left=expression compareOperator right=expression + | left=expression eqOperator right=expression + | left=expression inOperator right=expression + | left=expression andOperator right=expression + | left=expression orOperator right=expression + | expr=expression asOperator ClassIdentifier + | expr=expression isOperator ClassIdentifier + ; + +primary + : Lparenthesis singleExpression=expression Rparenthesis + | literal + | Identifier + | ConstantIdentifier + | 'self' + | 'parent(' parent=ClassIdentifier ')' + ; + +inOperator + : operator='in' + ; + +andOperator + : operator='and' + ; + +orOperator + : operator=('or' | 'xor') + ; + +asOperator + : operator='as' + ; + +isOperator + : operator='is' + ; + +eqOperator + : operator=('=' | '!=') + ; + +compareOperator + : operator=('<' | '>' | '>=' | '<=') + ; + +powerOperator + : operator='^' + ; + +plusMinusOperator + : operator=('+' | '-') + ; + +notOperator + : operator='not' + ; + +accessOperator + : operator=('.' | '->') + ; + +dotOperator + : operator=('*' | '/' | '%') + ; + +literal + : IntegerLiteral + | RealLiteral + | CharacterLiteral + | StringLiteral + | BooleanLiteral + | arrayLiteral + ; + +arrayLiteral + : Lbracket (expression (',' expression)*)? Rbracket + ; diff --git a/src/main/antlr4/imports/lex.g4 b/src/main/antlr4/imports/lex.g4 new file mode 100644 index 0000000..75de360 --- /dev/null +++ b/src/main/antlr4/imports/lex.g4 @@ -0,0 +1,247 @@ +lexer grammar lex; + +@lexer::header { + import java.util.Stack; + import java.util.LinkedList; + import java.util.Queue; +} + +@lexer::members { +// we need a stack to store the indentation levels +Stack indentationStack = new Stack(); +// the queue provides us the possibility to add more than one token per lexer rule +Queue tokenQueue = new LinkedList(); +// we have to count opening an closing brackets for implicit line skips +int nesting = 0; + +// we have to store the 'imaginary tokens' because they only appear in the parser class +public static final int Indent = MontyParser.Indent; +public static final int Dedent = MontyParser.Dedent; + +// initialize the indentation stack with level 0 indent +{ + indentationStack.push(0); +} + +// add every token to the queue +@Override +public void emit(Token token) { + _token = token; + tokenQueue.offer(token); +} + +// return tokens from the queue until it is empty, then return EOF +@Override +public Token nextToken() { + super.nextToken(); + if(tokenQueue.peek() == null) + return new CommonToken(Token.EOF); + return tokenQueue.poll(); +} +} + +// forward declarations of 'imaginary tokens' +tokens { Indent, Dedent } + +// line skip with \ +ExplicitLineSkip : '\\' ('\u000C')? '\r'? '\n' -> skip; +// line skip within brackets +// ImplicitLineSkip : ('\u000C')? '\r'? '\n' {nesting>0}? -> skip; + +// check indentation, treat multiple newlines as one +EndOfLine : + //_________line breaks____ _whitespaces__ __comments__ ___last line break______ ___indent__ + ((('\u000C')?('\r')? '\n' ) | '\t' | ' ' | ('//' (~'\n')*))* (('\u000C')?('\r')? '\n' ) (' ' | '\t' )* + + { + if(nesting>0) + { + skip(); + return; + } + + String tokenText = getText(); + int indentLength = tokenText.length()-(tokenText.lastIndexOf("\n")+1); + // generate a newline token + tokenQueue.offer(new CommonToken(EndOfLine, "\n")); + + // if the indentation is deeper than the last one, add an Indent token + if(indentLength > indentationStack.peek()) + { + indentationStack.push(indentLength); + tokenQueue.offer(new CommonToken(Indent, "Indent")); + } + // if the indentation is less deep than the last line, + // add as many Dedent tokens as required + else if(indentLength < indentationStack.peek()) + { + while(indentationStack.peek() > indentLength) + { + indentationStack.pop(); + tokenQueue.offer(new CommonToken(Dedent, "Dedent")); + } + // if the new indentation does not match any outer level, + // we have a problem: + if(indentationStack.peek() != indentLength) + { + throw new RuntimeException("Monty says: Your indentation sucks!"); + } + } + + skip(); // do not automatically emit an EndOfLine token, + // since we already did it manually to ensure + // that it appears before the Indent or Dedent tokens + }; + +Lparenthesis + : '(' {nesting++;} ; +Rparenthesis + : ')' {nesting--;} ; +Lbracket + : '[' {nesting++;} ; +Rbracket + : ']' {nesting--;} ; +Lcurly + : '{' {nesting++;} ; +Rcurly + : '}' {nesting--;} ; + + +/* See http://www.antlr.org/wiki/display/ANTLR4/Grammar+Lexicon */ +fragment IdentifierStart + : Letter + | '\u00C0' .. '\u00D6' + | '\u00D8' .. '\u00F6' + | '\u00F8' .. '\u02FF' + | '\u0370' .. '\u037D' + | '\u037F' .. '\u1FFF' + | '\u200C' .. '\u200D' + | '\u2070' .. '\u218F' + | '\u2C00' .. '\u2FEF' + | '\u3001' .. '\uD7FF' + | '\uF900' .. '\uFDCF' + | '\uFDF0' .. '\uFFFD' + ; + +fragment IdentifierCharacter + : IdentifierStart + | Digit + | '_' + | '\u00B7' + | '\u0300' .. '\u036F' + | '\u203F' .. '\u2040' + ; + +BooleanLiteral + : ('true' | 'false') + ; + +/* Unicode identifiers. */ +Identifier + : '_'* LowercaseLetter (LowercaseLetter | UppercaseLetter | Digit | '_')* + ; + +ClassIdentifier + : UppercaseLetter (LowercaseLetter | UppercaseLetter | Digit)* LowercaseLetter (LowercaseLetter | UppercaseLetter | Digit)* + ; + +ConstantIdentifier + : '_'* UppercaseLetter (UppercaseLetter | Digit | '_')* + ; + +UppercaseLetter + : [A-Z] + ; + +LowercaseLetter + : [a-z] + ; + +IntegerLiteral + : (Digit | Letter)+ Exponent? Base? + ; + +RealLiteral + : Digit+ '.' Digit+ Exponent? + ; + +Digit + : [0-9] + ; + +Letter + : [a-zA-Z] + ; + +operation + : unaryOperation + | binaryOperation + ; + +unaryOperation + : 'not' + | '-' + ; + +binaryOperation + : '+' + | '-' + | '*' + | '/' + | '%' + | '^' + + | '=' + | '!=' + | '<' + | '>' + | '<=' + | '>=' + + | 'and' + | 'or' + | 'xor' + + | Lbracket Rbracket + + | 'in' + ; + +fragment Base + : '_' Digit+ + ; + +fragment Exponent + : 'e' ('+' | '-')? Digit+ + ; + +CharacterLiteral + : '\'' (CharacterEscapeSequence | ~('\'' | '\\')) '\'' + ; + +StringLiteral + : 'raw'? '"' (StringEscapeSequence | ~('\\' | '"'))* '"' + ; + +fragment CharacterEscapeSequence + : '\\' ('b' | 't' | 'n' | 'f' | 'r' | '\'' | '\\') + ; + +// hier müsste man noch das \n aus dem String rauskriegen +fragment StringEscapeSequence + : '\\' ('b' | 't' | 'n' | 'f' | 'r' | '\"' | '\\' | '$' | (('\u000C')?('\r')? '\n' )) + ; + +/* Toss out whitespaces. */ +Whitespaces + : ' '+ -> skip + ; + +/* Treat one or more tabs as a token representing a sequence of indentation + * characters. + */ +SpaceChars + : '\t'+ -> skip + ; + +Semicolon : ';' ; diff --git a/src/main/java/de/uni/bremen/monty/moco/Main.java b/src/main/java/de/uni/bremen/monty/moco/Main.java new file mode 100644 index 0000000..ed44a80 --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/Main.java @@ -0,0 +1,152 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco; + +import de.uni.bremen.monty.moco.antlr.MontyParser; +import de.uni.bremen.monty.moco.ast.AntlrAdapter; +import de.uni.bremen.monty.moco.ast.Package; +import de.uni.bremen.monty.moco.ast.PackageBuilder; +import de.uni.bremen.monty.moco.util.Params; +import de.uni.bremen.monty.moco.util.ParseTreePrinter; +import de.uni.bremen.monty.moco.visitor.*; +import org.antlr.v4.runtime.misc.TestRig; +import org.apache.commons.io.IOUtils; + +import java.io.*; + +public class Main { + + public static void main(String[] args) throws IOException { + Params params = new Params(args); + new Main().start(params); + } + + private void start(Params params) throws IOException { + + String inputFile = params.getInputFile(); + + if (params.isDebugParseTree()) { + debugParseTree(params, inputFile); + return; + } + + PackageBuilder packageBuilder = new PackageBuilder(params); + Package mainPackage = packageBuilder.buildPackage(); + + visitVisitors(params, mainPackage); + } + + private void visitVisitors(Params params, Package ast) throws IOException { + + BaseVisitor[] visitors = + new BaseVisitor[] { new SetParentVisitor(), new DeclarationVisitor(), new ResolveVisitor(), + new TypeCheckVisitor(), new ControlFlowVisitor(), new NameManglingVisitor() }; + + boolean everyThingIsAwesome = true; + + for (BaseVisitor visitor : visitors) { + visitor.setStopOnFirstError(params.isStopOnFirstError()); + visitor.setStopOnFirstError(params.isStopOnFirstError()); + + try { + visitor.visitDoubleDispatched(ast); + } catch (RuntimeException exception) { + visitor.logError(exception); + everyThingIsAwesome = false; + break; + } + + if (visitor.foundError()) { + everyThingIsAwesome = false; + break; + } + } + + if (params.usePrintVisitor()) { + (new PrintVisitor()).visitDoubleDispatched(ast); + } else if (everyThingIsAwesome) { + (new CodeGenerationVisitor(params)).visitDoubleDispatched(ast); + generateCode(params); + } + } + + private void debugParseTree(Params params, String inputFile) throws IOException { + AntlrAdapter antlrAdapter = new AntlrAdapter(); + + File file = new File(inputFile); + MontyParser parser = antlrAdapter.createParser(new FileInputStream(file)); + ParseTreePrinter parseTreePrinter = new ParseTreePrinter(parser); + parser.addParseListener(parseTreePrinter); + parser.compilationUnit(); + System.out.print(parseTreePrinter.toString()); + try { + new TestRig(new String[] { "de.uni.bremen.monty.moco.antlr.Monty", "compilationUnit", "-gui", + params.getInputFile() }).process(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + private void generateCode(Params params) throws IOException { + PrintStream resultStream; + if (params.getOutputFile() == null) { + resultStream = System.out; + } else { + resultStream = new PrintStream(new FileOutputStream(params.getOutputFile())); + } + + if (!params.isGenerateOnlyLLVM()) { + String llFile = params.getLlFile(); + ProcessBuilder processBuilder = new ProcessBuilder("lli", llFile); + Process start = processBuilder.start(); + + String in = IOUtils.toString(start.getInputStream()); + String err = IOUtils.toString(start.getErrorStream()); + + System.err.print(err); + resultStream.print(in); + + if (!params.isKeepLLVMCode()) { + if (!new File(llFile).delete()) { + System.err.println("Warning: failed to delete file " + llFile); + } + } + } + } +} diff --git a/src/main/java/de/uni/bremen/monty/moco/ast/ASTBuilder.java b/src/main/java/de/uni/bremen/monty/moco/ast/ASTBuilder.java new file mode 100644 index 0000000..ff6a19e --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/ast/ASTBuilder.java @@ -0,0 +1,644 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.ast; + +import de.uni.bremen.monty.moco.antlr.MontyBaseVisitor; +import de.uni.bremen.monty.moco.antlr.MontyParser; +import de.uni.bremen.monty.moco.antlr.MontyParser.DefaultParameterContext; +import de.uni.bremen.monty.moco.antlr.MontyParser.TypeContext; +import de.uni.bremen.monty.moco.antlr.MontyParser.*; +import de.uni.bremen.monty.moco.ast.declaration.*; +import de.uni.bremen.monty.moco.ast.declaration.ProcedureDeclaration.DeclarationType; +import de.uni.bremen.monty.moco.ast.expression.*; +import de.uni.bremen.monty.moco.ast.expression.literal.*; +import de.uni.bremen.monty.moco.ast.statement.*; + +import org.antlr.v4.runtime.Token; +import org.antlr.v4.runtime.misc.NotNull; +import org.antlr.v4.runtime.tree.TerminalNode; +import org.apache.commons.io.FilenameUtils; + +import java.util.*; + +public class ASTBuilder extends MontyBaseVisitor { + private final String fileName; + private Stack currentBlocks; + private VariableDeclaration.DeclarationType currentVariableContext; + private ProcedureDeclaration.DeclarationType currentProcedureContext; + + public ASTBuilder(String fileName) { + this.fileName = fileName; + currentBlocks = new Stack<>(); + } + + private Position position(Token idSymbol) { + return new Position(fileName, idSymbol.getLine(), idSymbol.getCharPositionInLine()); + } + + private String getText(TerminalNode identifier) { + return identifier.getSymbol().getText(); + } + + @Override + public ASTNode visitModuleDeclaration(@NotNull MontyParser.ModuleDeclarationContext ctx) { + Block block = new Block(position(ctx.getStart())); + ModuleDeclaration module = + new ModuleDeclaration(position(ctx.getStart()), new Identifier(FilenameUtils.getBaseName(fileName)), + block, new ArrayList()); + currentBlocks.push(block); + + for (MontyParser.ImportLineContext imp : ctx.importLine()) { + + module.getImports().add( + new Import(position(imp.getStart()), new ResolvableIdentifier(getText(imp.Identifier())))); + } + + for (ClassDeclarationContext classDeclarationContext : ctx.classDeclaration()) { + ClassDeclaration classDecl = (ClassDeclaration) visit(classDeclarationContext); + block.addDeclaration(classDecl); + } + addStatementsToBlock(block, ctx.statement()); + currentBlocks.pop(); + return module; + } + + @Override + public ASTNode visitAssignment(@NotNull AssignmentContext ctx) { + Assignment assignment = + new Assignment(position(ctx.getStart()), (Expression) visit(ctx.left), (Expression) visit(ctx.right)); + return assignment; + } + + @Override + public ASTNode visitCompoundAssignment(CompoundAssignmentContext ctx) { + Expression expr = + binaryExpression( + position(ctx.getStart()), + ctx.compoundSymbol().operator.getText().substring(0, 1), + ctx.left, + ctx.right); + + return new Assignment(position(ctx.getStart()), (Expression) visit(ctx.left), expr); + } + + @Override + public ASTNode visitVariableDeclaration(@NotNull VariableDeclarationContext ctx) { + String typeName = ctx.type().ClassIdentifier().toString(); + ResolvableIdentifier type = new ResolvableIdentifier(typeName); + return new VariableDeclaration(position(ctx.getStart()), new Identifier(getText(ctx.Identifier())), type, + currentVariableContext); + } + + @Override + public ASTNode visitFunctionCall(FunctionCallContext ctx) { + ArrayList arguments = new ArrayList<>(); + String identifier; + if (ctx.Identifier() == null) { + identifier = ctx.ClassIdentifier().getText(); + } else { + identifier = ctx.Identifier().getText(); + } + FunctionCall func = new FunctionCall(position(ctx.getStart()), new ResolvableIdentifier(identifier), arguments); + if (ctx.expressionList() != null) { + for (ExpressionContext exprC : ctx.expressionList().expression()) { + + ASTNode expr = visit(exprC); + if (expr instanceof Expression) { + + arguments.add((Expression) expr); + } + } + } + return func; + } + + private void buildDefaultProcedures(boolean functionDeclaration, List defaultParameter, + List allVariableDeclarations, List params, + List defaultExpression, List defaultVariableDeclaration, + Identifier identifier, Token token, TypeContext typeContext, DeclarationType declarationTypeCopy) { + + for (int defaultParameterIdx = 0; defaultParameterIdx < defaultParameter.size(); defaultParameterIdx++) { + Block block = new Block(position(token)); + List l = new ArrayList<>(); + for (int variableDeclarationIdy = 0; variableDeclarationIdy < allVariableDeclarations.size(); variableDeclarationIdy++) { + if (variableDeclarationIdy >= params.size() + defaultParameterIdx) { + l.add(defaultExpression.get(variableDeclarationIdy - params.size())); + } else if (variableDeclarationIdy < params.size()) { + l.add(new VariableAccess(position(token), new ResolvableIdentifier(params.get( + variableDeclarationIdy).getIdentifier().getSymbol()))); + } else { + VariableDeclaration variableDeclaration = + defaultVariableDeclaration.get(variableDeclarationIdy - params.size()); + l.add(new VariableAccess(position(token), new ResolvableIdentifier( + variableDeclaration.getIdentifier().getSymbol()))); + } + } + + List subParams = + allVariableDeclarations.subList(0, params.size() + defaultParameterIdx); + + Expression expression = + new FunctionCall(position(token), new ResolvableIdentifier(identifier.getSymbol()), l); + + if (declarationTypeCopy == ProcedureDeclaration.DeclarationType.METHOD) { + expression = new MemberAccess(position(token), new SelfExpression(position(token)), expression); + } + + ProcedureDeclaration procDecl1; + if (functionDeclaration) { + block.addStatement(new ReturnStatement(new Position(), expression)); + procDecl1 = + new FunctionDeclaration(position(token), identifier, block, subParams, declarationTypeCopy, + new ResolvableIdentifier(typeContext.ClassIdentifier().getText())); + } else { + block.addStatement((Statement) expression); + block.addStatement(new ReturnStatement(new Position(), null)); + procDecl1 = + new ProcedureDeclaration(position(token), identifier, block, subParams, declarationTypeCopy); + } + currentBlocks.peek().addDeclaration(procDecl1); + } + } + + private ProcedureDeclaration buildProcedures(boolean functionDeclaration, + ParameterListContext parameterListContext, Token token, TypeContext typeContext, + StatementBlockContext statementBlockContext, Identifier identifier) { + + ProcedureDeclaration.DeclarationType declarationTypeCopy = currentProcedureContext; + List params = parameterListToVarDeclList(parameterListContext); + List defaultParameter = defaultParameterListToVarDeclList(parameterListContext); + + List defaultVariableDeclaration = new ArrayList<>(); + List defaultExpression = new ArrayList<>(); + for (DefaultParameterContext context : defaultParameter) { + defaultVariableDeclaration.add((VariableDeclaration) visit(context.variableDeclaration())); + defaultExpression.add((Expression) visit(context.expression())); + } + + List allVariableDeclarations = new ArrayList<>(); + allVariableDeclarations.addAll(params); + allVariableDeclarations.addAll(defaultVariableDeclaration); + + buildDefaultProcedures( + functionDeclaration, + defaultParameter, + allVariableDeclarations, + params, + defaultExpression, + defaultVariableDeclaration, + identifier, + token, + typeContext, + declarationTypeCopy); + + ProcedureDeclaration procDecl2; + + if (functionDeclaration) { + procDecl2 = + new FunctionDeclaration(position(token), identifier, (Block) visit(statementBlockContext), + allVariableDeclarations, declarationTypeCopy, new ResolvableIdentifier( + typeContext.ClassIdentifier().getText())); + } else { + procDecl2 = + new ProcedureDeclaration(position(token), identifier, (Block) visit(statementBlockContext), + allVariableDeclarations, declarationTypeCopy); + } + return procDecl2; + } + + @Override + public ASTNode visitFunctionDeclaration(FunctionDeclarationContext ctx) { + Identifier identifier; + if (ctx.binaryOperation() == null) { + identifier = new Identifier(getText(ctx.Identifier())); + } else { + identifier = new Identifier("operator" + ctx.binaryOperation().getText()); + } + + return buildProcedures(true, ctx.parameterList(), ctx.getStart(), ctx.type(), ctx.statementBlock(), identifier); + } + + @Override + public ASTNode visitClassDeclaration(ClassDeclarationContext ctx) { + List superClasses = new ArrayList<>(); + if (ctx.typeList() != null) { + for (TypeContext type : ctx.typeList().type()) { + superClasses.add(new ResolvableIdentifier(type.ClassIdentifier().getText())); + } + } + ClassDeclaration cl = + new ClassDeclaration(position(ctx.getStart()), new Identifier(ctx.ClassIdentifier().getText()), + superClasses, new Block(position(ctx.getStart()))); + + currentBlocks.push(cl.getBlock()); + for (MemberDeclarationContext member : ctx.memberDeclaration()) { + currentVariableContext = VariableDeclaration.DeclarationType.ATTRIBUTE; + currentProcedureContext = ProcedureDeclaration.DeclarationType.METHOD; + ASTNode astNode = visit(member); + if (astNode instanceof Declaration) { + + Declaration decl = (Declaration) astNode; + decl.setAccessModifier(AccessModifier.stringToAccess(member.accessModifier().modifier.getText())); + cl.getBlock().addDeclaration(decl); + } else if (astNode instanceof Assignment) { + + Assignment asgnmnt = + new Assignment(astNode.getPosition(), new MemberAccess(astNode.getPosition(), + new SelfExpression(new Position()), ((Assignment) astNode).getLeft()), + ((Assignment) astNode).getRight()); + cl.getBlock().addStatement(asgnmnt); + } + } + currentBlocks.pop(); + return cl; + } + + @Override + public ASTNode visitProcedureDeclaration(ProcedureDeclarationContext ctx) { + ProcedureDeclaration proc = + buildProcedures(false, ctx.parameterList(), ctx.start, null, ctx.statementBlock(), new Identifier( + getText(ctx.Identifier()))); + + List list = proc.getBody().getStatements(); + if ((list.isEmpty()) || !(list.get(list.size() - 1) instanceof ReturnStatement)) { + list.add(new ReturnStatement(new Position(), null)); + } + return proc; + } + + private List parameterListToVarDeclList(ParameterListContext parameter) { + if (parameter == null) { + return new ArrayList<>(); + } + ArrayList parameterList = new ArrayList<>(); + currentVariableContext = VariableDeclaration.DeclarationType.PARAMETER; + for (VariableDeclarationContext var : parameter.variableDeclaration()) { + parameterList.add((VariableDeclaration) visit(var)); + } + return parameterList; + } + + private List defaultParameterListToVarDeclList(ParameterListContext parameter) { + if (parameter == null) { + return new ArrayList<>(); + } + currentVariableContext = VariableDeclaration.DeclarationType.PARAMETER; + return parameter.defaultParameter(); + } + + @Override + public ASTNode visitWhileStatement(WhileStatementContext ctx) { + ASTNode expr = visit(ctx.expression()); + if (!(expr instanceof Expression)) { + + return null; + } + + WhileLoop loop = + new WhileLoop(position(ctx.getStart()), (Expression) expr, (Block) visit(ctx.statementBlock())); + + return loop; + } + + @Override + public ASTNode visitIfStatement(IfStatementContext ctx) { + + Block leastElseBlock = new Block(new Position()); + if (ctx.elseBlock != null) { + leastElseBlock = (Block) visit(ctx.elseBlock); + } + Block firstElseBlock; + + if (ctx.elif().isEmpty()) { + firstElseBlock = leastElseBlock; + } else { + + Block lastElseBlock = new Block(position(ctx.getStart())); + firstElseBlock = lastElseBlock; + Block currentElseBlock; + + for (int i = 0; i < ctx.elif().size(); i++) { + ElifContext currentCtx = ctx.elif(i); + + if (i == ctx.elif().size() - 1) { + currentElseBlock = leastElseBlock; + } else { + currentElseBlock = new Block(position(currentCtx.getStart())); + } + + lastElseBlock.addStatement(new ConditionalStatement(position(ctx.elif().get(i).getStart()), + (Expression) visit(currentCtx.elifCondition), (Block) visit(currentCtx.elifBlock), + currentElseBlock)); + lastElseBlock = currentElseBlock; + + } + } + return new ConditionalStatement(position(ctx.getStart()), (Expression) visit(ctx.ifCondition), + (Block) visit(ctx.thenBlock), firstElseBlock); + + } + + @Override + public ASTNode visitTryStatement(TryStatementContext ctx) { + ASTNode decl = visit(ctx.variableDeclaration().get(0)); + TryStatement tryStm = + new TryStatement(position(ctx.getStart()), (VariableDeclaration) decl, new Block( + position(ctx.getStart())), new Block(position(ctx.getStart()))); + addStatementsToBlock(tryStm.getTryBlock(), ctx.tryBlock.statement()); + addStatementsToBlock(tryStm.getHandleBlock(), ctx.handleBlock.statement()); + return tryStm; + } + + public void addStatementsToBlock(Block block, List statements) { + for (StatementContext stm : statements) { + currentVariableContext = VariableDeclaration.DeclarationType.VARIABLE; + currentProcedureContext = ProcedureDeclaration.DeclarationType.UNBOUND; + ASTNode node = visit(stm); + if (node instanceof Statement) { + block.addStatement((Statement) node); + } else { + block.addDeclaration((Declaration) node); + } + } + } + + @Override + public ASTNode visitIndependentDeclaration(IndependentDeclarationContext ctx) { + ASTNode node; + if (ctx.functionDeclaration() != null) { + node = visit(ctx.functionDeclaration()); + } else if (ctx.procedureDeclaration() != null) { + node = visit(ctx.procedureDeclaration()); + } else { + node = visit(ctx.variableDeclaration()); + if (ctx.expression() != null) { + currentBlocks.peek().addDeclaration((Declaration) node); + return new Assignment(position(ctx.getStart()), new VariableAccess(position(ctx.getStart()), + ResolvableIdentifier.convert(((VariableDeclaration) node).getIdentifier())), + (Expression) visit(ctx.expression())); + } + } + return node; + } + + @Override + public ASTNode visitStatementBlock(StatementBlockContext ctx) { + + Block block = new Block(position(ctx.getStart())); + currentBlocks.push(block); + addStatementsToBlock(block, ctx.statement()); + currentBlocks.pop(); + return block; + } + + @Override + public ASTNode visitReturnStm(ReturnStmContext ctx) { + ASTNode expr = null; + if (ctx.expression() != null) { + + expr = visit(ctx.expression()); + } + + return new ReturnStatement(position(ctx.getStart()), (Expression) expr); + } + + @Override + public ASTNode visitRaiseStm(RaiseStmContext ctx) { + ASTNode expr = null; + if (ctx.expression() != null) { + + expr = visit(ctx.expression()); + } + return new RaiseStatement(position(ctx.getStart()), (Expression) expr); + } + + @Override + public ASTNode visitBreakStm(BreakStmContext ctx) { + + return new BreakStatement(position(ctx.getStart())); + } + + @Override + public ASTNode visitSkipStm(SkipStmContext ctx) { + + return new SkipStatement(position(ctx.getStart())); + } + + @Override + public ASTNode visitExpression(ExpressionContext ctx) { + + if (ctx.primary() != null) { + return visit(ctx.primary()); + } else if (ctx.ifExpCondition != null && ctx.ifExprElse != null && ctx.ifExprThen != null) { + + return visitTernary(ctx); + } else if (ctx.functionCall() != null) { + + return visit(ctx.functionCall()); + } else if (ctx.array != null) { + List arguments = Arrays.asList((Expression) visit(ctx.array), (Expression) visit(ctx.index)); + return new FunctionCall(position(ctx.getStart()), new ResolvableIdentifier("operator[]"), arguments); + } else if (ctx.accessOperator() != null) { + + return visitMemberAccessExpr(ctx); + } else if (ctx.plusMinusOperator() != null && ctx.singleExpression != null) { + + return unaryExpression( + position(ctx.getStart()), + ctx.plusMinusOperator().operator.getText(), + ctx.singleExpression); + } else if (ctx.notOperator() != null) { + + return unaryExpression(position(ctx.getStart()), ctx.notOperator().operator.getText(), ctx.singleExpression); + } else if (ctx.powerOperator() != null) { + + return binaryExpression(position(ctx.getStart()), ctx.powerOperator().getText(), ctx.left, ctx.right); + } else if (ctx.dotOperator() != null) { + + return binaryExpression(position(ctx.getStart()), ctx.dotOperator().getText(), ctx.left, ctx.right); + } else if (ctx.plusMinusOperator() != null) { + + return binaryExpression(position(ctx.getStart()), ctx.plusMinusOperator().getText(), ctx.left, ctx.right); + } else if (ctx.compareOperator() != null) { + + return binaryExpression(position(ctx.getStart()), ctx.compareOperator().getText(), ctx.left, ctx.right); + } else if (ctx.eqOperator() != null) { + + return binaryExpression(position(ctx.getStart()), ctx.eqOperator().getText(), ctx.left, ctx.right); + } else if (ctx.inOperator() != null) { + + return binaryExpression(position(ctx.getStart()), ctx.inOperator().getText(), ctx.left, ctx.right); + } else if (ctx.andOperator() != null) { + + return binaryExpression(position(ctx.getStart()), ctx.andOperator().getText(), ctx.left, ctx.right); + } else if (ctx.orOperator() != null) { + + return binaryExpression(position(ctx.getStart()), ctx.orOperator().getText(), ctx.left, ctx.right); + } else if (ctx.asOperator() != null) { + return visitCastExpression(ctx); + } else if (ctx.isOperator() != null) { + return visitIsExpression(ctx); + } + return null; + } + + @Override + public ASTNode visitPrimary(PrimaryContext ctx) { + if (ctx.singleExpression != null) { + + return visit(ctx.singleExpression); + } else if (ctx.literal() != null) { + + return visit(ctx.literal()); + } else if (ctx.parent != null) { + + return visitParent(ctx); + } else if (ctx.Identifier() != null) { + + return visitIdentifier(ctx); + } else { + + return visitSelf(ctx); + } + } + + @Override + public ASTNode visitLiteral(LiteralContext ctx) { + + if (ctx.IntegerLiteral() != null) { + + return new IntegerLiteral(position(ctx.getStart()), + Integer.parseInt(ctx.IntegerLiteral().getSymbol().getText())); + } else if (ctx.RealLiteral() != null) { + + return new FloatLiteral(position(ctx.getStart()), Float.parseFloat(ctx.RealLiteral().getSymbol().getText())); + } else if (ctx.CharacterLiteral() != null) { + + return new CharacterLiteral(position(ctx.getStart()), + ctx.CharacterLiteral().getSymbol().getText().charAt(1)); + } else if (ctx.StringLiteral() != null) { + + return new StringLiteral(position(ctx.getStart()), ctx.StringLiteral().getSymbol().getText()); + } else if (ctx.arrayLiteral() != null) { + ArrayList elements = new ArrayList<>(); + for (ExpressionContext eContext : ctx.arrayLiteral().expression()) { + elements.add((Expression) visit(eContext)); + } + return new ArrayLiteral(position(ctx.getStart()), elements); + } else { + + return new BooleanLiteral(position(ctx.getStart()), Boolean.parseBoolean(ctx.BooleanLiteral().toString())); + } + } + + public ASTNode visitIdentifier(PrimaryContext ctx) { + + return new VariableAccess(position(ctx.getStart()), new ResolvableIdentifier(getText(ctx.Identifier()))); + } + + public ASTNode visitSelf(PrimaryContext ctx) { + + return new SelfExpression(position(ctx.getStart())); + } + + public ParentExpression visitParent(PrimaryContext ctx) { + return new ParentExpression(position(ctx.getStart()), new ResolvableIdentifier(getText(ctx.ClassIdentifier()))); + } + + public ASTNode visitTernary(ExpressionContext ctx) { + ASTNode condition = visit(ctx.ifExpCondition); + ASTNode thenExpr = visit(ctx.ifExprThen); + ASTNode elseExpr = visit(ctx.ifExprElse); + return new ConditionalExpression(position(ctx.getStart()), (Expression) condition, (Expression) thenExpr, + (Expression) elseExpr); + } + + @Override + public ASTNode visitMemberAccessStmt(@NotNull MemberAccessStmtContext ctx) { + ASTNode left = visit(ctx.left); + ASTNode right = visit(ctx.right); + return new MemberAccess(position(ctx.getStart()), (Expression) left, (Expression) right); + } + + public ASTNode visitMemberAccessExpr(ExpressionContext ctx) { + ASTNode left = visit(ctx.left); + ASTNode right = visit(ctx.right); + return new MemberAccess(position(ctx.getStart()), (Expression) left, (Expression) right); + } + + private MemberAccess unaryExpression(Position position, String operator, ExpressionContext expr) { + String underscore = ""; + if (operator.equals("not")) { + underscore = "_"; + } + Expression self = (Expression) visit(expr); + FunctionCall operatorCall = + new FunctionCall(position, new ResolvableIdentifier("operator" + underscore + operator), + new ArrayList()); + return new MemberAccess(position, self, operatorCall); + } + + private MemberAccess binaryExpression(Position position, String operator, ExpressionContext left, + ExpressionContext right) { + String underscore = ""; + List needsUnderscore = Arrays.asList("and", "or", "xor", "in"); + if (needsUnderscore.contains(operator)) { + underscore = "_"; + } + Expression self = (Expression) visit(left); + FunctionCall operatorCall = + new FunctionCall(position, new ResolvableIdentifier("operator" + underscore + operator), + Arrays.asList((Expression) visit(right))); + return new MemberAccess(position, self, operatorCall); + } + + private CastExpression visitCastExpression(ExpressionContext ctx) { + return new CastExpression(position(ctx.getStart()), (Expression) visit(ctx.expr), new ResolvableIdentifier( + getText(ctx.ClassIdentifier()))); + } + + private IsExpression visitIsExpression(ExpressionContext ctx) { + return new IsExpression(position(ctx.getStart()), (Expression) visit(ctx.expr), new ResolvableIdentifier( + getText(ctx.ClassIdentifier()))); + } + + protected ASTNode aggregateResult(ASTNode aggregate, ASTNode nextResult) { + return nextResult == null ? aggregate : nextResult; + } +} diff --git a/src/main/java/de/uni/bremen/monty/moco/ast/ASTNode.java b/src/main/java/de/uni/bremen/monty/moco/ast/ASTNode.java new file mode 100644 index 0000000..1ebb824 --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/ast/ASTNode.java @@ -0,0 +1,77 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.ast; + +import de.uni.bremen.monty.moco.visitor.BaseVisitor; + +public interface ASTNode { + + ASTNode getParentNode(); + + void setParentNode(ASTNode parentNode); + + Position getPosition(); + + void setScope(Scope scope); + + Scope getScope(); + + /** Visit this node using double-dispatch. + *

+ * This method is only called from within the BaseVisitor. Every actual subclass must implement this method with the + * following body: + * + *

+	 * {@code visitor.visit(this);}
+	 * 
. + * + * @param visitor + * the visitor to visit this node */ + void visit(BaseVisitor visitor); + + /** Comfort method to visit all children. + *

+ * Can be used from any visitor if the traversal order does not matter. The BaseVisitor uses this method by default. @ + * param visitor the visitor to viit this node + * + * @param visitor + * the visitor to visit this node */ + void visitChildren(BaseVisitor visitor); + +} diff --git a/src/main/java/de/uni/bremen/monty/moco/ast/AccessModifier.java b/src/main/java/de/uni/bremen/monty/moco/ast/AccessModifier.java new file mode 100644 index 0000000..2341483 --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/ast/AccessModifier.java @@ -0,0 +1,62 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.ast; + +public enum AccessModifier { + + PUBLIC, PRIVATE, PROTECTED, PACKAGE; + + public static AccessModifier stringToAccess(String AccessStr) { + + switch (AccessStr) { + + case "+": + return AccessModifier.PUBLIC; + case "-": + return AccessModifier.PRIVATE; + case "#": + return AccessModifier.PROTECTED; + case "~": + return AccessModifier.PACKAGE; + default: + return AccessModifier.PUBLIC; + } + } + +} diff --git a/src/main/java/de/uni/bremen/monty/moco/ast/AntlrAdapter.java b/src/main/java/de/uni/bremen/monty/moco/ast/AntlrAdapter.java new file mode 100644 index 0000000..370340d --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/ast/AntlrAdapter.java @@ -0,0 +1,78 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ + +package de.uni.bremen.monty.moco.ast; + +import de.uni.bremen.monty.moco.antlr.MontyLexer; +import de.uni.bremen.monty.moco.antlr.MontyParser; +import de.uni.bremen.monty.moco.ast.declaration.ModuleDeclaration; +import org.antlr.v4.runtime.ANTLRInputStream; +import org.antlr.v4.runtime.CommonTokenStream; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.SequenceInputStream; + +public class AntlrAdapter { + + public MontyParser createParser(final InputStream file) throws IOException { + + InputStream in = createInputStream(file); + + // the additional line-break is needed because of our indentation rule + // and the fact that a statement should be terminated by a line break + ANTLRInputStream input = new ANTLRInputStream(in); + MontyLexer lexer = new MontyLexer(input); + CommonTokenStream tokens = new CommonTokenStream(lexer); + return new MontyParser(tokens); + } + + private InputStream createInputStream(InputStream file) { + return new SequenceInputStream(file, new ByteArrayInputStream("\n".getBytes())); + } + + public ModuleDeclaration parse(InputStream file, String fileName) throws IOException { + MontyParser parser = createParser(file); + + ASTBuilder astBuilder = new ASTBuilder(fileName); + ASTNode moduleNode = astBuilder.visit(parser.compilationUnit()); + return (ModuleDeclaration) moduleNode; + } +} diff --git a/src/main/java/de/uni/bremen/monty/moco/ast/BasicASTNode.java b/src/main/java/de/uni/bremen/monty/moco/ast/BasicASTNode.java new file mode 100644 index 0000000..74a5ce3 --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/ast/BasicASTNode.java @@ -0,0 +1,109 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.ast; + +/** Baseclass for every node in the AST. */ +public abstract class BasicASTNode implements ASTNode { + + /** Sourcecode position of this node. */ + private final Position position; + + /** Parent node. */ + private ASTNode parentNode; + + /** Associated scope. */ + private Scope scope; + + /** Constructor. + * + * @param position + * Position of this node */ + public BasicASTNode(Position position) { + this.position = position; + } + + /** {@inheritDoc} */ + @Override + public String toString() { + return getClass().getSimpleName(); + } + + /** Get parent node. + * + * @return the parent node */ + @Override + public ASTNode getParentNode() { + return parentNode; + } + + /** Set parent node. + * + * @param parentNode + * the parent node */ + @Override + public void setParentNode(ASTNode parentNode) { + this.parentNode = parentNode; + } + + /** Get the sourcecode position. + * + * @return the position */ + @Override + public Position getPosition() { + return position; + } + + /** Set the associated scope. + * + * @param scope + * the associated scope */ + @Override + public void setScope(Scope scope) { + this.scope = scope; + } + + /** Get the accociated scope. + * + * @return the scope */ + @Override + public Scope getScope() { + return scope; + } + +} diff --git a/src/main/java/de/uni/bremen/monty/moco/ast/Block.java b/src/main/java/de/uni/bremen/monty/moco/ast/Block.java new file mode 100644 index 0000000..9948137 --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/ast/Block.java @@ -0,0 +1,119 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.ast; + +import java.util.*; + +import de.uni.bremen.monty.moco.ast.declaration.Declaration; +import de.uni.bremen.monty.moco.ast.statement.Statement; +import de.uni.bremen.monty.moco.visitor.BaseVisitor; + +/** This node represents a block. + * + * A block contains declarations and statements. The declarations must be processed first. */ +public class Block extends BasicASTNode { + + /** The statements. */ + private final List statements; + + /** The declarations. */ + private final List declarations; + + /** Constructor. + * + * @param position + * Position of this node */ + public Block(Position position) { + super(position); + statements = new ArrayList(); + declarations = new ArrayList(); + } + + /** @return true if the block does not have any statements or declarations. */ + public boolean isEmpty() { + return statements.isEmpty() && declarations.isEmpty(); + } + + /** Add a statement to this block. + * + * @param statement + * the statement to add */ + public void addStatement(Statement statement) { + statements.add(statement); + } + + /** Add a declaration to this block. + * + * @param declaration + * the declaration to add */ + public void addDeclaration(Declaration declaration) { + declarations.add(declaration); + } + + /** Get the statements of this block. + * + * @return the statements */ + public List getStatements() { + return statements; + } + + /** Get the declarations of this block. + * + * @return the declarations */ + public List getDeclarations() { + return declarations; + } + + /** {@inheritDoc} */ + @Override + public void visit(BaseVisitor visitor) { + visitor.visit(this); + } + + /** {@inheritDoc} */ + @Override + public void visitChildren(BaseVisitor visitor) { + for (Declaration declaration : declarations) { + visitor.visitDoubleDispatched(declaration); + } + for (Statement statement : statements) { + visitor.visitDoubleDispatched(statement); + } + } +} diff --git a/src/main/java/de/uni/bremen/monty/moco/ast/ClassScope.java b/src/main/java/de/uni/bremen/monty/moco/ast/ClassScope.java new file mode 100644 index 0000000..69b256a --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/ast/ClassScope.java @@ -0,0 +1,159 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.ast; + +import de.uni.bremen.monty.moco.ast.declaration.*; +import de.uni.bremen.monty.moco.exception.*; +import java.util.List; +import java.util.ArrayList; + +/** A scope in which identifier are associated with declarations. + *

+ * To nest scopes or build a stack the parent scope is passed as an argument to the construtor. So you use it like this + *

+ * + *

+ * {@code
+ * // create a new scope and nest the old one
+ * currentScope = new ClassScope(currentScope);
+ * // do something
+ * // destroy this scope and use the old (nested) one
+ * currentScope = currentScope.getParentScope();
+ * }
+ * 
+ *

+ * This special scope searches its associations, the parent classes in inheritance hierachy and only then the parent + * scope. + *

+ * Note: only single inheritance so far. */ +public class ClassScope extends Scope { + + /** The parent class in inheritance hierachy. */ + private List parentClassesScopes; + + /** Constructor. + * + * @param parent + * the parent scope in nesting hierachy */ + public ClassScope(Scope parent) { + super(parent); + this.parentClassesScopes = new ArrayList<>(); + } + + public void addParentClassScope(ClassScope scope) { + parentClassesScopes.add(scope); + } + + /** Resolve an identifier in inherited scopes. + * + * @param identifier + * the identifier + * @return the declaration or null if nothing is found */ + protected Declaration resolveMember(ResolvableIdentifier identifier) { + Declaration declaration = members.get(identifier); + + if (declaration != null) { + return declaration; + } + for (ClassScope scope : parentClassesScopes) { + declaration = scope.resolveMember(identifier); + if (declaration != null) { + return declaration; + } + } + return null; + } + + /** Resolve an identifier for list of overloaded procedures or functions in inherited scope. + * + * @param identifier + * the identifier to resolve + * @return the list of procedure declarations */ + protected List resolveProcedureMember(ResolvableIdentifier identifier) { + List result = new ArrayList(); + + if (procedures.containsKey(identifier)) { + result.addAll(procedures.get(identifier)); + } + for (ClassScope scope : parentClassesScopes) { + result.addAll(scope.resolveProcedureMember(identifier)); + } + return result; + } + + /** Resolve an identifier for a declaration + *

+ * It first searches its associations, the parent classes in inheritance hierachy and only then the parent scope. + * + * @param identifier + * the identifier to resolve + * @return the declaration or null if nothing is found */ + @Override + public Declaration resolve(ResolvableIdentifier identifier) { + Declaration declaration = resolveMember(identifier); + + if (declaration != null) { + return declaration; + } + return super.resolve(identifier); + } + + /** Resolve an identifier for list of overloaded procedures or functions. + *

+ * It first searches its associations, the parent classes in inheritance hierachy and only then the parent scope. + * + * @param identifier + * the identifier to resolve + * @return the list of procedure declarations */ + @Override + public List resolveProcedure(ResolvableIdentifier identifier) { + List result = new ArrayList(); + result.addAll(resolveProcedureMember(identifier)); + if (parent != null) { + try { + result.addAll(parent.resolveProcedure(identifier)); + } catch (UnknownIdentifierException e) { + } + } + if (result.isEmpty()) { + throw new UnknownIdentifierException(identifier); + } + return result; + } +} diff --git a/src/main/java/de/uni/bremen/monty/moco/ast/CoreClasses.java b/src/main/java/de/uni/bremen/monty/moco/ast/CoreClasses.java new file mode 100644 index 0000000..71ed950 --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/ast/CoreClasses.java @@ -0,0 +1,102 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ + +package de.uni.bremen.monty.moco.ast; + +import de.uni.bremen.monty.moco.ast.declaration.ClassDeclaration; + +import java.util.Map; +import java.util.HashMap; +import java.util.Collection; +import java.util.Collections; + +public class CoreClasses { + + private static Map coreClasses = new HashMap(); + + static { + // TODO find name for void that is not a valid identifier + String[] classNames = new String[] { "Object", "Char", "String", "Int", "Float", "Bool", "Array", "__void" }; + for (String name : classNames) { + CoreClasses.setCoreClass(name, new ClassDeclaration(new Position("Dummy_" + name, 0, 0), new Identifier( + name), Collections. emptyList(), new Block( + new Position("Dummy_" + name, 1, 0)))); + } + } + + public static Collection getAllCoreClasses() { + return coreClasses.values(); + } + + public static void setCoreClass(String name, ClassDeclaration classDeclaration) { + coreClasses.put(name, classDeclaration); + } + + public static ClassDeclaration objectType() { + return coreClasses.get("Object"); + } + + public static ClassDeclaration charType() { + return coreClasses.get("Char"); + } + + public static ClassDeclaration stringType() { + return coreClasses.get("String"); + } + + public static ClassDeclaration intType() { + return coreClasses.get("Int"); + } + + public static ClassDeclaration floatType() { + return coreClasses.get("Float"); + } + + public static ClassDeclaration boolType() { + return coreClasses.get("Bool"); + } + + public static ClassDeclaration arrayType() { + return coreClasses.get("Array"); + } + + public static ClassDeclaration voidType() { + return coreClasses.get("__void"); + } +} diff --git a/src/main/java/de/uni/bremen/monty/moco/ast/Identifier.java b/src/main/java/de/uni/bremen/monty/moco/ast/Identifier.java new file mode 100644 index 0000000..f3de556 --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/ast/Identifier.java @@ -0,0 +1,93 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.ast; + +/** An Identifier is the user defined name of a declaration. + *

+ * During context-analysis the identifier with an associated declaration is stored in a scope. */ +public class Identifier { + + /** The name of the declaration. */ + private final String symbol; + + /** Constructor. + * + * @param symbol + * the name of the declaration */ + public Identifier(String symbol) { + this.symbol = symbol; + } + + /** Get the name of the declaration. + * + * @return the name */ + public String getSymbol() { + return symbol; + } + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } else if (other == null) { + return false; + } + + if (other instanceof Identifier) { + Identifier that = (Identifier) other; + return getSymbol().equals(that.getSymbol()); + } + + return false; + } + + @Override + public int hashCode() { + return symbol.hashCode(); + } + + @Override + public String toString() { + return symbol; + } + + public static Identifier convert(ResolvableIdentifier identifier) { + return new Identifier(identifier.getSymbol()); + } +} diff --git a/src/main/java/de/uni/bremen/monty/moco/ast/Import.java b/src/main/java/de/uni/bremen/monty/moco/ast/Import.java new file mode 100644 index 0000000..2ae0a3a --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/ast/Import.java @@ -0,0 +1,70 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.ast; + +import de.uni.bremen.monty.moco.visitor.BaseVisitor; + +/** Represent the imported modules. */ +public class Import extends BasicASTNode { + + /** The identifier of the importline */ + private ResolvableIdentifier identifier; + + /** Constructor. + * + * @param position + * Position of this node */ + public Import(Position position, ResolvableIdentifier identifier) { + super(position); + this.identifier = identifier; + } + + /** {@inheritDoc} */ + @Override + public void visit(BaseVisitor visitor) { + visitor.visit(this); + } + + /** {@inheritDoc} */ + @Override + public void visitChildren(BaseVisitor visitor) { + // throw new NotYetImplementedException(); + } + +} diff --git a/src/main/java/de/uni/bremen/monty/moco/ast/Package.java b/src/main/java/de/uni/bremen/monty/moco/ast/Package.java new file mode 100644 index 0000000..3ccb27c --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/ast/Package.java @@ -0,0 +1,109 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ + +package de.uni.bremen.monty.moco.ast; + +import de.uni.bremen.monty.moco.ast.declaration.ModuleDeclaration; +import de.uni.bremen.monty.moco.visitor.BaseVisitor; + +import java.util.ArrayList; +import java.util.List; + +public class Package extends BasicASTNode { + + private Identifier name; + + private List modules; + private List subPackages; + private boolean nativePackage = false; + + /** Constructor. + * + * @param name */ + public Package(Identifier name) { + super(new Position()); + this.name = name; + modules = new ArrayList<>(); + subPackages = new ArrayList<>(); + } + + @Override + public void visit(BaseVisitor visitor) { + visitor.visit(this); + } + + @Override + public void visitChildren(BaseVisitor visitor) { + for (Package subPackage : subPackages) { + visitor.visit(subPackage); + } + for (ModuleDeclaration module : modules) { + visitor.visit(module); + } + } + + public void addModule(ModuleDeclaration module) { + modules.add(module); + } + + public void addSubPackage(Package aPackage) { + subPackages.add(aPackage); + } + + public List getModules() { + return modules; + } + + public List getModulesRecursive() { + List allModules = new ArrayList<>(); + allModules.addAll(modules); + for (Package subPackage : subPackages) { + allModules.addAll(subPackage.getModulesRecursive()); + } + return allModules; + } + + public boolean isNativePackage() { + return nativePackage; + } + + public void setNativePackage(boolean nativePackage) { + this.nativePackage = nativePackage; + } +} diff --git a/src/main/java/de/uni/bremen/monty/moco/ast/PackageBuilder.java b/src/main/java/de/uni/bremen/monty/moco/ast/PackageBuilder.java new file mode 100644 index 0000000..31615b9 --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/ast/PackageBuilder.java @@ -0,0 +1,157 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ + +package de.uni.bremen.monty.moco.ast; + +import de.uni.bremen.monty.moco.ast.declaration.*; +import de.uni.bremen.monty.moco.util.MontyFile; +import de.uni.bremen.monty.moco.util.MontyJar; +import de.uni.bremen.monty.moco.util.MontyResource; +import de.uni.bremen.monty.moco.util.Params; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.Collections; + +public class PackageBuilder { + private final AntlrAdapter antlrAdapter; + private Params params; + + public PackageBuilder(Params params) { + this.params = params; + antlrAdapter = new AntlrAdapter(); + } + + public Package buildPackage() throws IOException { + Package basePackage = new Package(new Identifier("")); + String inputFile = params.getInputFile(); + if (inputFile != null) { + basePackage.addSubPackage(createPackageFromSingleModule(inputFile)); + } else { + basePackage.addSubPackage(createPackageFromSourceFolder(params)); + } + addCoreLib(basePackage); + return basePackage; + } + + private void addCoreLib(Package basePackage) throws IOException { + Package corePackage = createPackage(getCoreLibFolder()); + corePackage.setNativePackage(true); + basePackage.addSubPackage(corePackage); + + Block block = new Block(new Position()); + ModuleDeclaration module = + new ModuleDeclaration(new Position(), new Identifier("CoreClasses"), block, + Collections. emptyList()); + block.addDeclaration(CoreClasses.stringType()); + block.addDeclaration(CoreClasses.arrayType()); + block.addDeclaration(CoreClasses.voidType()); + corePackage.addModule(module); + setCoreClasses(corePackage); + } + + private void setCoreClasses(Package corePackage) { + for (ModuleDeclaration module : corePackage.getModulesRecursive()) { + for (Declaration declaration : module.getBlock().getDeclarations()) { + if (declaration instanceof ClassDeclaration) { + ClassDeclaration classDeclaration = (ClassDeclaration) declaration; + CoreClasses.setCoreClass(classDeclaration.getIdentifier().getSymbol(), classDeclaration); + } + } + } + } + + private MontyResource getCoreLibFolder() { + try { + Class aClass = PackageBuilder.class; + ClassLoader classLoader = aClass.getClassLoader(); + URL testProgramFolder = classLoader.getResource("corelib/"); + if (testProgramFolder.toString().startsWith("jar:")) { + return new MontyJar(testProgramFolder); + } else { + return new MontyFile(testProgramFolder.toURI()); + } + } catch (URISyntaxException e) { + throw new RuntimeException(e); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private Package createPackageFromSourceFolder(Params params) throws IOException { + String baseFolder = params.getInputFolder(); + MontyResource inputFolder = new MontyFile(baseFolder); + return createPackage(inputFolder); + } + + private Package createPackageFromSingleModule(String inputFile) throws IOException { + MontyResource file = new MontyFile(inputFile); + + Package mainPackage = new Package(new Identifier("")); + addModules(new MontyResource[] { file }, mainPackage); + return mainPackage; + } + + private Package createPackage(MontyResource inputFolder) throws IOException { + MontyResource[] montyFiles = inputFolder.listSubModules(); + return createPackage(inputFolder, montyFiles); + } + + private Package createPackage(MontyResource inputFolder, MontyResource[] montyFiles) throws IOException { + Package mainPackage = new Package(new Identifier(inputFolder.getName())); + addModules(montyFiles, mainPackage); + addSubPackages(inputFolder, mainPackage); + return mainPackage; + } + + private void addModules(MontyResource[] montyFiles, Package aPackage) throws IOException { + for (MontyResource file : montyFiles) { + ModuleDeclaration module = antlrAdapter.parse(file.toInputStream(), file.getName()); + aPackage.addModule(module); + } + } + + private void addSubPackages(MontyResource inputFolder, Package mainPackage) throws IOException { + MontyResource[] subPackages = inputFolder.listSubPackages(); + for (MontyResource subPackage : subPackages) { + mainPackage.addSubPackage(createPackage(subPackage)); + } + } +} diff --git a/src/main/java/de/uni/bremen/monty/moco/ast/Position.java b/src/main/java/de/uni/bremen/monty/moco/ast/Position.java new file mode 100644 index 0000000..48fe8c6 --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/ast/Position.java @@ -0,0 +1,96 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.ast; + +/** Represents a position in the source code. */ +public class Position { + + /** The source file name. */ + private String fileName = ""; + + /** The source file line number. */ + private int lineNumber = 0; + + /** The source file char number. */ + private int charNumber = 0; + + /** Default constructor. */ + public Position() { + + } + + /** Constructor. + * + * @param fileName + * the source file name + * @param lineNumber + * the source file line number + * @param charNumber + * the source file char number */ + public Position(String fileName, int lineNumber, int charNumber) { + this.fileName = fileName; + this.lineNumber = lineNumber; + this.charNumber = charNumber; + } + + public String toString() { + return String.format("file: %s, line: %d, char: %d", fileName, lineNumber, charNumber); + } + + /** Get the source file name. + * + * @return the source file name */ + public String getFileName() { + return fileName; + } + + /** Get the source file line number. + * + * @return the souce file line number */ + public int getLineNumber() { + return lineNumber; + } + + /** Get the source file char number. + * + * @return the source file char number */ + public int getCharNumber() { + return charNumber; + } +} diff --git a/src/main/java/de/uni/bremen/monty/moco/ast/ResolvableIdentifier.java b/src/main/java/de/uni/bremen/monty/moco/ast/ResolvableIdentifier.java new file mode 100644 index 0000000..bd43f14 --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/ast/ResolvableIdentifier.java @@ -0,0 +1,57 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.ast; + +/** A ResolvableIdentifier is similar to the Identifier a name of a declaration. + *

+ * During context-analysis this is resolved to a declaration using a scope. */ +public class ResolvableIdentifier extends Identifier { + + /** Constructor. + * + * @param symbol + * the name of the declaration */ + public ResolvableIdentifier(String symbol) { + super(symbol); + } + + public static ResolvableIdentifier convert(Identifier identifier) { + return new ResolvableIdentifier(identifier.getSymbol()); + } +} diff --git a/src/main/java/de/uni/bremen/monty/moco/ast/Scope.java b/src/main/java/de/uni/bremen/monty/moco/ast/Scope.java new file mode 100644 index 0000000..9ceb4e1 --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/ast/Scope.java @@ -0,0 +1,202 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.ast; + +import java.util.*; + +import de.uni.bremen.monty.moco.ast.declaration.*; +import de.uni.bremen.monty.moco.exception.*; + +/** A scope in which an identifier is associated with a declaration. + *

+ * To nest scopes or build a stack the parent scope is passed as an argument to the constructor. So you use it like + * this: + *

+ * + *

+ * {@code
+ * // create a new scope and nest the old one
+ * currentScope = new Scope(currentScope);
+ * // do something
+ * // destroy this scope and use the old (nested) one
+ * currentScope = currentScope.getParentScope();
+ * }
+ * 
*/ +public class Scope { + + /** The parent scope in nesting hierarchy. */ + protected Scope parent; + + /** The map to store the associations to procedure declarations. */ + protected Map> procedures; + + /** The map to store the remaining associations. */ + protected Map members; + + /** Constructor. + * + * @param parent + * the parent scope in nesting hierarchy */ + public Scope(Scope parent) { + this.parent = parent; + procedures = new HashMap>(); + members = new HashMap(); + } + + /** Get the parent scope in nesting hierarchy. + *

+ * This method acts as the 'pop()'-operation in the scope-stack analogy. + * + * @return the parent scope */ + public Scope getParentScope() { + return parent; + } + + /** Resolve an identifier for a declaration. + *

+ * First the declarations of this scope are searched. If the not successful the search continues recursively in the + * parent scope. + * + * @param identifier + * the identifier to resolve + * @return the declaration */ + public Declaration resolve(ResolvableIdentifier identifier) { + Declaration declaration = members.get(identifier); + + if (declaration != null) { + return declaration; + } + if (parent != null) { + return parent.resolve(identifier); + } + throw new UnknownIdentifierException(identifier); + } + + /** Resolve an identifier for a type declaration. + * + * @param identifier + * the identifier to resolve + * @return the declaration */ + public TypeDeclaration resolveType(ResolvableIdentifier identifier) { + try { + Declaration declaration = resolve(identifier); + if (declaration instanceof TypeDeclaration) { + return (TypeDeclaration) declaration; + } + throw new UnknownTypeException(identifier); + } catch (UnknownIdentifierException e) { + throw new UnknownTypeException(identifier); + } + } + + /** Resolve an identifier for list of overloaded procedures or functions. + * + * @param identifier + * the identifier to resolve + * @return the list of procedure declarations */ + public List resolveProcedure(ResolvableIdentifier identifier) { + List result = new ArrayList(); + + if (procedures.containsKey(identifier)) { + result.addAll(procedures.get(identifier)); + } + if (parent != null) { + try { + result.addAll(parent.resolveProcedure(identifier)); + } catch (UnknownIdentifierException e) { + } + } + if (result.isEmpty()) { + throw new UnknownIdentifierException(identifier); + } + return result; + } + + /** Associate an identifier with a declaration. + * + * This method uses define(Identifier, ProcedureDeclaration) if the given declaration is a procedure or function + * declaration. + * + * @param identifier + * the identifier + * @param declaration + * the declaration + * @throws RedeclarationException + * if the identifier is already defined or this is invalid overloading */ + public void define(Identifier identifier, Declaration declaration) throws RedeclarationException { + if (declaration instanceof ProcedureDeclaration) { + define(identifier, (ProcedureDeclaration) declaration); + } else if (members.get(identifier) != null) { + throw new RedeclarationException(declaration, identifier.getSymbol()); + } else { + members.put(identifier, declaration); + } + } + + /** Associate an identifier with a declaration. + *

+ * This differs from define(Identifier, Declaration) as this method uses the declaration's Identifier-attribute to + * call define(Identifier, Declaration) + * + * @param declaration + * the declaration + * @throws RedeclarationException + * if the identifier is already defined or this is invalid overloading */ + public void define(Declaration declaration) throws RedeclarationException { + define(declaration.getIdentifier(), declaration); + } + + /** Associate an identifier with a procedure or function declaration. + * + * This takes overloading into account and throws a RedeclarationException if the declaration is an instance of + * invalid overloading. + * + * @param identifier + * the identifier + * @param declaration + * the declaration + * @throws RedeclarationException + * if this is invalid overloading */ + public void define(Identifier identifier, ProcedureDeclaration declaration) throws RedeclarationException { + if (!procedures.containsKey(identifier)) { + procedures.put(identifier, new ArrayList()); + } + procedures.get(identifier).add(declaration); + } +} diff --git a/src/main/java/de/uni/bremen/monty/moco/ast/declaration/ClassDeclaration.java b/src/main/java/de/uni/bremen/monty/moco/ast/declaration/ClassDeclaration.java new file mode 100644 index 0000000..75eda41 --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/ast/declaration/ClassDeclaration.java @@ -0,0 +1,188 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.ast.declaration; + +import de.uni.bremen.monty.moco.ast.Block; +import de.uni.bremen.monty.moco.ast.Identifier; +import de.uni.bremen.monty.moco.ast.Position; +import de.uni.bremen.monty.moco.ast.ResolvableIdentifier; +import de.uni.bremen.monty.moco.visitor.BaseVisitor; + +import java.util.List; +import java.util.ArrayList; + +/** A ClassDeclaration represents the declaration of a class in the AST. + *

+ * A ClassDeclaration has a list of superclasses and a list of nested declarations. It can be used as a type. */ +public class ClassDeclaration extends TypeDeclaration { + + /** Identifier of superclasses. */ + private final List superClassIdentifiers = new ArrayList<>(); + + /** Superclasses. */ + private final List superClassDeclarations = new ArrayList<>(); + + /** The generated default initializer to be called from every user defined initializer. */ + private ProcedureDeclaration defaultInitializer; + + /** Block with assignments */ + private final Block block; + + /** The virtal method table for this class */ + private List virtualMethodTable = new ArrayList<>(); + + /** The last index for the attributes of this class. This counter starts at `1` as index 0 is reserved for a pointer + * to the vmt. */ + private int lastAttributeIndex = 1; + + /** Constructor. + * + * @param position + * Position of this node + * @param identifier + * the identifier + * @param superClasses + * a list of direct super-classes + * @param block + * the block */ + public ClassDeclaration(Position position, Identifier identifier, List superClasses, + Block block) { + super(position, identifier); + this.block = block; + this.superClassIdentifiers.addAll(superClasses); + } + + /** Get the list of declarations and assignments. + * + * @return the block with declarations and assignments */ + public Block getBlock() { + return block; + } + + /** Get the list of identifiers of direct superclasses + * + * @return the identifier of superclasses */ + public List getSuperClassIdentifiers() { + return superClassIdentifiers; + } + + /** Get the list of direct superclasses this class inherits from. + * + * @return the superclasses */ + public List getSuperClassDeclarations() { + return superClassDeclarations; + } + + /** Get a list of all the declarations of superclasses and this one. */ + public List getSuperClassDeclarationsRecursive() { + List allSuperClassDeclarations = new ArrayList<>(); + for (TypeDeclaration superClass : superClassDeclarations) { + if (superClass instanceof ClassDeclaration) { + allSuperClassDeclarations.addAll(((ClassDeclaration) superClass).getSuperClassDeclarationsRecursive()); + } + } + allSuperClassDeclarations.add(this); + return allSuperClassDeclarations; + } + + /** set the last attribute index. + * + * @param lastAttributeIndex + * the last attribute index */ + public void setLastAttributeIndex(int lastAttributeIndex) { + this.lastAttributeIndex = lastAttributeIndex; + } + + /** get the last attribute index + * + * @return the last attribute index */ + public int getLastAttributeIndex() { + return lastAttributeIndex; + } + + /** Get the VMT. + * + * @return the VMT */ + public List getVirtualMethodTable() { + return virtualMethodTable; + } + + /** Get the default initializer. + * + * @return the default initializer */ + public ProcedureDeclaration getDefaultInitializer() { + return this.defaultInitializer; + } + + /** Set the default initializer. + * + * @param defaultInitializer + * the new default initializer */ + public void setDefaultInitializer(ProcedureDeclaration defaultInitializer) { + this.defaultInitializer = defaultInitializer; + } + + /** {@inheritDoc} */ + @Override + public void visit(BaseVisitor visitor) { + visitor.visit(this); + } + + /** {@inheritDoc} */ + @Override + public void visitChildren(BaseVisitor visitor) { + visitor.visitDoubleDispatched(block); + } + + /** {@inheritDoc} */ + @Override + public boolean matchesType(TypeDeclaration other) { + if (super.matchesType(other)) { + return true; + } + if (other instanceof ClassDeclaration) { + for (TypeDeclaration parentClass : superClassDeclarations) { + if (parentClass.matchesType(other)) { + return true; + } + } + } + return false; + } +} diff --git a/src/main/java/de/uni/bremen/monty/moco/ast/declaration/Declaration.java b/src/main/java/de/uni/bremen/monty/moco/ast/declaration/Declaration.java new file mode 100644 index 0000000..3148ccc --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/ast/declaration/Declaration.java @@ -0,0 +1,99 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.ast.declaration; + +import de.uni.bremen.monty.moco.ast.*; + +/** The baseclass of every declaration. + *

+ * A declaration has an identifier, the name under which this declaration is known. */ +public abstract class Declaration extends BasicASTNode { + + /** The identifier. */ + private final Identifier identifier; + + /** The mangled identifier. */ + private Identifier mangledIdentifier; + + private AccessModifier access; + + /** Constructor. + * + * @param position + * Position of this node + * @param identifier + * the identifier */ + public Declaration(Position position, Identifier identifier) { + super(position); + this.identifier = identifier; + this.access = AccessModifier.PUBLIC; + } + + public Declaration(Position position, Identifier identifier, AccessModifier access) { + super(position); + this.identifier = identifier; + this.access = access; + } + + public void setAccessModifier(AccessModifier access) { + + this.access = access; + } + + /** Get the mangled Identifier. + * + * @return mangled Identifier */ + public Identifier getMangledIdentifier() { + return mangledIdentifier; + } + + /** Set the mangled Identifier. + * + * @param mangledIdentifier */ + public void setMangledIdentifier(Identifier mangledIdentifier) { + this.mangledIdentifier = mangledIdentifier; + } + + /** Get the identifier. + * + * @return the identifier */ + public Identifier getIdentifier() { + return identifier; + } +} diff --git a/src/main/java/de/uni/bremen/monty/moco/ast/declaration/FunctionDeclaration.java b/src/main/java/de/uni/bremen/monty/moco/ast/declaration/FunctionDeclaration.java new file mode 100644 index 0000000..718d0c2 --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/ast/declaration/FunctionDeclaration.java @@ -0,0 +1,148 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.ast.declaration; + +import de.uni.bremen.monty.moco.ast.*; +import de.uni.bremen.monty.moco.visitor.BaseVisitor; + +import java.util.List; + +/** A FunctionDeclaration represents the declaration of a function in the AST. + *

+ * It can be used as a returnType. */ +public class FunctionDeclaration extends ProcedureDeclaration { + + /** The return returnType. */ + private ResolvableIdentifier returnTypeIdentifier; + private TypeDeclaration returnType; + + /** Constructor. + * + * @param position + * Position of this node + * @param identifier + * the identifier + * @param body + * the body of this function + * @param parameter + * the parameter of this function + * @param returnTypeIdentifier + * the return returnType */ + public FunctionDeclaration(Position position, Identifier identifier, Block body, + List parameter, ProcedureDeclaration.DeclarationType declarationType, + ResolvableIdentifier returnTypeIdentifier) { + super(position, identifier, body, parameter, declarationType); + this.returnTypeIdentifier = returnTypeIdentifier; + } + + public FunctionDeclaration(Position position, Identifier identifier, Block body, + List parameter, ResolvableIdentifier returnTypeIdentifier) { + this(position, identifier, body, parameter, ProcedureDeclaration.DeclarationType.UNBOUND, returnTypeIdentifier); + } + + /** Constructor + * + * @param position + * * Position of this node + * @param identifier + * the identifier + * @param body + * the body of this function + * @param parameter + * the parameter of this function + * @param returnType + * the return returnType */ + public FunctionDeclaration(Position position, Identifier identifier, Block body, + List parameter, ClassDeclaration returnType) { + super(position, identifier, body, parameter); + this.returnType = returnType; + this.returnTypeIdentifier = ResolvableIdentifier.convert(returnType.getIdentifier()); + } + + /** get the return returnType. + * + * @return the return returnType */ + public ResolvableIdentifier getReturnTypeIdentifier() { + return returnTypeIdentifier; + } + + /** {@inheritDoc} */ + @Override + public void visit(BaseVisitor visitor) { + visitor.visit(this); + } + + /** {@inheritDoc} */ + @Override + public void visitChildren(BaseVisitor visitor) { + super.visitChildren(visitor); + } + + /** get the returnType. + * + * @return the returnType */ + public TypeDeclaration getReturnType() { + return returnType; + } + + /** set the returnType + * + * @param returnType */ + public void setReturnType(TypeDeclaration returnType) { + this.returnType = returnType; + } + + /** Check equality of two types taking into account the AST object hierachy. + *

+ * + * @param other + * the other TypeDeclaration to check against + * @return if equal */ + @Override + public boolean matchesType(TypeDeclaration other) { + if (!super.matchesType(other)) { + return false; + } + if (!(other instanceof FunctionDeclaration)) { + return true; + } + FunctionDeclaration function = (FunctionDeclaration) other; + return returnType.matchesType(function.getReturnType()); + } +} diff --git a/src/main/java/de/uni/bremen/monty/moco/ast/declaration/ModuleDeclaration.java b/src/main/java/de/uni/bremen/monty/moco/ast/declaration/ModuleDeclaration.java new file mode 100644 index 0000000..688bf0a --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/ast/declaration/ModuleDeclaration.java @@ -0,0 +1,101 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.ast.declaration; + +import java.util.List; + +import de.uni.bremen.monty.moco.ast.*; +import de.uni.bremen.monty.moco.visitor.BaseVisitor; + +/** A ModuleDeclaration represents the declaration of a module in the AST. + *

+ * It can be used as a type. */ +public class ModuleDeclaration extends TypeDeclaration { + + /** The imports in this module. */ + private final List imports; + + /** The nested statements and declarations. */ + private final Block block; + + /** Constructor. + * + * @param position + * Position of this node + * @param identifier + * the identifier + * @param block + * the nested declarations and statements + * @param imports + * the imports in this module */ + public ModuleDeclaration(Position position, Identifier identifier, Block block, List imports) { + super(position, identifier); + this.imports = imports; + this.block = block; + } + + /** Get the body block. + * + * @return the block */ + public Block getBlock() { + return block; + } + + /** Get the list of imports. + * + * @return the imports */ + public List getImports() { + return imports; + } + + /** {@inheritDoc} */ + @Override + public void visit(BaseVisitor visitor) { + visitor.visit(this); + } + + /** {@inheritDoc} */ + @Override + public void visitChildren(BaseVisitor visitor) { + for (Import imp : imports) { + visitor.visitDoubleDispatched(imp); + } + visitor.visitDoubleDispatched(block); + } +} diff --git a/src/main/java/de/uni/bremen/monty/moco/ast/declaration/ProcedureDeclaration.java b/src/main/java/de/uni/bremen/monty/moco/ast/declaration/ProcedureDeclaration.java new file mode 100644 index 0000000..6a769d6 --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/ast/declaration/ProcedureDeclaration.java @@ -0,0 +1,184 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.ast.declaration; + +import java.util.List; + +import de.uni.bremen.monty.moco.ast.*; +import de.uni.bremen.monty.moco.visitor.BaseVisitor; + +/** A ProcedureDeclaration represents the declaration of a procedure in the AST. + *

+ * It can be used as a type. */ +public class ProcedureDeclaration extends TypeDeclaration { + public enum DeclarationType { + INITIALIZER, METHOD, UNBOUND + } + + /** The declarations and statements within this declaration. */ + private final Block body; + + /** The parameters of this declaration. */ + private final List parameter; + + private DeclarationType declarationType; + + /** Index of the procedure in the vmt if it is a procedure in the class struct */ + private int vmtIndex; + + /** Constructor. + * + * @param position + * Position of this node + * @param identifier + * the identifier + * @param body + * the body of this procedure + * @param parameter + * the parameter of this procedure */ + public ProcedureDeclaration(Position position, Identifier identifier, Block body, + List parameter, DeclarationType declarationType) { + super(position, identifier); + this.body = body; + this.parameter = parameter; + this.declarationType = declarationType; + this.vmtIndex = -1; + } + + public ProcedureDeclaration(Position position, Identifier identifier, Block body, + List parameter) { + this(position, identifier, body, parameter, DeclarationType.UNBOUND); + } + + /** Get the body block. + * + * @return the body */ + public Block getBody() { + return body; + } + + /** Get the list of parameter. + * + * @return the paramter */ + public List getParameter() { + return parameter; + } + + /** set the declaration type */ + public void setDeclarationType(DeclarationType type) { + this.declarationType = type; + } + + /** get the declaration type + * + * @return the declaration type */ + public DeclarationType getDeclarationType() { + return declarationType; + } + + public boolean isInitializer() { + return declarationType == DeclarationType.INITIALIZER; + } + + public boolean isMethod() { + return declarationType == DeclarationType.METHOD; + } + + public boolean isUnbound() { + return declarationType == DeclarationType.UNBOUND; + } + + public ClassDeclaration getDefiningClass() { + if (isMethod() || isInitializer()) { + return (ClassDeclaration) getParentNode().getParentNode(); + } + return null; + } + + /** Get the vmtIndex. */ + public int getVMTIndex() { + return vmtIndex; + } + + /** Set the vmtIndex. */ + public void setVMTIndex(int vmtIndex) { + this.vmtIndex = vmtIndex; + } + + /** {@inheritDoc} */ + @Override + public void visit(BaseVisitor visitor) { + visitor.visit(this); + } + + /** {@inheritDoc} */ + @Override + public void visitChildren(BaseVisitor visitor) { + for (VariableDeclaration variableDeclaration : parameter) { + visitor.visitDoubleDispatched(variableDeclaration); + } + visitor.visitDoubleDispatched(body); + } + + /** Check equality of two types taking into account the AST object hierachy. + *

+ * + * @param other + * the other TypeDeclaration to check against + * @return if equal */ + @Override + public boolean matchesType(TypeDeclaration other) { + if (!super.matchesType(other)) { + return false; + } + if (!(other instanceof ProcedureDeclaration)) { + return false; + } + List otherParameter = ((ProcedureDeclaration) other).getParameter(); + if (parameter.size() != otherParameter.size()) { + return false; + } + for (int i = 0; i < parameter.size(); i++) { + if (!parameter.get(i).getType().matchesType(otherParameter.get(i).getType())) { + return false; + } + } + return true; + } +} diff --git a/src/main/java/de/uni/bremen/monty/moco/ast/declaration/TypeDeclaration.java b/src/main/java/de/uni/bremen/monty/moco/ast/declaration/TypeDeclaration.java new file mode 100644 index 0000000..235583e --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/ast/declaration/TypeDeclaration.java @@ -0,0 +1,67 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.ast.declaration; + +import de.uni.bremen.monty.moco.ast.Identifier; +import de.uni.bremen.monty.moco.ast.Position; + +/** The baseclass of every declaration that describes a new type. + *

+ * The TypeDeclarations are used as types for Expressions. */ +public abstract class TypeDeclaration extends Declaration { + /** Constructor. + * + * @param position + * Position of this node + * @param identifier + * the identifier */ + public TypeDeclaration(Position position, Identifier identifier) { + super(position, identifier); + } + + /** Check equality of two types taking into account the AST object hierachy. + *

+ * + * @param other + * the other TypeDeclaration to check against + * @return if equal */ + public boolean matchesType(TypeDeclaration other) { + return getIdentifier().equals(other.getIdentifier()); + } +} diff --git a/src/main/java/de/uni/bremen/monty/moco/ast/declaration/VariableDeclaration.java b/src/main/java/de/uni/bremen/monty/moco/ast/declaration/VariableDeclaration.java new file mode 100644 index 0000000..b5864a0 --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/ast/declaration/VariableDeclaration.java @@ -0,0 +1,151 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.ast.declaration; + +import de.uni.bremen.monty.moco.ast.*; +import de.uni.bremen.monty.moco.visitor.BaseVisitor; + +public class VariableDeclaration extends Declaration { + public enum DeclarationType { + VARIABLE, PARAMETER, ATTRIBUTE + } + + private ResolvableIdentifier typeIdentifier; + private TypeDeclaration type; + private DeclarationType declarationType; + private boolean isGlobal; + + /* Index of the variable if it is an attribute in the class struct */ + private int attributeIndex; + + public VariableDeclaration(Position position, Identifier identifier, ResolvableIdentifier typeIdentifier, + DeclarationType declarationType) { + this(position, identifier, typeIdentifier); + this.declarationType = declarationType; + } + + public VariableDeclaration(Position position, Identifier identifier, ResolvableIdentifier typeIdentifier) { + super(position, identifier); + this.typeIdentifier = typeIdentifier; + this.declarationType = DeclarationType.VARIABLE; + attributeIndex = -1; + } + + /** set the declaration type */ + public void setDeclarationType(DeclarationType type) { + this.declarationType = type; + } + + /** get the declaration type + * + * @return the declaration type */ + public DeclarationType getDeclarationType() { + return declarationType; + } + + public boolean isVariable() { + return declarationType == DeclarationType.VARIABLE; + } + + public boolean isParameter() { + return declarationType == DeclarationType.PARAMETER; + } + + public boolean isAttribute() { + return declarationType == DeclarationType.ATTRIBUTE; + } + + /** get the identifier of the type. + * + * @return the type identifier */ + public ResolvableIdentifier getTypeIdentifier() { + return typeIdentifier; + } + + /** get the type. + * + * @return the type */ + public TypeDeclaration getType() { + return type; + } + + /** set the type + * + * @param type */ + public void setType(TypeDeclaration type) { + this.type = type; + } + + /** get if this variable is global. + * + * @return if global */ + public boolean getIsGlobal() { + return isGlobal; + } + + /** set if this variable is global. + * + * @param isGlobal + * if global */ + public void setIsGlobal(boolean isGlobal) { + this.isGlobal = isGlobal; + } + + /** Get the attributeIndex. */ + public int getAttributeIndex() { + return attributeIndex; + } + + /** Set the attributeIndex. */ + public void setAttributeIndex(int attributeIndex) { + this.attributeIndex = attributeIndex; + } + + /** {@inheritDoc} */ + @Override + public void visit(BaseVisitor visitor) { + visitor.visit(this); + } + + /** {@inheritDoc} */ + @Override + public void visitChildren(BaseVisitor visitor) { + } + +} diff --git a/src/main/java/de/uni/bremen/monty/moco/ast/expression/CastExpression.java b/src/main/java/de/uni/bremen/monty/moco/ast/expression/CastExpression.java new file mode 100644 index 0000000..0c6f85a --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/ast/expression/CastExpression.java @@ -0,0 +1,73 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.ast.expression; + +import de.uni.bremen.monty.moco.ast.*; +import de.uni.bremen.monty.moco.ast.declaration.*; +import de.uni.bremen.monty.moco.visitor.BaseVisitor; + +public class CastExpression extends Expression { + + private Expression expression; + private ResolvableIdentifier castIdentifier; + + public CastExpression(Position position, Expression expression, ResolvableIdentifier castIdentifier) { + super(position); + this.expression = expression; + this.castIdentifier = castIdentifier; + } + + public ResolvableIdentifier getCastIdentifier() { + return castIdentifier; + } + + public Expression getExpression() { + return expression; + } + + @Override + public void visit(BaseVisitor visitor) { + visitor.visit(this); + } + + @Override + public void visitChildren(BaseVisitor visitor) { + visitor.visitDoubleDispatched(expression); + } +} diff --git a/src/main/java/de/uni/bremen/monty/moco/ast/expression/ConditionalExpression.java b/src/main/java/de/uni/bremen/monty/moco/ast/expression/ConditionalExpression.java new file mode 100644 index 0000000..420a729 --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/ast/expression/ConditionalExpression.java @@ -0,0 +1,92 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.ast.expression; + +import de.uni.bremen.monty.moco.ast.*; +import de.uni.bremen.monty.moco.visitor.BaseVisitor; + +public class ConditionalExpression extends Expression { + private final Expression condition; + private final Expression thenExpression; + private final Expression elseExpression; + + public ConditionalExpression(Position position, Expression condition, Expression thenExpression, + Expression elseExpression) { + super(position); + this.condition = condition; + this.thenExpression = thenExpression; + this.elseExpression = elseExpression; + } + + /** get the condition. + * + * @return the condition */ + public Expression getCondition() { + return condition; + } + + /** get the expression of the then part. + * + * @return the then expression */ + public Expression getThenExpression() { + return thenExpression; + } + + /** get the expression of the else part. + * + * @return the else expression */ + public Expression getElseExpression() { + return elseExpression; + } + + /** {@inheritDoc} */ + @Override + public void visit(BaseVisitor visitor) { + visitor.visit(this); + } + + /** {@inheritDoc} */ + @Override + public void visitChildren(BaseVisitor visitor) { + visitor.visitDoubleDispatched(condition); + visitor.visitDoubleDispatched(thenExpression); + visitor.visitDoubleDispatched(elseExpression); + } + +} diff --git a/src/main/java/de/uni/bremen/monty/moco/ast/expression/Expression.java b/src/main/java/de/uni/bremen/monty/moco/ast/expression/Expression.java new file mode 100644 index 0000000..e5d8c92 --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/ast/expression/Expression.java @@ -0,0 +1,74 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.ast.expression; + +import de.uni.bremen.monty.moco.ast.*; +import de.uni.bremen.monty.moco.ast.declaration.TypeDeclaration; + +/** The base class for every expression. + *

+ * An expression has a type which must be set by a visitor. */ +public abstract class Expression extends BasicASTNode { + + /** The type. */ + private TypeDeclaration type; + + /** Constructor. + * + * @param position + * Position of this node */ + public Expression(Position position) { + super(position); + } + + /** Set the type. + * + * @param type + * the new type */ + public void setType(TypeDeclaration type) { + this.type = type; + } + + /** Get the type. + * + * @return the type */ + public TypeDeclaration getType() { + return type; + } +} diff --git a/src/main/java/de/uni/bremen/monty/moco/ast/expression/FunctionCall.java b/src/main/java/de/uni/bremen/monty/moco/ast/expression/FunctionCall.java new file mode 100644 index 0000000..6f7ca2f --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/ast/expression/FunctionCall.java @@ -0,0 +1,106 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.ast.expression; + +import de.uni.bremen.monty.moco.ast.Position; +import de.uni.bremen.monty.moco.ast.ResolvableIdentifier; +import de.uni.bremen.monty.moco.ast.Identifier; +import de.uni.bremen.monty.moco.ast.declaration.ProcedureDeclaration; +import de.uni.bremen.monty.moco.ast.statement.Statement; +import de.uni.bremen.monty.moco.visitor.BaseVisitor; + +import java.util.List; + +public class FunctionCall extends Expression implements Statement { + private final ResolvableIdentifier identifier; + private final List arguments; + private ProcedureDeclaration declaration; + + public FunctionCall(Position position, ResolvableIdentifier identifier, List arguments) { + super(position); + this.identifier = identifier; + this.arguments = arguments; + } + + /** get the identifier. + * + * @return the identifier */ + public ResolvableIdentifier getIdentifier() { + return identifier; + } + + /** get the List of paramter + * + * @return the paramters */ + public List getArguments() { + return arguments; + } + + /** {@inheritDoc} */ + @Override + public void visit(BaseVisitor visitor) { + visitor.visit(this); + } + + /** {@inheritDoc} */ + @Override + public void visitChildren(BaseVisitor visitor) { + for (Expression expression : arguments) { + visitor.visitDoubleDispatched(expression); + } + } + + /** @return the declaration */ + public ProcedureDeclaration getDeclaration() { + return declaration; + } + + /** @param declaration + * the declaration to set */ + public void setDeclaration(ProcedureDeclaration declaration) { + this.declaration = declaration; + } + + /** Get mangled identifier + * + * @return the mangled identifier */ + public Identifier getMangledIdentifier() { + return declaration.getMangledIdentifier(); + } +} diff --git a/src/main/java/de/uni/bremen/monty/moco/ast/expression/IsExpression.java b/src/main/java/de/uni/bremen/monty/moco/ast/expression/IsExpression.java new file mode 100644 index 0000000..024978d --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/ast/expression/IsExpression.java @@ -0,0 +1,82 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.ast.expression; + +import de.uni.bremen.monty.moco.ast.*; +import de.uni.bremen.monty.moco.ast.declaration.*; +import de.uni.bremen.monty.moco.visitor.BaseVisitor; + +public class IsExpression extends Expression { + + private Expression expression; + private ResolvableIdentifier isIdentifier; + private TypeDeclaration toType; + + public IsExpression(Position position, Expression expression, ResolvableIdentifier isIdentifier) { + super(position); + this.expression = expression; + this.isIdentifier = isIdentifier; + } + + public ResolvableIdentifier getIsIdentifier() { + return isIdentifier; + } + + public Expression getExpression() { + return expression; + } + + public void setToType(TypeDeclaration toType) { + this.toType = toType; + } + + public TypeDeclaration getToType() { + return toType; + } + + @Override + public void visit(BaseVisitor visitor) { + visitor.visit(this); + } + + @Override + public void visitChildren(BaseVisitor visitor) { + visitor.visitDoubleDispatched(expression); + } +} diff --git a/src/main/java/de/uni/bremen/monty/moco/ast/expression/MemberAccess.java b/src/main/java/de/uni/bremen/monty/moco/ast/expression/MemberAccess.java new file mode 100644 index 0000000..b055f22 --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/ast/expression/MemberAccess.java @@ -0,0 +1,82 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.ast.expression; + +import de.uni.bremen.monty.moco.ast.Position; +import de.uni.bremen.monty.moco.ast.statement.Statement; +import de.uni.bremen.monty.moco.visitor.BaseVisitor; + +public class MemberAccess extends Expression implements Statement { + private final Expression left; + private final Expression right; + + public MemberAccess(Position position, Expression left, Expression right) { + super(position); + this.left = left; + this.right = right; + } + + /** get the left expression + * + * @return left */ + public Expression getLeft() { + return left; + } + + /** get the right expression + * + * @return right */ + public Expression getRight() { + return right; + } + + /** {@inheritDoc} */ + @Override + public void visit(BaseVisitor visitor) { + visitor.visit(this); + } + + /** {@inheritDoc} */ + @Override + public void visitChildren(BaseVisitor visitor) { + visitor.visitDoubleDispatched(left); + visitor.visitDoubleDispatched(right); + } + +} diff --git a/src/main/java/de/uni/bremen/monty/moco/ast/expression/ParentExpression.java b/src/main/java/de/uni/bremen/monty/moco/ast/expression/ParentExpression.java new file mode 100644 index 0000000..4cb5c22 --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/ast/expression/ParentExpression.java @@ -0,0 +1,75 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.ast.expression; + +import de.uni.bremen.monty.moco.ast.*; +import de.uni.bremen.monty.moco.ast.declaration.*; +import de.uni.bremen.monty.moco.visitor.BaseVisitor; + +public class ParentExpression extends Expression { + + private ResolvableIdentifier parentIdentifier; + private ClassDeclaration selfType; + + public ParentExpression(Position position, ResolvableIdentifier parentIdentifier) { + super(position); + this.parentIdentifier = parentIdentifier; + } + + public ResolvableIdentifier getParentIdentifier() { + return parentIdentifier; + } + + public ClassDeclaration getSelfType() { + return selfType; + } + + public void setSelfType(ClassDeclaration selfType) { + this.selfType = selfType; + } + + @Override + public void visit(BaseVisitor visitor) { + visitor.visit(this); + } + + @Override + public void visitChildren(BaseVisitor visitor) { + } +} diff --git a/src/main/java/de/uni/bremen/monty/moco/ast/expression/SelfExpression.java b/src/main/java/de/uni/bremen/monty/moco/ast/expression/SelfExpression.java new file mode 100644 index 0000000..95a1885 --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/ast/expression/SelfExpression.java @@ -0,0 +1,58 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.ast.expression; + +import de.uni.bremen.monty.moco.ast.Position; +import de.uni.bremen.monty.moco.visitor.BaseVisitor; + +public class SelfExpression extends Expression { + + public SelfExpression(Position position) { + super(position); + } + + @Override + public void visit(BaseVisitor visitor) { + visitor.visit(this); + } + + @Override + public void visitChildren(BaseVisitor visitor) { + } +} diff --git a/src/main/java/de/uni/bremen/monty/moco/ast/expression/VariableAccess.java b/src/main/java/de/uni/bremen/monty/moco/ast/expression/VariableAccess.java new file mode 100644 index 0000000..8ea145d --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/ast/expression/VariableAccess.java @@ -0,0 +1,107 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.ast.expression; + +import de.uni.bremen.monty.moco.ast.*; +import de.uni.bremen.monty.moco.ast.declaration.Declaration; +import de.uni.bremen.monty.moco.visitor.BaseVisitor; + +/** VariableAccess is an expression that references a local variable or a member of an object. */ +public class VariableAccess extends Expression { + + /** Identifier of the variable to access. */ + private final ResolvableIdentifier identifier; + private Declaration declaration; + + /** Is this a L-value? */ + private boolean lValue = false; + + public VariableAccess(Position position, ResolvableIdentifier identifier) { + super(position); + this.identifier = identifier; + } + + /** Get the identifier of the variable to access. + * + * @return the identifier */ + public ResolvableIdentifier getIdentifier() { + return identifier; + } + + /** {@inheritDoc} */ + @Override + public void visit(BaseVisitor visitor) { + visitor.visit(this); + } + + /** {@inheritDoc} */ + @Override + public void visitChildren(BaseVisitor visitor) { + } + + /** Mark this VariableAccess as a L-value. */ + public void setLValue() { + lValue = true; + } + + /** Is this a L-value? + * + * @return if L-value */ + public boolean getLValue() { + return lValue; + } + + /** @return the declaration */ + public Declaration getDeclaration() { + return declaration; + } + + /** @param declaration + * the declaration to set */ + public void setDeclaration(Declaration declaration) { + this.declaration = declaration; + } + + /** Get mangled identifier + * + * @return the mangled identifier */ + public Identifier getMangledIdentifier() { + return declaration.getMangledIdentifier(); + } +} diff --git a/src/main/java/de/uni/bremen/monty/moco/ast/expression/literal/ArrayLiteral.java b/src/main/java/de/uni/bremen/monty/moco/ast/expression/literal/ArrayLiteral.java new file mode 100644 index 0000000..d41f185 --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/ast/expression/literal/ArrayLiteral.java @@ -0,0 +1,78 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ + +package de.uni.bremen.monty.moco.ast.expression.literal; + +import de.uni.bremen.monty.moco.ast.Position; +import de.uni.bremen.monty.moco.ast.expression.Expression; +import de.uni.bremen.monty.moco.visitor.BaseVisitor; + +import java.util.ArrayList; +import java.util.List; + +public class ArrayLiteral extends Expression { + + private List entries; + + /** Constructor. + * + * @param position + * Position of this node + * @param entries */ + public ArrayLiteral(Position position, ArrayList entries) { + super(position); + this.entries = entries; + } + + @Override + public void visit(BaseVisitor visitor) { + visitor.visit(this); + } + + @Override + public void visitChildren(BaseVisitor visitor) { + for (Expression entry : entries) { + entry.visit(visitor); + } + } + + public List getEntries() { + return entries; + } +} diff --git a/src/main/java/de/uni/bremen/monty/moco/ast/expression/literal/BooleanLiteral.java b/src/main/java/de/uni/bremen/monty/moco/ast/expression/literal/BooleanLiteral.java new file mode 100644 index 0000000..2121e34 --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/ast/expression/literal/BooleanLiteral.java @@ -0,0 +1,56 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.ast.expression.literal; + +import de.uni.bremen.monty.moco.ast.CoreClasses; +import de.uni.bremen.monty.moco.ast.Position; +import de.uni.bremen.monty.moco.visitor.BaseVisitor; + +public class BooleanLiteral extends LiteralExpression { + + public BooleanLiteral(Position position, Boolean value) { + super(position, value); + } + + @Override + public void visit(BaseVisitor visitor) { + visitor.visit(this); + } + +} diff --git a/src/main/java/de/uni/bremen/monty/moco/ast/expression/literal/CharacterLiteral.java b/src/main/java/de/uni/bremen/monty/moco/ast/expression/literal/CharacterLiteral.java new file mode 100644 index 0000000..81f8a6e --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/ast/expression/literal/CharacterLiteral.java @@ -0,0 +1,56 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ + +package de.uni.bremen.monty.moco.ast.expression.literal; + +import de.uni.bremen.monty.moco.ast.CoreClasses; +import de.uni.bremen.monty.moco.ast.Position; +import de.uni.bremen.monty.moco.visitor.BaseVisitor; + +public class CharacterLiteral extends LiteralExpression { + public CharacterLiteral(Position position, Character value) { + super(position, value); + } + + @Override + public void visit(BaseVisitor visitor) { + visitor.visit(this); + } + +} diff --git a/src/main/java/de/uni/bremen/monty/moco/ast/expression/literal/FloatLiteral.java b/src/main/java/de/uni/bremen/monty/moco/ast/expression/literal/FloatLiteral.java new file mode 100644 index 0000000..86cac4b --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/ast/expression/literal/FloatLiteral.java @@ -0,0 +1,56 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.ast.expression.literal; + +import de.uni.bremen.monty.moco.ast.CoreClasses; +import de.uni.bremen.monty.moco.ast.Position; +import de.uni.bremen.monty.moco.visitor.BaseVisitor; + +public class FloatLiteral extends LiteralExpression { + + public FloatLiteral(Position position, Float value) { + super(position, value); + } + + @Override + public void visit(BaseVisitor visitor) { + visitor.visit(this); + } + +} diff --git a/src/main/java/de/uni/bremen/monty/moco/ast/expression/literal/IntegerLiteral.java b/src/main/java/de/uni/bremen/monty/moco/ast/expression/literal/IntegerLiteral.java new file mode 100644 index 0000000..8880f74 --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/ast/expression/literal/IntegerLiteral.java @@ -0,0 +1,56 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.ast.expression.literal; + +import de.uni.bremen.monty.moco.ast.CoreClasses; +import de.uni.bremen.monty.moco.ast.Position; +import de.uni.bremen.monty.moco.visitor.BaseVisitor; + +public class IntegerLiteral extends LiteralExpression { + + public IntegerLiteral(Position position, Integer value) { + super(position, value); + } + + @Override + public void visit(BaseVisitor visitor) { + visitor.visit(this); + } + +} diff --git a/src/main/java/de/uni/bremen/monty/moco/ast/expression/literal/LiteralExpression.java b/src/main/java/de/uni/bremen/monty/moco/ast/expression/literal/LiteralExpression.java new file mode 100644 index 0000000..3e99bf4 --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/ast/expression/literal/LiteralExpression.java @@ -0,0 +1,60 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.ast.expression.literal; + +import de.uni.bremen.monty.moco.ast.Position; +import de.uni.bremen.monty.moco.ast.expression.Expression; +import de.uni.bremen.monty.moco.visitor.BaseVisitor; + +public abstract class LiteralExpression extends Expression { + protected T value; + + public LiteralExpression(Position position, T value) { + super(position); + this.value = value; + } + + public T getValue() { + return value; + } + + @Override + public final void visitChildren(BaseVisitor visitor) { + } +} diff --git a/src/main/java/de/uni/bremen/monty/moco/ast/expression/literal/StringLiteral.java b/src/main/java/de/uni/bremen/monty/moco/ast/expression/literal/StringLiteral.java new file mode 100644 index 0000000..d15f4d6 --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/ast/expression/literal/StringLiteral.java @@ -0,0 +1,56 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.ast.expression.literal; + +import de.uni.bremen.monty.moco.ast.CoreClasses; +import de.uni.bremen.monty.moco.ast.Position; +import de.uni.bremen.monty.moco.visitor.BaseVisitor; + +public class StringLiteral extends LiteralExpression { + public StringLiteral(Position position, String value) { + super(position, value.replaceAll("\"", "")); + setType(CoreClasses.stringType()); + } + + @Override + public void visit(BaseVisitor visitor) { + visitor.visit(this); + } + +} diff --git a/src/main/java/de/uni/bremen/monty/moco/ast/statement/Assignment.java b/src/main/java/de/uni/bremen/monty/moco/ast/statement/Assignment.java new file mode 100644 index 0000000..bd6b4bb --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/ast/statement/Assignment.java @@ -0,0 +1,94 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.ast.statement; + +import de.uni.bremen.monty.moco.ast.*; +import de.uni.bremen.monty.moco.ast.expression.Expression; +import de.uni.bremen.monty.moco.visitor.BaseVisitor; + +public class Assignment extends BasicASTNode implements Statement { + + /** The left side. */ + private final Expression left; + + /** The right side. */ + private final Expression right; + + /** Constructor. + * + * @param position + * Position of this node + * @param left + * the left side + * @param right + * the right side */ + public Assignment(Position position, Expression left, Expression right) { + super(position); + this.left = left; + this.right = right; + } + + /** Get the left side. + * + * @return the left side */ + public Expression getLeft() { + return left; + } + + /** Get the right side. + * + * @return the right side */ + public Expression getRight() { + return right; + } + + /** {@inheritDoc} */ + @Override + public void visit(BaseVisitor visitor) { + visitor.visit(this); + } + + /** {@inheritDoc} */ + @Override + public void visitChildren(BaseVisitor visitor) { + visitor.visitDoubleDispatched(left); + visitor.visitDoubleDispatched(right); + } + +} diff --git a/src/main/java/de/uni/bremen/monty/moco/ast/statement/BreakStatement.java b/src/main/java/de/uni/bremen/monty/moco/ast/statement/BreakStatement.java new file mode 100644 index 0000000..a0ece7b --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/ast/statement/BreakStatement.java @@ -0,0 +1,75 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.ast.statement; + +import de.uni.bremen.monty.moco.ast.*; +import de.uni.bremen.monty.moco.visitor.BaseVisitor; + +public class BreakStatement extends BasicASTNode implements Statement { + + /** The loop to skip.* */ + private WhileLoop loop; + + /** Constructor. + * + * @param position + * Position of this node */ + public BreakStatement(Position position) { + super(position); + } + + public void setLoop(WhileLoop loop) { + this.loop = loop; + } + + public WhileLoop getLoop() { + return loop; + } + + /** {@inheritDoc} */ + @Override + public void visit(BaseVisitor visitor) { + visitor.visit(this); + } + + /** {@inheritDoc} */ + @Override + public void visitChildren(BaseVisitor visitor) { + } +} diff --git a/src/main/java/de/uni/bremen/monty/moco/ast/statement/ConditionalStatement.java b/src/main/java/de/uni/bremen/monty/moco/ast/statement/ConditionalStatement.java new file mode 100644 index 0000000..b8b34bd --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/ast/statement/ConditionalStatement.java @@ -0,0 +1,103 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.ast.statement; + +import de.uni.bremen.monty.moco.ast.*; +import de.uni.bremen.monty.moco.ast.expression.Expression; +import de.uni.bremen.monty.moco.visitor.BaseVisitor; + +public class ConditionalStatement extends BasicASTNode implements Statement { + + private final Expression condition; + private final Block thenBlock; + private final Block elseBlock; + + /** Constructor. + * + * @param position + * Position of this node + * @param condition + * the condition + * @param thenBlock + * block if condition is true + * @param elseBlock + * block if condition is false */ + public ConditionalStatement(Position position, Expression condition, Block thenBlock, Block elseBlock) { + super(position); + this.condition = condition; + this.thenBlock = thenBlock; + this.elseBlock = elseBlock; + } + + /** get the condition + * + * @return the condition */ + public Expression getCondition() { + return condition; + } + + /** get the then block + * + * @return the then block */ + public Block getThenBlock() { + return thenBlock; + } + + /** get the else block + * + * @return the else block */ + public Block getElseBlock() { + return elseBlock; + } + + /** {@inheritDoc} */ + @Override + public void visit(BaseVisitor visitor) { + visitor.visit(this); + } + + /** {@inheritDoc} */ + @Override + public void visitChildren(BaseVisitor visitor) { + visitor.visitDoubleDispatched(condition); + visitor.visitDoubleDispatched(thenBlock); + visitor.visitDoubleDispatched(elseBlock); + } + +} diff --git a/src/main/java/de/uni/bremen/monty/moco/ast/statement/ContinueStatement.java b/src/main/java/de/uni/bremen/monty/moco/ast/statement/ContinueStatement.java new file mode 100644 index 0000000..71a5f2e --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/ast/statement/ContinueStatement.java @@ -0,0 +1,66 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.ast.statement; + +import de.uni.bremen.monty.moco.ast.*; +import de.uni.bremen.monty.moco.visitor.BaseVisitor; + +public class ContinueStatement extends BasicASTNode implements Statement { + + /** Constructor + * + * @param position + * Position of this node */ + public ContinueStatement(Position position) { + super(position); + } + + /** {@inheritDoc} */ + @Override + public void visit(BaseVisitor visitor) { + visitor.visit(this); + } + + /** {@inheritDoc} */ + @Override + public void visitChildren(BaseVisitor visitor) { + + } + +} diff --git a/src/main/java/de/uni/bremen/monty/moco/ast/statement/RaiseStatement.java b/src/main/java/de/uni/bremen/monty/moco/ast/statement/RaiseStatement.java new file mode 100644 index 0000000..be776c3 --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/ast/statement/RaiseStatement.java @@ -0,0 +1,63 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.ast.statement; + +import de.uni.bremen.monty.moco.ast.BasicASTNode; +import de.uni.bremen.monty.moco.ast.Position; +import de.uni.bremen.monty.moco.ast.expression.Expression; +import de.uni.bremen.monty.moco.visitor.BaseVisitor; + +public class RaiseStatement extends BasicASTNode implements Statement { + + private Expression expression; + + public RaiseStatement(Position position, Expression expression) { + super(position); + this.expression = expression; + } + + @Override + public void visit(BaseVisitor visitor) { + } + + @Override + public void visitChildren(BaseVisitor visitor) { + } + +} diff --git a/src/main/java/de/uni/bremen/monty/moco/ast/statement/ReturnStatement.java b/src/main/java/de/uni/bremen/monty/moco/ast/statement/ReturnStatement.java new file mode 100644 index 0000000..8ae4025 --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/ast/statement/ReturnStatement.java @@ -0,0 +1,80 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.ast.statement; + +import de.uni.bremen.monty.moco.ast.*; +import de.uni.bremen.monty.moco.ast.expression.Expression; +import de.uni.bremen.monty.moco.visitor.BaseVisitor; + +public class ReturnStatement extends BasicASTNode implements Statement { + private Expression parameter; + + /** Constructor. + * + * @param position + * Position of this node + * @param parameter + * the expression to return */ + public ReturnStatement(Position position, Expression parameter) { + super(position); + this.parameter = parameter; + } + + /** get the paramter + * + * @return the paramter */ + public Expression getParameter() { + return parameter; + } + + /** {@inheritDoc} */ + @Override + public void visit(BaseVisitor visitor) { + visitor.visit(this); + } + + /** {@inheritDoc} */ + @Override + public void visitChildren(BaseVisitor visitor) { + if (parameter != null) { + visitor.visitDoubleDispatched(parameter); + } + } + +} diff --git a/src/main/java/de/uni/bremen/monty/moco/ast/statement/SkipStatement.java b/src/main/java/de/uni/bremen/monty/moco/ast/statement/SkipStatement.java new file mode 100644 index 0000000..159852e --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/ast/statement/SkipStatement.java @@ -0,0 +1,71 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.ast.statement; + +import de.uni.bremen.monty.moco.ast.BasicASTNode; +import de.uni.bremen.monty.moco.ast.Position; +import de.uni.bremen.monty.moco.visitor.BaseVisitor; + +public class SkipStatement extends BasicASTNode implements Statement { + + /** The loop to skip.* */ + private WhileLoop loop; + + public SkipStatement(Position position) { + super(position); + } + + public void setLoop(WhileLoop loop) { + this.loop = loop; + } + + public WhileLoop getLoop() { + return loop; + } + + @Override + public void visit(BaseVisitor visitor) { + visitor.visit(this); + + } + + @Override + public void visitChildren(BaseVisitor visitor) { + } +} diff --git a/src/main/java/de/uni/bremen/monty/moco/ast/statement/Statement.java b/src/main/java/de/uni/bremen/monty/moco/ast/statement/Statement.java new file mode 100644 index 0000000..fe6b4f3 --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/ast/statement/Statement.java @@ -0,0 +1,46 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.ast.statement; + +import de.uni.bremen.monty.moco.ast.*; + +/** The baseclass for every statement. */ +public interface Statement extends ASTNode { + +} diff --git a/src/main/java/de/uni/bremen/monty/moco/ast/statement/TryStatement.java b/src/main/java/de/uni/bremen/monty/moco/ast/statement/TryStatement.java new file mode 100644 index 0000000..e13dd39 --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/ast/statement/TryStatement.java @@ -0,0 +1,80 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.ast.statement; + +import de.uni.bremen.monty.moco.ast.*; +import de.uni.bremen.monty.moco.ast.declaration.VariableDeclaration; +import de.uni.bremen.monty.moco.visitor.BaseVisitor; + +public class TryStatement extends BasicASTNode implements Statement { + + VariableDeclaration handle; + Block tryBlock; + Block handleBlock; + + public TryStatement(Position position, VariableDeclaration handle, Block tryBlock, Block handleBlock) { + super(position); + this.handle = handle; + this.tryBlock = tryBlock; + this.handleBlock = handleBlock; + } + + public Block getTryBlock() { + + return tryBlock; + } + + public Block getHandleBlock() { + + return handleBlock; + } + + @Override + public void visit(BaseVisitor visitor) { + visitor.visit(this); + } + + @Override + public void visitChildren(BaseVisitor visitor) { + visitor.visitDoubleDispatched(tryBlock); + visitor.visitDoubleDispatched(handleBlock); + + } + +} diff --git a/src/main/java/de/uni/bremen/monty/moco/ast/statement/WhileLoop.java b/src/main/java/de/uni/bremen/monty/moco/ast/statement/WhileLoop.java new file mode 100644 index 0000000..a0aaed9 --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/ast/statement/WhileLoop.java @@ -0,0 +1,91 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.ast.statement; + +import de.uni.bremen.monty.moco.ast.*; +import de.uni.bremen.monty.moco.ast.expression.Expression; +import de.uni.bremen.monty.moco.visitor.BaseVisitor; + +public class WhileLoop extends BasicASTNode implements Statement { + + private final Expression condition; + private final Block body; + + /** Constructor. + * + * @param position + * Position of this node + * @param condition + * the condition + * @param body + * loop-body */ + public WhileLoop(Position position, Expression condition, Block body) { + super(position); + this.condition = condition; + this.body = body; + } + + /** get the condition + * + * @return the condition */ + public Expression getCondition() { + return condition; + } + + /** get the body + * + * @return the body */ + public Block getBody() { + return body; + } + + /** {@inheritDoc} */ + @Override + public void visit(BaseVisitor visitor) { + visitor.visit(this); + } + + /** {@inheritDoc} */ + @Override + public void visitChildren(BaseVisitor visitor) { + visitor.visitDoubleDispatched(condition); + visitor.visitDoubleDispatched(body); + } + +} diff --git a/src/main/java/de/uni/bremen/monty/moco/codegeneration/CodeGenerator.java b/src/main/java/de/uni/bremen/monty/moco/codegeneration/CodeGenerator.java new file mode 100644 index 0000000..c120b66 --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/codegeneration/CodeGenerator.java @@ -0,0 +1,584 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.codegeneration; + +import de.uni.bremen.monty.moco.ast.ASTNode; +import de.uni.bremen.monty.moco.ast.CoreClasses; +import de.uni.bremen.monty.moco.ast.declaration.*; +import de.uni.bremen.monty.moco.codegeneration.context.CodeContext; +import de.uni.bremen.monty.moco.codegeneration.context.CodeContext.LLVMFunctionAttribute; +import de.uni.bremen.monty.moco.codegeneration.context.CodeContext.Linkage; +import de.uni.bremen.monty.moco.codegeneration.context.Operations; +import de.uni.bremen.monty.moco.codegeneration.identifier.FunctionSignature; +import de.uni.bremen.monty.moco.codegeneration.identifier.LLVMIdentifier; +import de.uni.bremen.monty.moco.codegeneration.identifier.LLVMIdentifierFactory; +import de.uni.bremen.monty.moco.codegeneration.types.*; +import de.uni.bremen.monty.moco.codegeneration.voodoo.BlackMagic; + +import java.util.*; + +import static de.uni.bremen.monty.moco.codegeneration.types.LLVMTypeFactory.*; + +/** This class should contain most of the logic for the CodeGeneration. Mainly methods are called from the + * CodeGenerationVisitor and have a Parameter 'CodeContext c'. On this argument LLVM instructions can be executed. + * + * It is an mapping layer between the CodeGenerationVisitor on one side and CodeContext on the other. The + * CodeGenerationVisitor is mainly influenced by the Monty-AST and the CodeContext only know LLVM instructions. So the + * CodeGenerator is the where most parts of the mapping between those two languages exists. + * + * An simple task of mapping is e.g. map from monty-Types (TypeDeclaration) to LLVM-Types(LLVMType) */ +public class CodeGenerator { + private final Operations operations; + private final BlackMagic blackMagic; + private final TypeConverter typeConverter; + + /* + * Map an ASTNode to a label prefix. + */ + protected HashMap node2label = new HashMap<>(); + + /* + * Map each label to its number of occurrences. We use this information to create unique labels in the resulting + * LLVM code. + */ + protected HashMap label2occurrences = new HashMap<>(); + + private LLVMIdentifierFactory llvmIdentifierFactory; + + public CodeGenerator(TypeConverter typeConverter, LLVMIdentifierFactory llvmIdentifierFactory) { + this.typeConverter = typeConverter; + this.llvmIdentifierFactory = llvmIdentifierFactory; + operations = new Operations(this, llvmIdentifierFactory); + blackMagic = new BlackMagic(operations); + initFormatStrings(); + } + + public void initFormatStrings() { + LLVMArrayType stringType = array(int8(), 3); + LLVMIdentifier> stringFormatIdent = + llvmIdentifierFactory.newGlobal(".stringFormat", stringType); + operations.setStringFormat(llvmIdentifierFactory.elementPointerTo(stringFormatIdent)); + LLVMIdentifier> intFormatIdent = + llvmIdentifierFactory.newGlobal(".intFormat", stringType); + operations.setIntFormat(llvmIdentifierFactory.elementPointerTo(intFormatIdent)); + LLVMIdentifier> floatFormatIdent = + llvmIdentifierFactory.newGlobal(".floatFormat", stringType); + operations.setFloatFormat(llvmIdentifierFactory.elementPointerTo(floatFormatIdent)); + LLVMIdentifier> charFormatIdent = + llvmIdentifierFactory.newGlobal(".charFormat", stringType); + operations.setCharFormat(llvmIdentifierFactory.elementPointerTo(charFormatIdent)); + } + + private LLVMIdentifier> castIfNeeded(CodeContext c, + LLVMIdentifier> variable, LLVMPointer toType) { + if (!variable.getType().equals(toType)) { + LLVMIdentifier> castedVariable = + llvmIdentifierFactory.newLocal(toType, variable.needToBeResolved()); + c.bitcast(castedVariable, variable); + return castedVariable; + } + return variable; + } + + private LLVMIdentifier castIfNeeded(CodeContext c, LLVMIdentifier variable, T toType) { + if ((variable.getType() instanceof LLVMPointer) && (toType instanceof LLVMPointer)) { + return (LLVMIdentifier) (LLVMIdentifier) castIfNeeded( + c, + (LLVMIdentifier>) (LLVMIdentifier) variable, + (LLVMPointer) toType); + } + return variable; + } + + private LLVMIdentifier resolveIfNeeded(CodeContext c, LLVMIdentifier addr) { + if (addr.needToBeResolved()) { + LLVMIdentifier> sourcePointer = llvmIdentifierFactory.pointerTo(addr); + LLVMIdentifier targetPointer = llvmIdentifierFactory.newLocal(addr.getType(), false); + return c.load(sourcePointer, targetPointer); + } else { + return addr; + } + } + + private List> resolveArgumentsIfNeeded(CodeContext c, + List> arguments, List parameters) { + List> resolvedArguments = new ArrayList<>(arguments.size()); + for (int i = 0; i < arguments.size(); i++) { + LLVMIdentifier resolvedArgument = resolveIfNeeded(c, (LLVMIdentifier) arguments.get(i)); + LLVMType expectedType = mapToLLVMType(parameters.get(i)); + resolvedArguments.add(castIfNeeded(c, resolvedArgument, expectedType)); + } + return resolvedArguments; + } + + private List> unboxArgumentsIfNeeded(CodeContext c, + List> arguments) { + List> unboxedArguments = new ArrayList<>(arguments.size()); + for (LLVMIdentifier llvmIdentifier : arguments) { + if (llvmIdentifier.getType().equals(mapToLLVMType(CoreClasses.intType()))) { + unboxedArguments.add(unboxType(c, (LLVMIdentifier) llvmIdentifier, int64())); + } else if (llvmIdentifier.getType().equals(mapToLLVMType(CoreClasses.boolType()))) { + unboxedArguments.add(unboxType(c, (LLVMIdentifier) llvmIdentifier, int1())); + } else if (llvmIdentifier.getType().equals(mapToLLVMType(CoreClasses.floatType()))) { + unboxedArguments.add(unboxType(c, (LLVMIdentifier) llvmIdentifier, double64())); + } else if (llvmIdentifier.getType().equals(mapToLLVMType(CoreClasses.charType()))) { + unboxedArguments.add(unboxType(c, (LLVMIdentifier) llvmIdentifier, int8())); + } else { + unboxedArguments.add(llvmIdentifier); + } + } + return unboxedArguments; + } + + private LLVMIdentifier> addStringToDataField(CodeContext c, String value) { + int length = value.length() + 1; + + LLVMArrayType type = array(int8(), length); + LLVMIdentifier> identifier = llvmIdentifierFactory.newGlobal(type); + String internValue = "c\"" + value + "\\00\";"; + c.global(Linkage.priv, (LLVMIdentifier) (LLVMIdentifier) identifier, true, internValue); + return identifier; + } + + private LLVMIdentifier> getVMTPointer(CodeContext c, + LLVMIdentifier> selfReference, ClassDeclaration classDeclaration) { + LLVMPointer vmtType = + pointer((LLVMType) struct(classDeclaration.getMangledIdentifier().getSymbol() + "_vmt_type")); + LLVMIdentifier> vmtPointer = llvmIdentifierFactory.newLocal(vmtType, true); + c.getelementptr( + (LLVMIdentifier) (LLVMIdentifier) vmtPointer, + selfReference, + llvmIdentifierFactory.constant(int32(), 0), + llvmIdentifierFactory.constant(int32(), 0)); + return vmtPointer; + } + + private LLVMIdentifier> getFunctionPointer(CodeContext c, + LLVMIdentifier> selfReference, ProcedureDeclaration declaration) { + LLVMIdentifier> vmtPointer = + getVMTPointer(c, selfReference, (ClassDeclaration) declaration.getParentNode().getParentNode()); + + LLVMPointer functionType = mapToLLVMType(declaration); + LLVMIdentifier> functionPointer = llvmIdentifierFactory.newLocal(functionType); + c.getelementptr( + functionPointer, + resolveIfNeeded(c, vmtPointer), + llvmIdentifierFactory.constant(int32(), 0), + llvmIdentifierFactory.constant(int32(), declaration.getVMTIndex())); + return functionPointer; + } + + public void buildConstructor(CodeContext c, ClassDeclaration classDeclaration) { + List> llvmParameter = new ArrayList<>(); + String constructorName = classDeclaration.getMangledIdentifier().getSymbol() + "_constructor"; + addFunction(c, classDeclaration, llvmParameter, constructorName); + + LLVMPointer selfType = mapToLLVMType(classDeclaration); + LLVMIdentifier> selfReference = llvmIdentifierFactory.newLocal(selfType, false); + malloc(c, selfReference); + + LLVMIdentifier vmtPointer = + (LLVMIdentifier) (LLVMIdentifier) getVMTPointer(c, selfReference, classDeclaration); + LLVMIdentifier vmtData = + llvmIdentifierFactory.newGlobal( + classDeclaration.getMangledIdentifier().getSymbol() + "_vmt_data", + vmtPointer.getType()); + c.store(vmtData, llvmIdentifierFactory.pointerTo(vmtPointer)); + + returnValue(c, (LLVMIdentifier) selfReference, classDeclaration); + } + + public LLVMIdentifier callConstructor(CodeContext c, ClassDeclaration classDeclaration) { + LLVMIdentifier result = llvmIdentifierFactory.newLocal(mapToLLVMType(classDeclaration), false); + LLVMIdentifier signature = + llvmIdentifierFactory.newGlobal( + classDeclaration.getMangledIdentifier().getSymbol() + "_constructor", + result.getType()); + c.call(signature, result); + return result; + } + + /** Create a unique label prefix and store it under an association with the given node. */ + public String createLabelPrefix(String name, ASTNode node) { + if (!label2occurrences.containsKey(name)) { + label2occurrences.put(name, 0); + } + int id = label2occurrences.get(name); + String label = name + id; + label2occurrences.put(name, id + 1); + node2label.put(node, label); + return label; + } + + /** Get the unique label prefix associated with the given node. + * + * This is a Map lookup so the error will be thrown if node does not exist as key */ + public String getLabelPrefix(ASTNode node) { + return node2label.get(node); + } + + public LLVMIdentifier declareGlobalVariable(CodeContext c, String name, TypeDeclaration type) { + LLVMType llvmType = mapToLLVMType(type); + LLVMIdentifier variable = llvmIdentifierFactory.newGlobal(name, llvmType); + c.global(Linkage.priv, variable, false); + return variable; + } + + public LLVMIdentifier declareLocalVariable(CodeContext c, String name, TypeDeclaration type) { + LLVMType llvmType = mapToLLVMType(type); + + LLVMIdentifier variable = llvmIdentifierFactory.newLocal(name, llvmType, true); + c.alloca(variable, llvmType); + return variable; + } + + public LLVMIdentifier resolveLocalVarName(String name, TypeDeclaration type, + boolean resolvable) { + T llvmType = mapToLLVMType(type); + return llvmIdentifierFactory.newLocal(name, llvmType, resolvable); + } + + public LLVMIdentifier resolveGlobalVarName(String name, TypeDeclaration type) { + T llvmType = mapToLLVMType(type); + return llvmIdentifierFactory.newGlobal(name, llvmType); + } + + public void addMain(CodeContext active) { + + FunctionSignature mainFunction = + llvmIdentifierFactory.newFunction( + int32(), + "main", + Collections.> emptyList()); + + active.define(Arrays.asList(LLVMFunctionAttribute.ssp), mainFunction); + active.label("entry"); + } + + public void addFunction(CodeContext c, TypeDeclaration returnType, + List> llvmParameter, String name) { + LLVMType llvmReturnType = mapToLLVMType(returnType); + c.define( + new ArrayList(), + llvmIdentifierFactory.newFunction(llvmReturnType, name, llvmParameter)); + c.label("entry"); + } + + public void addNativeFunction(CodeContext c, TypeDeclaration returnType, + List> llvmParameter, String name) { + addFunction(c, returnType, llvmParameter, name); + + List> unboxedParameter = unboxArgumentsIfNeeded(c, llvmParameter); + + LLVMIdentifier result = + (LLVMIdentifier) blackMagic.generateNativeFunction(c, name, unboxedParameter); + if (result != null) { + if (result.getType() instanceof LLVMPointer) { + returnValue(c, result, returnType); + } else { + returnValue(c, boxType(c, result, returnType), returnType); + } + } else { + returnValue( + c, + (LLVMIdentifier) (LLVMIdentifier) llvmIdentifierFactory.voidId(), + CoreClasses.voidType()); + } + } + + public void returnMain(CodeContext c) { + c.ret(llvmIdentifierFactory.constant(int32(), 0)); + } + + public void returnValue(CodeContext c, LLVMIdentifier returnValue, TypeDeclaration expectedType) { + LLVMIdentifier resolved = resolveIfNeeded(c, returnValue); + LLVMIdentifier casted = castIfNeeded(c, resolved, mapToLLVMType(expectedType)); + c.ret(casted); + } + + public LLVMIdentifier> addConstantString(CodeContext constant, String value) { + LLVMIdentifier> nameOfDataField = addStringToDataField(constant, value); + LLVMIdentifier> stringAsCharPointer = + llvmIdentifierFactory.elementPointerTo(nameOfDataField); + return stringAsCharPointer; + } + + public void exit(CodeContext c, int statusCode) { + LLVMIdentifier signature = llvmIdentifierFactory.newGlobal("exit", (LLVMType) voidType()); + c.callVoid(signature, llvmIdentifierFactory.constant(int32(), statusCode)); + } + + /** Allocates heap memory for the given type and return a typed pointer. */ + public LLVMIdentifier> malloc(CodeContext c, + LLVMIdentifier> result) { + return malloc(c, result, (LLVMPointer) result.getType()); + } + + /** Allocates heap memory for the given type and return a typed pointer. */ + public LLVMIdentifier> malloc(CodeContext c, + LLVMIdentifier> result, LLVMPointer inputType) { + + LLVMIdentifier> sizePtr = llvmIdentifierFactory.newLocal(inputType); + c.getelementptr( + sizePtr, + llvmIdentifierFactory.constantNull(inputType), + llvmIdentifierFactory.constant(int32(), 1)); + LLVMIdentifier sizeInt = llvmIdentifierFactory.newLocal((LLVMType) int32()); + c.ptrtoint(sizeInt, (LLVMIdentifier) sizePtr); + + LLVMIdentifier> s = llvmIdentifierFactory.newGlobal("malloc", pointer(int8())); + LLVMIdentifier> mallocPtr = llvmIdentifierFactory.newLocal(s.getType()); + c.call((LLVMIdentifier) (LLVMIdentifier) s, mallocPtr, sizeInt); + c.bitcast((LLVMIdentifier) result, (LLVMIdentifier) mallocPtr); + return result; + } + + public void assign(CodeContext c, LLVMIdentifier target, LLVMIdentifier source) { + source = resolveIfNeeded(c, source); + source = castIfNeeded(c, source, target.getType()); + LLVMIdentifier> targetPointer = llvmIdentifierFactory.pointerTo(target); + c.store(source, targetPointer); + } + + public LLVMIdentifier accessMember(CodeContext c, LLVMIdentifier> pointer, + int attributeOffset, TypeDeclaration type, boolean load) { + + LLVMIdentifier result = llvmIdentifierFactory.newLocal(mapToLLVMType(type), load); + c.getelementptr( + result, + resolveIfNeeded(c, pointer), + llvmIdentifierFactory.constant(int32(), 0), + llvmIdentifierFactory.constant(int32(), attributeOffset)); + return result; + } + + public T mapToLLVMType(TypeDeclaration type) { + return typeConverter.mapToLLVMType(type); + } + + public LLVMIdentifier> castClass(CodeContext c, + LLVMIdentifier> pointer, ClassDeclaration sourceType, ClassDeclaration resultType, + String labelPrefix) { + + String successLabel = labelPrefix + ".success"; + String failureLabel = labelPrefix + ".failure"; + + pointer = resolveIfNeeded(c, pointer); + LLVMIdentifier isaCmpResult = isClass(c, pointer, sourceType, resultType); + + c.branch(isaCmpResult, successLabel, failureLabel); + c.label(failureLabel); + exit(c, 1); + c.branch(successLabel); + c.label(successLabel); + return castIfNeeded(c, pointer, (LLVMPointer) mapToLLVMType(resultType)); + } + + public LLVMIdentifier isClass(CodeContext c, LLVMIdentifier> pointer, + ClassDeclaration sourceType, ClassDeclaration resultType) { + + pointer = resolveIfNeeded(c, pointer); + LLVMIdentifier> vmt = getVMTPointer(c, pointer, sourceType); + vmt = resolveIfNeeded(c, vmt); + + LLVMType ctType = array(pointer(int8()), sourceType.getSuperClassDeclarationsRecursive().size() + 1); + LLVMIdentifier> ct = llvmIdentifierFactory.newLocal(pointer(ctType), true); + c.getelementptr(ct, vmt, llvmIdentifierFactory.constant(int32(), 0), llvmIdentifierFactory.constant(int32(), 0)); + ct = resolveIfNeeded(c, ct); + + LLVMType pointerArrayType = array(pointer(int8()), 0); + LLVMIdentifier> pointerArray = llvmIdentifierFactory.newLocal(pointer(pointerArrayType)); + c.bitcast(pointerArray, ct); + + LLVMType resultVMTType = struct(resultType.getMangledIdentifier().getSymbol() + "_vmt_type"); + LLVMIdentifier> resultVMT = + llvmIdentifierFactory.newGlobal( + resultType.getMangledIdentifier().getSymbol() + "_vmt_data", + pointer(resultVMTType)); + LLVMIdentifier> resultPointer = + llvmIdentifierFactory.newLocal(pointer((LLVMType) int8())); + c.bitcast(resultPointer, resultVMT); + + LLVMIdentifier isaCmpResult = llvmIdentifierFactory.newLocal(int1(), false); + LLVMIdentifier isaSignature = llvmIdentifierFactory.newGlobal("vmt_isa_class", int1()); + c.call((LLVMIdentifier) (LLVMIdentifier) isaSignature, isaCmpResult, pointerArray, resultPointer); + return isaCmpResult; + } + + public void checkArrayBounds(CodeContext c, LLVMIdentifier> array, + LLVMIdentifier index) { + + List arrayTypeList = Arrays.asList(int64(), array(pointer(int8()), 0)); + array = castIfNeeded(c, array, pointer(struct(arrayTypeList))); + LLVMIdentifier boundsCheckSignature = + llvmIdentifierFactory.newGlobal("array_bounds_check", voidType()); + c.callVoid((LLVMIdentifier) (LLVMIdentifier) boundsCheckSignature, array, index); + } + + public LLVMIdentifier call(CodeContext c, String functionName, TypeDeclaration returnType, + List> arguments, List parameters) { + LLVMType llvmReturnType = mapToLLVMType(returnType); + LLVMIdentifier functionSignature = llvmIdentifierFactory.newGlobal(functionName, llvmReturnType); + List> resolvedArguments = resolveArgumentsIfNeeded(c, arguments, parameters); + return c.call( + functionSignature, + llvmIdentifierFactory.newLocal(functionSignature.getType(), false), + resolvedArguments); + } + + public void callVoid(CodeContext c, String functionName, List> arguments, + List parameters) { + List> resolvedArguments = resolveArgumentsIfNeeded(c, arguments, parameters); + c.callVoid(llvmIdentifierFactory.newGlobal(functionName, (LLVMType) voidType()), resolvedArguments); + } + + public LLVMIdentifier callMethod(CodeContext c, FunctionDeclaration declaration, + List> arguments, List parameters) { + List> resolvedArguments = resolveArgumentsIfNeeded(c, arguments, parameters); + + LLVMIdentifier> functionPointer = + getFunctionPointer(c, (LLVMIdentifier>) resolvedArguments.get(0), declaration); + return c.call( + (LLVMIdentifier) (LLVMIdentifier) resolveIfNeeded(c, functionPointer), + llvmIdentifierFactory.newLocal(mapToLLVMType(declaration.getReturnType()), false), + resolvedArguments); + } + + public void callVoidMethod(CodeContext c, ProcedureDeclaration declaration, List> arguments, + List parameters) { + List> resolvedArguments = resolveArgumentsIfNeeded(c, arguments, parameters); + + LLVMIdentifier> functionPointer = + getFunctionPointer(c, (LLVMIdentifier>) resolvedArguments.get(0), declaration); + c.callVoid( + (LLVMIdentifier) (LLVMIdentifier) resolveIfNeeded(c, functionPointer), + resolvedArguments); + } + + public void branch(CodeContext c, LLVMIdentifier expression, String trueLabel, String falseLabel) { + LLVMIdentifier boxedValue = resolveIfNeeded(c, expression); + LLVMIdentifier value = unboxType(c, boxedValue, int1()); + c.branch(value, trueLabel, falseLabel); + } + + public LLVMIdentifier loadInt(Integer value) { + return llvmIdentifierFactory.constant(int64(), value); + } + + public LLVMIdentifier loadFloat(Float value) { + return llvmIdentifierFactory.constant(double64(), value); + } + + public LLVMIdentifier loadBool(Boolean value) { + return llvmIdentifierFactory.constant(int1(), value); + } + + public LLVMIdentifier loadChar(Character value) { + return llvmIdentifierFactory.constant(int8(), value); + } + + public LLVMIdentifier> addArray(CodeContext c, int size, ClassDeclaration type) { + + LLVMPointer array = mapToLLVMType(type); + LLVMIdentifier> var = llvmIdentifierFactory.newLocal(array, false); + + // Temporary until object or generic + LLVMType arrayType = mapToLLVMType((TypeDeclaration) CoreClasses.intType()); + List mallocList = Arrays.asList(int64(), array(arrayType, size)); + malloc(c, var, pointer((LLVMType) struct(mallocList))); + + LLVMIdentifier arraySize = + (LLVMIdentifier) (LLVMIdentifier) llvmIdentifierFactory.constant(int64(), size); + LLVMIdentifier> sizeField = llvmIdentifierFactory.newLocal(pointer(arraySize.getType())); + c.getelementptr( + sizeField, + var, + llvmIdentifierFactory.constant(int32(), 0), + llvmIdentifierFactory.constant(int32(), 0)); + c.store(arraySize, sizeField); + + return var; + } + + public void setArrayElement(CodeContext c, LLVMIdentifier> array, int index, + LLVMIdentifier value) { + + // Temporary until object or generic + LLVMType internalType = mapToLLVMType((TypeDeclaration) CoreClasses.intType()); + LLVMIdentifier> element = llvmIdentifierFactory.newLocal(pointer(internalType)); + + c.getelementptr( + element, + array, + llvmIdentifierFactory.constant(int32(), 0), + llvmIdentifierFactory.constant(int32(), 1), + llvmIdentifierFactory.constant(int32(), index)); + c.store(value, element); + } + + public LLVMIdentifier boxType(CodeContext c, LLVMIdentifier toBox, TypeDeclaration type) { + + LLVMIdentifier boxedValue = callConstructor(c, (ClassDeclaration) type); + LLVMIdentifier boxedValueField = llvmIdentifierFactory.newLocal(toBox.getType()); + c.getelementptr( + boxedValueField, + boxedValue, + llvmIdentifierFactory.constant(int32(), 0), + llvmIdentifierFactory.constant(int32(), 1)); + LLVMIdentifier> targetPointer = llvmIdentifierFactory.pointerTo(boxedValueField); + c.store(toBox, targetPointer); + return boxedValue; + } + + public LLVMIdentifier unboxType(CodeContext c, LLVMIdentifier toUnbox, T llvmtype) { + toUnbox = resolveIfNeeded(c, toUnbox); + LLVMIdentifier unboxedValue = llvmIdentifierFactory.newLocal(llvmtype); + + c.getelementptr( + unboxedValue, + toUnbox, + llvmIdentifierFactory.constant(int32(), 0), + llvmIdentifierFactory.constant(int32(), 1)); + LLVMIdentifier> sourcePointer = llvmIdentifierFactory.pointerTo(unboxedValue); + LLVMIdentifier targetPointer = llvmIdentifierFactory.newLocal(unboxedValue.getType(), false); + + c.load(sourcePointer, targetPointer); + return targetPointer; + } +} diff --git a/src/main/java/de/uni/bremen/monty/moco/codegeneration/CodeWriter.java b/src/main/java/de/uni/bremen/monty/moco/codegeneration/CodeWriter.java new file mode 100644 index 0000000..34c98cd --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/codegeneration/CodeWriter.java @@ -0,0 +1,84 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.codegeneration; + +import de.uni.bremen.monty.moco.util.Params; +import org.apache.commons.io.FilenameUtils; +import org.apache.commons.io.IOUtils; + +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +public class CodeWriter { + + private OutputStream llOutputStream; + + public CodeWriter(Params params) throws IOException { + llOutputStream = initLlvmOutput(params); + IOUtils.copy(getClass().getResourceAsStream("/std_llvm_include.ll"), llOutputStream); + } + + private OutputStream initLlvmOutput(Params params) throws FileNotFoundException { + OutputStream llOutputStream; + if (params.isGenerateOnlyLLVM()) { + if (params.getOutputFile() == null) { + llOutputStream = System.out; + } else { + llOutputStream = new FileOutputStream(params.getOutputFile()); + } + } else { + String llFile; + if (params.getInputFile() != null) { + llFile = FilenameUtils.removeExtension(params.getInputFile()) + ".ll"; + } else { + llFile = params.getInputFolder() + "/Main.ll"; + } + llOutputStream = new FileOutputStream(llFile); + params.setLlFile(llFile); + } + return llOutputStream; + } + + public void write(String data) throws IOException { + llOutputStream.write(data.getBytes()); + llOutputStream.flush(); + } +} diff --git a/src/main/java/de/uni/bremen/monty/moco/codegeneration/Native.java b/src/main/java/de/uni/bremen/monty/moco/codegeneration/Native.java new file mode 100644 index 0000000..2afc5ca --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/codegeneration/Native.java @@ -0,0 +1,51 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ + +package de.uni.bremen.monty.moco.codegeneration; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface Native { + String value(); +} diff --git a/src/main/java/de/uni/bremen/monty/moco/codegeneration/context/CodeContext.java b/src/main/java/de/uni/bremen/monty/moco/codegeneration/context/CodeContext.java new file mode 100644 index 0000000..17be5fe --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/codegeneration/context/CodeContext.java @@ -0,0 +1,452 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.codegeneration.context; + +import static de.uni.bremen.monty.moco.codegeneration.types.LLVMTypeFactory.pointer; + +import java.util.List; +import java.util.Arrays; +import org.apache.commons.lang3.StringUtils; + +import de.uni.bremen.monty.moco.codegeneration.identifier.FunctionSignature; +import de.uni.bremen.monty.moco.codegeneration.identifier.LLVMIdentifier; +import de.uni.bremen.monty.moco.codegeneration.types.LLVMPointer; +import de.uni.bremen.monty.moco.codegeneration.types.LLVMStructType; +import de.uni.bremen.monty.moco.codegeneration.types.LLVMType; +import de.uni.bremen.monty.moco.codegeneration.types.LLVMTypeFactory.LLVMBool; +import de.uni.bremen.monty.moco.codegeneration.types.LLVMTypeFactory.LLVMIntType; + +/** The CodeContext provides methods representing LLVM-Instruction. + * + * In LLVM-IR is e.g. the load instruction, so there is a load Method in CodeContext. + * + * For convenience CodeContext extends from Context. From the perspective of it's users you have only one instance + * knowing where to write (Context) and how/what to write (CodeContext). */ +public class CodeContext extends Context { + + /** @param commentAppender + * the comment appender to be used */ + public CodeContext(CommentAppender commentAppender) { + super(commentAppender); + } + + // --------------Memory Access and Addressing Operations-------------------- + + /** Allocates space for a variable + * + * @param identifierOfLocalVar + * identifier of the local variable + * @param llvmType + * type of the local variable + * @return identifier of the local variable */ + public LLVMIdentifier alloca(LLVMIdentifier identifierOfLocalVar, LLVMType llvmType) { + append(identifierOfLocalVar.getName() + " = alloca " + llvmType); + return identifierOfLocalVar; + } + + /** Dereferences a pointer + * + * @param sourcePointer + * the pointer to dereferences + * @param + * Type encapsulated from the Pointer + * @return Address of the dereferenced value */ + public LLVMIdentifier load(LLVMIdentifier> sourcePointer, + LLVMIdentifier identifier) { + append(identifier.getName() + " = load " + sourcePointer); + return identifier; + } + + /** Stores a value + * + * @param source + * the value + * @param targetPointer + * target address + * @param + * the type of the value */ + public void store(LLVMIdentifier source, LLVMIdentifier> targetPointer) { + append("store " + source + ", " + targetPointer); + } + + /** Gets an element pointer + * + * @param varIdentifier + * the LLVMIdentifier + * @param pointer + * the pointer + * @param offsets + * the offset added to pointer */ + + @SafeVarargs + public final void getelementptr(LLVMIdentifier varIdentifier, + LLVMIdentifier pointer, LLVMIdentifier... offsets) { + append(varIdentifier.getName() + " = getelementptr inbounds " + pointer + ", " + + + StringUtils.join(offsets, ',')); + } + + // ---------------- Other Operations --------------------------------------- + + /** Compares two Integers + * + * @param icmpOperand + * How to compare + * @param arg1 + * First argument. Should be an Integer. + * @param arg2 + * Second argument. Should be an Integer. + * @return Address of the calculated result */ + public LLVMIdentifier icmp(IcmpOperand icmpOperand, LLVMIdentifier arg1, LLVMIdentifier arg2, + LLVMIdentifier product) { + + append(product.getName() + " = icmp " + icmpOperand.name() + " " + arg1 + "," + arg2.getName()); + return product; + } + + /** Compares two Integers + * + * @param fcmpOperand + * How to compare + * @param arg1 + * First argument. Should be an Integer. + * @param arg2 + * Second argument. Should be an Integer. + * @return Address of the calculated result */ + public LLVMIdentifier fcmp(FcmpOperand fcmpOperand, LLVMIdentifier arg1, LLVMIdentifier arg2, + LLVMIdentifier product) { + + append(product.getName() + " = fcmp " + fcmpOperand.name() + " " + arg1 + "," + arg2.getName()); + return product; + } + + /** The phi instruction. + * + * This must be the first instruction in a basic block. identifier and label must be nonempty and of the same + * length. + * + * @param type + * the result type + * @param resolvable + * if the result needs to be resolved + * @param identifiers + * list of identifier + * @param labels + * list of labels + * @param + * Return Type + * @return Identifier for result */ + + public LLVMIdentifier phi(T type, boolean resolvable, List> identifiers, + LLVMIdentifier identifier, List labels) { + + String typeStr = resolvable ? pointer(type).toString() : type.toString(); + StringBuilder sb = new StringBuilder(); + sb.append(String.format("%s = phi %s ", identifier.getName(), typeStr)); + for (int i = 0; i < identifiers.size(); i++) { + sb.append(String.format("[%s, %%%s]", identifiers.get(i).getName(), labels.get(i))); + + if (i != (identifiers.size() - 1)) { + sb.append(", "); + } + } + append(sb.toString()); + return identifier; + } + + /** @param signature + * Name and return type of the function + * @param arguments + * List of Arguments + * @param + * Return Type + * @return Identifier for result */ + public LLVMIdentifier call(LLVMIdentifier signature, + LLVMIdentifier identifier, LLVMIdentifier... arguments) { + return call(signature, identifier, Arrays.asList(arguments)); + } + + /** @param signature + * Name and return type of the function + * @param arguments + * List of Arguments + * @param + * Return Type + * @return Identifier for result */ + public LLVMIdentifier call(LLVMIdentifier signature, + LLVMIdentifier identifier, List> arguments) { + return call(signature, identifier, arguments, ""); + } + + /** Calls a function + * + * @param signature + * Name and return type of the function + * @param arguments + * List of Arguments + * @param overloadArgs + * Special argument that is used for overloaded methods. + * @param + * Return Type + * @return Identifier for result */ + public LLVMIdentifier call(LLVMIdentifier signature, + LLVMIdentifier identifier, List> arguments, String overloadArgs) { + append(identifier.getName() + " = call " + signature.getType() + " " + overloadArgs + " " + signature.getName() + + "(" + StringUtils.join(arguments, ',') + ")"); + return identifier; + } + + /** Calls a Procedure + * + * @param signature + * Name and return type of the function + * @param arguments + * List of Arguments */ + public void callVoid(LLVMIdentifier signature, LLVMIdentifier... arguments) { + callVoid(signature, Arrays.asList(arguments)); + } + + /** Calls a Procedure + * + * @param signature + * Name and return type of the function + * @param arguments + * List of Arguments */ + public void callVoid(LLVMIdentifier signature, List> arguments) { + append("call " + signature + "(" + StringUtils.join(arguments, ',') + ")"); + } + + /** Defines a function. Appends the function signature and opens a new scope. Instructions called after this will be + * inside this new scope until {@link #close()} is used. + * + * @param fNAttr + * LLVM-Attributes like 'ssp' + * @param functionSignature + * function Signature: name, return type and parameter */ + public void define(List fNAttr, FunctionSignature functionSignature) { + emptyLine(); + append("define " + functionSignature + " " + StringUtils.join(fNAttr, ' ') + " {"); + indent(); + } + + public enum LLVMFunctionAttribute { + ssp, nounwind + } + + /** Appends a label + * + * A label starts a basic block. Because a basic block must end with a terminator instruction the last instruction + * before this label must be a terminator instruction. `br` (branch instruction) is one of those. + * + * @param label + * name of the label */ + public void label(String label) { + append(label + ":"); + } + + /** Append a global variable. + * + * Dont use this method unless you know why, use global(Linkage, LLVMIdentifier, boolean, + * LLVMIdentifier) or global(Linkage, LLVMIdentifier, boolean) instead. */ + public LLVMIdentifier global(Linkage linkage, LLVMIdentifier target, boolean isConstant, + String initializer) { + String globalOrConstant = isConstant ? " constant " : " global "; + append(target.getName() + " = " + linkage + globalOrConstant + target.getType() + initializer); + return target; + } + + /** Append a global variable. + * + * initializer should be a StructConstant or an ArrayConstant. */ + public LLVMIdentifier global(Linkage linkage, LLVMIdentifier target, boolean isConstant, + LLVMIdentifier initializer) { + return global(linkage, target, isConstant, initializer.getName()); + } + + /** Append a global variable with a zeroinitializer. */ + public LLVMIdentifier global(Linkage linkage, LLVMIdentifier target, boolean isConstant) { + return global(linkage, target, isConstant, " zeroinitializer"); + } + + public enum Linkage { + + priv("private"), internal; + + private String name; + + private Linkage(String name) { + this.name = name; + } + + private Linkage() { + + } + + public String toString() { + if (name == null) { + return name(); + } else { + return name; + } + } + } + + /** Return instruction for functions + * + * @param llvmIdentifier + * Value to return */ + public void ret(LLVMIdentifier llvmIdentifier) { + append("ret " + llvmIdentifier); + } + + /** Declares a function. Declare means the implementation of the function is somewhere else. + * + * @param functionSignature + * Name and return type of the function */ + public void declare(FunctionSignature functionSignature) { + append("declare " + functionSignature); + } + + /** Closes the scope opened from a {@link #define(List, FunctionSignature)}. Last instruction for a function + * definition */ + public void close() { + dedent(); + append("}"); + emptyLine(); + } + + /** Unconditional branch. */ + public void branch(String label) { + append("br label %" + label); + } + + /** Conditional branch. */ + public void branch(LLVMIdentifier value, String trueLabel, String falseLabel) { + append("br " + value + ", label %" + trueLabel + ", label %" + falseLabel); + } + + /** Adds a type declaration Compares two Integers + * + * @param type + * name and structur of the new type */ + public void type(LLVMStructType type, List list) { + String variableType = " = type { "; + if (!list.isEmpty()) { + variableType += list.get(0).toString(); + for (int i = 1; i < list.size(); i++) { + variableType += ", " + list.get(i).toString(); + } + } + + append(type + variableType + " }"); + } + + @SuppressWarnings("unchecked") + public LLVMIdentifier binaryOperation(String operator, LLVMIdentifier arg1, + LLVMIdentifier arg2, LLVMIdentifier product) { + append(product.getName() + " = " + operator + " " + arg1 + "," + arg2.getName()); + return (LLVMIdentifier) product; + } + + /** Converts a pointer to an integer */ + public void ptrtoint(LLVMIdentifier target, LLVMIdentifier> source) { + append(target.getName() + " = ptrtoint " + source + " to " + target.getType()); + } + + /** Casts a pointer to a pointer of a different type */ + public void bitcast(LLVMIdentifier> target, + LLVMIdentifier> source) { + append(target.getName() + " = bitcast " + source + " to " + target.getType()); + } + + /** The sext instruction. + * + * Casts an integer of small bitsize to an integer of larger bitsize. + * + * @param result + * variable for the result + * @param toCast + * variable to cast + * @param toType + * type to cast to */ + public LLVMIdentifier sext(LLVMIdentifier toCast, LLVMIntType toType, + LLVMIdentifier result) { + append(result.getName() + " = sext " + toCast + " to " + toType); + return result; + } + + /** Compare modi for {@link #icmp(IcmpOperand, LLVMIdentifier, LLVMIdentifier, LLVMIdentifier)} */ + public enum IcmpOperand { + /** equals */ + eq, + /** not equals */ + ne, + /** unsigned greater than */ + ugt, + /** unsigned greater or equal */ + uge, + /** unsigned less than */ + ult, + /** unsigned less or equal */ + ule, + /** signed greater than */ + sgt, + /** signed greater or equal */ + sge, + /** signed less than */ + slt, + /** signed less or equal */ + sle; + } + + public enum FcmpOperand { + /** ordered and equal */ + oeq, + /** ordered and not equal */ + one, + /** ordered and greater than */ + ogt, + /** ordered and greater than or equal */ + oge, + /** ordered and less than */ + olt, + /** ordered and less than or equal */ + ole + } +} diff --git a/src/main/java/de/uni/bremen/monty/moco/codegeneration/context/CommentAppender.java b/src/main/java/de/uni/bremen/monty/moco/codegeneration/context/CommentAppender.java new file mode 100644 index 0000000..658457c --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/codegeneration/context/CommentAppender.java @@ -0,0 +1,78 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.codegeneration.context; + +import de.uni.bremen.monty.moco.ast.ASTNode; +import de.uni.bremen.monty.moco.ast.Position; +import org.apache.commons.lang3.StringUtils; + +/** Adds a comment after each line in llvm. That comment contains the Class of the ASTNode and the line in the monty File + * that is responsible for the llvm instruction. */ +public class CommentAppender { + + private ASTNode currentNode; + + /** Adds a comment + * + * @param string + * the llvm instruction + * @return the llvm with comment */ + public String addComment(String string) { + Position position = currentNode.getPosition(); + StringBuilder builder = new StringBuilder(); + + builder.append(StringUtils.rightPad(string, 90)); + builder.append("; "); + builder.append(currentNode.getClass().getSimpleName()); + builder.append(" in "); + builder.append(position.getLineNumber()); + builder.append(":"); + builder.append(position.getCharNumber()); + + return builder.toString(); + } + + /** Links the LLVM-Instructions to Monty-Nodes + * + * @param currentNode + * Node that is currently processed. */ + public void setNode(ASTNode currentNode) { + this.currentNode = currentNode; + } +} diff --git a/src/main/java/de/uni/bremen/monty/moco/codegeneration/context/Context.java b/src/main/java/de/uni/bremen/monty/moco/codegeneration/context/Context.java new file mode 100644 index 0000000..c257eca --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/codegeneration/context/Context.java @@ -0,0 +1,104 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.codegeneration.context; + +import org.apache.commons.lang3.StringUtils; + +import java.util.ArrayList; +import java.util.List; + +/** An .ll File is composed by a Tree of Context. This Tree is realized in this class with a recursive Structure that is + * created with the attribute {@link #innerContexts} + * + * The leaves are lines holding a single Instruction represented as {@link StringData}. Those leaves can be composed + * together in a Context. For e.g. a function in llvm is a context because it is a composition of statements. One could + * further subdivide a function into multiple parts. All functions inside a .ll file are further composed into a + * context, which is then the root of the .ll file. */ +public class Context implements ContextData { + + /** Recursive Structure creating a Tree */ + private List innerContexts; + private CommentAppender commentAppender; + private int indentation = 0; + + public Context(CommentAppender commentAppender) { + this.commentAppender = commentAppender; + innerContexts = new ArrayList<>(); + } + + /** Adds an LLVM-Instruction as a Leaf to the Tree. + * + * @param data */ + public void append(String data) { + data = StringUtils.repeat(" ", indentation * 4) + data; + // data = commentAppender.addComment(data); + innerContexts.add(new StringData(data + "\n")); + } + + /** Appends a Context to the Tree. This increases the depth of the Tree... + * + * @param c */ + public void append(Context c) { + innerContexts.add(c); + } + + /** Converts this into a List of instruction as a String. Each Instruction is a new Line in the String. This is done + * by flattening the Tree by concatenating. + * + * @return All the children in a String */ + public String getData() { + StringBuilder s = new StringBuilder(); + for (ContextData contextData : innerContexts) { + s.append(contextData.getData()); + } + return s.toString(); + } + + protected void indent() { + indentation++; + } + + protected void dedent() { + indentation--; + } + + protected void emptyLine() { + innerContexts.add(new StringData("\n")); + } +} diff --git a/src/main/java/de/uni/bremen/monty/moco/codegeneration/context/ContextData.java b/src/main/java/de/uni/bremen/monty/moco/codegeneration/context/ContextData.java new file mode 100644 index 0000000..58e93c4 --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/codegeneration/context/ContextData.java @@ -0,0 +1,43 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.codegeneration.context; + +interface ContextData { + public String getData(); +} diff --git a/src/main/java/de/uni/bremen/monty/moco/codegeneration/context/ContextUtils.java b/src/main/java/de/uni/bremen/monty/moco/codegeneration/context/ContextUtils.java new file mode 100644 index 0000000..d5e6813 --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/codegeneration/context/ContextUtils.java @@ -0,0 +1,123 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.codegeneration.context; + +import de.uni.bremen.monty.moco.ast.ASTNode; + +import java.util.Stack; + +/** Utility class for accessing different {@link Context} + * + * Holds the {@link #baseContext} which is the Context that represent a whole .ll file. */ +public class ContextUtils { + + private final CommentAppender commentAppender; + + /** represents a whole .ll file */ + private final CodeContext baseContext; + + /** on top of each .ll file there is an area where all constant declaration should be located. */ + private final CodeContext constantsContext; + + /** each function should have it's own CodeContext. This is where those are stored. The first Context in the Stack is + * the container of all functions in the .ll file and not the container for all statements in a function. + * + * A Stack is used because monty allows to have functions inside functions.(Despite having closures) LLVM doesn't + * support that feature. So while processing a function you may find another function, which you have to process. + * You start processing the new one, while saving the state of the old one in the stack */ + private Stack activeContexts; + + /** Creates a {@link #baseContext} and a {@link #constantsContext} and makes the constantContext part of the + * baseContext. */ + public ContextUtils() { + commentAppender = new CommentAppender(); + + baseContext = new CodeContext(commentAppender); + activeContexts = new Stack<>(); + activeContexts.push(baseContext); + + constantsContext = new CodeContext(commentAppender); + baseContext.append(constantsContext); + } + + /** Sets the current Node to the {@link #commentAppender} + * + * @param node + * ast node */ + public void setNode(ASTNode node) { + commentAppender.setNode(node); + } + + /** Returns the active Context. That is the Context in which the next instruction for LLVM from an 'normal' monty + * Statement should be saved. + * + * @return the active Context. */ + public CodeContext active() { + return activeContexts.peek(); + } + + /** Returns the constant Context. That is the Context in which the constant LLVM-declarations should be located. Like + * string literals. + * + * @return the constant Context. */ + public CodeContext constant() { + return constantsContext; + } + + /** Converts the {@link #baseContext} into a string. The baseContext represents a whole .ll File. So the data is the + * content of a .ll file. + * + * @return the converted {@link #baseContext} */ + public String getData() { + return baseContext.getData(); + } + + /** Adds a new Context to the {@link #activeContexts}. This should be used in the beginning of the processing of a + * monty function. So that the llvm instructions of the monty statements stored into this new Context */ + public void addNewContext() { + CodeContext context = new CodeContext(commentAppender); + activeContexts.push(context); + baseContext.append(context); + } + + /** Closes a Context opened with {@link #addNewContext()}. This should be done at the end of processing a function. */ + public void closeContext() { + activeContexts.pop(); + } +} diff --git a/src/main/java/de/uni/bremen/monty/moco/codegeneration/context/Operations.java b/src/main/java/de/uni/bremen/monty/moco/codegeneration/context/Operations.java new file mode 100644 index 0000000..c978124 --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/codegeneration/context/Operations.java @@ -0,0 +1,334 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ + +package de.uni.bremen.monty.moco.codegeneration.context; + +import static de.uni.bremen.monty.moco.codegeneration.types.LLVMTypeFactory.double64; +import static de.uni.bremen.monty.moco.codegeneration.types.LLVMTypeFactory.int1; +import static de.uni.bremen.monty.moco.codegeneration.types.LLVMTypeFactory.int32; +import static de.uni.bremen.monty.moco.codegeneration.types.LLVMTypeFactory.int64; +import static de.uni.bremen.monty.moco.codegeneration.types.LLVMTypeFactory.int8; +import static de.uni.bremen.monty.moco.codegeneration.types.LLVMTypeFactory.pointer; + +import java.util.Arrays; + +import de.uni.bremen.monty.moco.ast.CoreClasses; +import de.uni.bremen.monty.moco.codegeneration.Native; +import de.uni.bremen.monty.moco.codegeneration.CodeGenerator; +import de.uni.bremen.monty.moco.codegeneration.context.CodeContext.FcmpOperand; +import de.uni.bremen.monty.moco.codegeneration.context.CodeContext.IcmpOperand; +import de.uni.bremen.monty.moco.codegeneration.identifier.LLVMIdentifier; +import de.uni.bremen.monty.moco.codegeneration.identifier.LLVMIdentifierFactory; +import de.uni.bremen.monty.moco.codegeneration.types.*; +import de.uni.bremen.monty.moco.codegeneration.types.LLVMTypeFactory.*; + +import static de.uni.bremen.monty.moco.codegeneration.types.LLVMTypeFactory.*; + +public class Operations { + + private CodeGenerator codeGenerator; + private LLVMIdentifierFactory llvmIdentifierFactory; + + private LLVMIdentifier> stringFormat; + private LLVMIdentifier> intFormat; + private LLVMIdentifier> floatFormat; + private LLVMIdentifier> charFormat; + + public Operations(CodeGenerator codeGenerator, LLVMIdentifierFactory llvmIdentifierFactory) { + this.codeGenerator = codeGenerator; + this.llvmIdentifierFactory = llvmIdentifierFactory; + } + + @Native("M.Print.P.print$M.Char.C.Char") + public void printChar(CodeContext c, LLVMIdentifier addr) { + LLVMType type = addr.getType(); + LLVMIdentifier signature = llvmIdentifierFactory.newGlobal("printf", int32()); + c.call( + (LLVMIdentifier) (LLVMIdentifier) signature, + llvmIdentifierFactory.newLocal(signature.getType(), false), + Arrays.> asList(charFormat, addr), + "(i8*, ...)*"); + } + + @Native("M.Print.P.print$M.std.C.String") + public void printString(CodeContext c, LLVMIdentifier addr) { + LLVMType type = addr.getType(); + LLVMIdentifier signature = llvmIdentifierFactory.newGlobal("printf", int32()); + c.call( + (LLVMIdentifier) (LLVMIdentifier) signature, + llvmIdentifierFactory.newLocal(signature.getType(), false), + Arrays.> asList(stringFormat, addr), + "(i8*, ...)*"); + } + + @Native("M.Print.P.print$M.Int.C.Int") + public void printInt(CodeContext c, LLVMIdentifier addr) { + LLVMType type = addr.getType(); + LLVMIdentifier signature = llvmIdentifierFactory.newGlobal("printf", int32()); + c.call( + (LLVMIdentifier) (LLVMIdentifier) signature, + llvmIdentifierFactory.newLocal(signature.getType(), false), + Arrays.> asList(intFormat, addr), + "(i8*, ...)*"); + } + + @Native("M.Print.P.print$M.Bool.C.Bool") + public void printBool(CodeContext c, LLVMIdentifier addr) { + LLVMType type = addr.getType(); + LLVMIdentifier signature = llvmIdentifierFactory.newGlobal("printf", int32()); + c.call( + (LLVMIdentifier) (LLVMIdentifier) signature, + llvmIdentifierFactory.newLocal(signature.getType(), false), + Arrays.> asList(intFormat, addr), + "(i8*, ...)*"); + } + + @Native("M.Print.P.print$M.Float.C.Float") + public void printFloat(CodeContext c, LLVMIdentifier addr) { + LLVMType type = addr.getType(); + LLVMIdentifier signature = llvmIdentifierFactory.newGlobal("printf", int32()); + c.call( + (LLVMIdentifier) (LLVMIdentifier) signature, + llvmIdentifierFactory.newLocal(signature.getType(), false), + Arrays.> asList(floatFormat, addr), + "(i8*, ...)*"); + } + + @Native("M.Int.C.Int.F.operator_plus$M.Int.C.Int$M.Int.C.Int") + public LLVMIdentifier add(CodeContext c, LLVMIdentifier arg1, LLVMIdentifier arg2) { + return c.binaryOperation("add", arg1, arg2, llvmIdentifierFactory.newLocal(arg1.getType(), false)); + } + + @Native("M.Float.C.Float.F.operator_plus$M.Float.C.Float$M.Float.C.Float") + public LLVMIdentifier fadd(CodeContext c, LLVMIdentifier arg1, + LLVMIdentifier arg2) { + return c.binaryOperation("fadd", arg1, arg2, llvmIdentifierFactory.newLocal(arg1.getType(), false)); + } + + @Native("M.Int.C.Int.F.operator_minus$M.Int.C.Int$M.Int.C.Int") + public LLVMIdentifier sub(CodeContext c, LLVMIdentifier arg1, LLVMIdentifier arg2) { + return c.binaryOperation("sub", arg1, arg2, llvmIdentifierFactory.newLocal(arg1.getType(), false)); + } + + @Native("M.Int.C.Int.F.operator_minus$M.Int.C.Int") + public LLVMIdentifier sub(CodeContext c, LLVMIdentifier arg1) { + return c.binaryOperation( + "sub", + llvmIdentifierFactory.constant(int64(), 0), + arg1, + llvmIdentifierFactory.newLocal(arg1.getType(), false)); + } + + @Native("M.Float.C.Float.F.operator_minus$M.Float.C.Float") + public LLVMIdentifier fsub(CodeContext c, LLVMIdentifier arg1) { + return c.binaryOperation( + "fsub", + llvmIdentifierFactory.constant(double64(), 0.0f), + arg1, + llvmIdentifierFactory.newLocal(arg1.getType(), false)); + } + + @Native("M.Float.C.Float.F.operator_minus$M.Float.C.Float$M.Float.C.Float") + public LLVMIdentifier fsub(CodeContext c, LLVMIdentifier arg1, + LLVMIdentifier arg2) { + return c.binaryOperation("fsub", arg1, arg2, llvmIdentifierFactory.newLocal(arg1.getType(), false)); + } + + @Native("M.Int.C.Int.F.operator_mult$M.Int.C.Int$M.Int.C.Int") + public LLVMIdentifier mul(CodeContext c, LLVMIdentifier arg1, LLVMIdentifier arg2) { + return c.binaryOperation("mul", arg1, arg2, llvmIdentifierFactory.newLocal(arg1.getType(), false)); + } + + @Native("M.Float.C.Float.F.operator_mult$M.Float.C.Float$M.Float.C.Float") + public LLVMIdentifier fmul(CodeContext c, LLVMIdentifier arg1, + LLVMIdentifier arg2) { + return c.binaryOperation("fmul", arg1, arg2, llvmIdentifierFactory.newLocal(arg1.getType(), false)); + } + + @Native("M.Int.C.Int.F.operator_div$M.Int.C.Int$M.Int.C.Int") + public LLVMIdentifier sdiv(CodeContext c, LLVMIdentifier arg1, LLVMIdentifier arg2) { + return c.binaryOperation("sdiv", arg1, arg2, llvmIdentifierFactory.newLocal(arg1.getType(), false)); + } + + @Native("M.Float.C.Float.F.operator_div$M.Float.C.Float$M.Float.C.Float") + public LLVMIdentifier fdiv(CodeContext c, LLVMIdentifier arg1, + LLVMIdentifier arg2) { + return c.binaryOperation("fdiv", arg1, arg2, llvmIdentifierFactory.newLocal(arg1.getType(), false)); + } + + @Native("M.Int.C.Int.F.operator_equal$M.Bool.C.Bool$M.Int.C.Int") + public LLVMIdentifier intEq(CodeContext c, LLVMIdentifier arg1, LLVMIdentifier arg2) { + return c.icmp(IcmpOperand.eq, arg1, arg2, llvmIdentifierFactory.newLocal(int1(), false)); + } + + @Native("M.Bool.C.Bool.F.operator_equal$M.Bool.C.Bool$M.Bool.C.Bool") + public LLVMIdentifier boolEq(CodeContext c, LLVMIdentifier arg1, LLVMIdentifier arg2) { + return c.icmp(IcmpOperand.eq, arg1, arg2, llvmIdentifierFactory.newLocal(int1(), false)); + } + + @Native("M.Float.C.Float.F.operator_equal$M.Bool.C.Bool$M.Float.C.Float") + public LLVMIdentifier floatEq(CodeContext c, LLVMIdentifier arg1, + LLVMIdentifier arg2) { + return c.fcmp(FcmpOperand.oeq, arg1, arg2, llvmIdentifierFactory.newLocal(int1(), false)); + } + + @Native("M.Int.C.Int.F.operator_not_equal$M.Bool.C.Bool$M.Int.C.Int") + public LLVMIdentifier intNe(CodeContext c, LLVMIdentifier arg1, LLVMIdentifier arg2) { + return c.icmp(IcmpOperand.ne, arg1, arg2, llvmIdentifierFactory.newLocal(int1(), false)); + } + + @Native("M.Bool.C.Bool.F.operator_not_equal$M.Bool.C.Bool$M.Bool.C.Bool") + public LLVMIdentifier boolNe(CodeContext c, LLVMIdentifier arg1, LLVMIdentifier arg2) { + return c.icmp(IcmpOperand.ne, arg1, arg2, llvmIdentifierFactory.newLocal(int1(), false)); + } + + @Native("M.Float.C.Float.F.operator_not_equal$M.Bool.C.Bool$M.Float.C.Float") + public LLVMIdentifier floatNe(CodeContext c, LLVMIdentifier arg1, + LLVMIdentifier arg2) { + return c.fcmp(FcmpOperand.one, arg1, arg2, llvmIdentifierFactory.newLocal(int1(), false)); + } + + @Native("M.Int.C.Int.F.operator_lesser$M.Bool.C.Bool$M.Int.C.Int") + public LLVMIdentifier intSlt(CodeContext c, LLVMIdentifier arg1, LLVMIdentifier arg2) { + return c.icmp(IcmpOperand.slt, arg1, arg2, llvmIdentifierFactory.newLocal(int1(), false)); + } + + @Native("M.Float.C.Float.F.operator_lesser$M.Bool.C.Bool$M.Float.C.Float") + public LLVMIdentifier floatSlt(CodeContext c, LLVMIdentifier arg1, + LLVMIdentifier arg2) { + return c.fcmp(FcmpOperand.olt, arg1, arg2, llvmIdentifierFactory.newLocal(int1(), false)); + } + + @Native("M.Int.C.Int.F.operator_lesser_equal$M.Bool.C.Bool$M.Int.C.Int") + public LLVMIdentifier intSle(CodeContext c, LLVMIdentifier arg1, LLVMIdentifier arg2) { + return c.icmp(IcmpOperand.sle, arg1, arg2, llvmIdentifierFactory.newLocal(int1(), false)); + } + + @Native("M.Float.C.Float.F.operator_lesser_equal$M.Bool.C.Bool$M.Float.C.Float") + public LLVMIdentifier floatSle(CodeContext c, LLVMIdentifier arg1, + LLVMIdentifier arg2) { + return c.fcmp(FcmpOperand.ole, arg1, arg2, llvmIdentifierFactory.newLocal(int1(), false)); + } + + @Native("M.Int.C.Int.F.operator_greater$M.Bool.C.Bool$M.Int.C.Int") + public LLVMIdentifier intSgt(CodeContext c, LLVMIdentifier arg1, LLVMIdentifier arg2) { + return c.icmp(IcmpOperand.sgt, arg1, arg2, llvmIdentifierFactory.newLocal(int1(), false)); + } + + @Native("M.Float.C.Float.F.operator_greater$M.Bool.C.Bool$M.Float.C.Float") + public LLVMIdentifier floatSgt(CodeContext c, LLVMIdentifier arg1, + LLVMIdentifier arg2) { + return c.fcmp(FcmpOperand.ogt, arg1, arg2, llvmIdentifierFactory.newLocal(int1(), false)); + } + + @Native("M.Int.C.Int.F.operator_greater_equal$M.Bool.C.Bool$M.Int.C.Int") + public LLVMIdentifier intSge(CodeContext c, LLVMIdentifier arg1, LLVMIdentifier arg2) { + return c.icmp(IcmpOperand.sge, arg1, arg2, llvmIdentifierFactory.newLocal(int1(), false)); + } + + @Native("M.Float.C.Float.F.operator_greater_equal$M.Bool.C.Bool$M.Float.C.Float") + public LLVMIdentifier floatSge(CodeContext c, LLVMIdentifier arg1, + LLVMIdentifier arg2) { + return c.fcmp(FcmpOperand.oge, arg1, arg2, llvmIdentifierFactory.newLocal(int1(), false)); + } + + @Native("M.Bool.C.Bool.F.operator_and$M.Bool.C.Bool$M.Bool.C.Bool") + public LLVMIdentifier and(CodeContext c, LLVMIdentifier arg1, LLVMIdentifier arg2) { + return c.binaryOperation("and", arg1, arg2, llvmIdentifierFactory.newLocal(arg1.getType(), false)); + } + + @Native("M.Bool.C.Bool.F.operator_or$M.Bool.C.Bool$M.Bool.C.Bool") + public LLVMIdentifier or(CodeContext c, LLVMIdentifier arg1, LLVMIdentifier arg2) { + return c.binaryOperation("or", arg1, arg2, llvmIdentifierFactory.newLocal(arg1.getType(), false)); + } + + @Native("M.Bool.C.Bool.F.operator_xor$M.Bool.C.Bool$M.Bool.C.Bool") + public LLVMIdentifier xor(CodeContext c, LLVMIdentifier arg1, LLVMIdentifier arg2) { + return c.binaryOperation("xor", arg1, arg2, llvmIdentifierFactory.newLocal(arg1.getType(), false)); + } + + @Native("M.Bool.C.Bool.F.operator_not$M.Bool.C.Bool") + public LLVMIdentifier not(CodeContext c, LLVMIdentifier arg1) { + return c.binaryOperation( + "xor", + arg1, + llvmIdentifierFactory.constant(int1(), 1), + llvmIdentifierFactory.newLocal(arg1.getType(), false)); + } + + @Native("M.Int.C.Int.F.operator_rem$M.Int.C.Int$M.Int.C.Int") + public LLVMIdentifier srem(CodeContext c, LLVMIdentifier arg1, LLVMIdentifier arg2) { + return c.binaryOperation("srem", arg1, arg2, llvmIdentifierFactory.newLocal(arg1.getType(), false)); + } + + @Native("M.Array.F.operator_array_access$M.Int.C.Int$M.std.C.Array$M.Int.C.Int") + public LLVMIdentifier arrayAccess(CodeContext c, LLVMIdentifier arrayPointer, + LLVMIdentifier index) { + + LLVMIdentifier> arrayStructPointer = + (LLVMIdentifier>) (LLVMIdentifier) arrayPointer; + + codeGenerator.checkArrayBounds(c, arrayStructPointer, index); + LLVMIdentifier result = + llvmIdentifierFactory.newLocal(codeGenerator.mapToLLVMType(CoreClasses.intType())); + c.getelementptr( + result, + arrayStructPointer, + llvmIdentifierFactory.constant(int32(), 0), + llvmIdentifierFactory.constant(int32(), 1), + index); + return result; + } + + public void setStringFormat(LLVMIdentifier> stringFormat) { + this.stringFormat = stringFormat; + } + + public void setIntFormat(LLVMIdentifier> intFormat) { + this.intFormat = intFormat; + } + + public void setFloatFormat(LLVMIdentifier> floatFormat) { + this.floatFormat = floatFormat; + } + + public void setCharFormat(LLVMIdentifier> charformat) { + this.charFormat = charformat; + } +} diff --git a/src/main/java/de/uni/bremen/monty/moco/codegeneration/context/StringData.java b/src/main/java/de/uni/bremen/monty/moco/codegeneration/context/StringData.java new file mode 100644 index 0000000..090ab37 --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/codegeneration/context/StringData.java @@ -0,0 +1,52 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.codegeneration.context; + +class StringData implements ContextData { + private String data; + + public StringData(String data) { + this.data = data; + } + + @Override + public String getData() { + return data; + } +} diff --git a/src/main/java/de/uni/bremen/monty/moco/codegeneration/identifier/ArrayConstant.java b/src/main/java/de/uni/bremen/monty/moco/codegeneration/identifier/ArrayConstant.java new file mode 100644 index 0000000..e413f3e --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/codegeneration/identifier/ArrayConstant.java @@ -0,0 +1,64 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.codegeneration.identifier; + +import de.uni.bremen.monty.moco.codegeneration.types.LLVMType; +import de.uni.bremen.monty.moco.codegeneration.types.LLVMArrayType; +import org.apache.commons.lang3.StringUtils; + +import java.util.List; + +public class ArrayConstant extends LLVMIdentifier { + + private List> arguments; + + ArrayConstant(LLVMArrayType type, List> arguments) { + super(type, "", false); + this.arguments = arguments; + } + + public List> getArguments() { + return arguments; + } + + @Override + public String getName() { + return " [ " + StringUtils.join(arguments, ", ") + " ]"; + } +} diff --git a/src/main/java/de/uni/bremen/monty/moco/codegeneration/identifier/FunctionSignature.java b/src/main/java/de/uni/bremen/monty/moco/codegeneration/identifier/FunctionSignature.java new file mode 100644 index 0000000..c97ce59 --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/codegeneration/identifier/FunctionSignature.java @@ -0,0 +1,59 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.codegeneration.identifier; + +import de.uni.bremen.monty.moco.codegeneration.types.LLVMType; +import org.apache.commons.lang3.StringUtils; + +import java.util.List; + +public class FunctionSignature extends LLVMIdentifier { + + private List> parameter; + + FunctionSignature(T type, String name, List> parameter) { + super(type, name, false); + this.parameter = parameter; + } + + @Override + public String toString() { + return type + " " + name + "(" + StringUtils.join(parameter, ", ") + ")"; + } +} diff --git a/src/main/java/de/uni/bremen/monty/moco/codegeneration/identifier/LLVMIdentifier.java b/src/main/java/de/uni/bremen/monty/moco/codegeneration/identifier/LLVMIdentifier.java new file mode 100644 index 0000000..6983921 --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/codegeneration/identifier/LLVMIdentifier.java @@ -0,0 +1,96 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.codegeneration.identifier; + +import de.uni.bremen.monty.moco.codegeneration.types.LLVMType; + +/** LLVMIdentifier is the simple composition of an LLVMType and a name. In LLVM-IR you often have to write s.th. like + * 'i64 %0' as a part of an instruction. This is an LLVMIdentifier. And if you use {@link #toString()} it gives you the + * representation for LLVM-IR. + * + * The Type can be composed, see {@link LLVMType}. And the name can be more complex too. e.g. ' getelementptr inbounds + * (i8* %0, i32 0, i32 0) ' is currently modeled as a simple name for an identifier. + * + * Instances should only be created with the {@link LLVMIdentifierFactory}. + * + * @param + * The Type that is encapsulated in the Identifier. If you have e.g. 'i64* %2' the Type will be + * LLVMIdentifier> */ +public class LLVMIdentifier { + protected final String name; + protected final T type; + + /** This is indicates if this value is a concrete value, or a pointer to a value, that needs to be resolved or + * dereference to gets its value. */ + private boolean resolvable; + + /** Don't use this. Only {@link LLVMIdentifierFactory} should create instances. + * + * @param type + * @param name + * @param resolvable */ + LLVMIdentifier(T type, String name, boolean resolvable) { + this.name = name; + this.type = type; + this.resolvable = resolvable; + } + + public String getName() { + return name; + } + + public T getType() { + return type; + } + + /** @returns the LLVM-IR representation. e.g. new LLVMIdentifier(pointer(int64(),"%foobar").toString() == + * "i64* %foobar" */ + @Override + public String toString() { + return type + " " + name; + } + + /** Is it a value or a pointer to value + * + * @return true if its a pointer to a value */ + public boolean needToBeResolved() { + return resolvable; + } + +} diff --git a/src/main/java/de/uni/bremen/monty/moco/codegeneration/identifier/LLVMIdentifierFactory.java b/src/main/java/de/uni/bremen/monty/moco/codegeneration/identifier/LLVMIdentifierFactory.java new file mode 100644 index 0000000..08ce3a0 --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/codegeneration/identifier/LLVMIdentifierFactory.java @@ -0,0 +1,165 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.codegeneration.identifier; + +import de.uni.bremen.monty.moco.codegeneration.types.LLVMArrayType; +import de.uni.bremen.monty.moco.codegeneration.types.LLVMPointer; +import de.uni.bremen.monty.moco.codegeneration.types.LLVMStructType; +import de.uni.bremen.monty.moco.codegeneration.types.LLVMType; + +import java.util.List; +import java.util.Stack; +import java.util.concurrent.atomic.AtomicInteger; + +import static de.uni.bremen.monty.moco.codegeneration.types.LLVMTypeFactory.*; + +/** This Factory creates LLVMIdentifier. It has various Methods allowing you to create global or local Identifier, with a + * given name or a generated name, resolvable or not, and even elementPointer and functionSignatures + * + * LLVM use prefixes to differ local from global values. '@' is global '%' is local + * + * Abstract on LLVM Name Policy for local values: If you don't care about the name of a value you can just use a number. + * Like '%3' BUT this number must start with 0 for the first value in the scope and have to increment, without omitting + * one. This counter is only valid in a local scope. + * + * This is where the {@link #scope} comes into play. */ +public class LLVMIdentifierFactory { + + /** Global counter for global values. */ + private int strIndex = 0; + + /** + * + */ + private Stack scope = new Stack<>(); + + public LLVMIdentifierFactory() { + scope.push(new AtomicInteger()); + } + + public LLVMIdentifier newLocal(String symbol, T type, boolean resolvable) { + return new LLVMIdentifier<>(type, "%" + symbol, resolvable); + } + + public LLVMIdentifier newLocal(T type) { + return newLocal(type, true); + } + + private String newName() { + return "_unnamed_" + scope.peek().getAndIncrement(); + } + + private String newGlobalName() { + return "." + strIndex++; + } + + public void openScope() { + scope.push(new AtomicInteger()); + } + + public void closeScope() { + scope.pop(); + } + + public LLVMIdentifier newGlobal(String symbol, T type) { + return new LLVMIdentifier<>(type, "@" + symbol, true); + } + + public LLVMIdentifier newGlobal(T type) { + return new LLVMIdentifier<>(type, "@" + newGlobalName(), true); + } + + public LLVMIdentifier> pointerTo(LLVMIdentifier right) { + return new LLVMIdentifier<>(pointer(right.getType()), right.getName(), false); + } + + public LLVMIdentifier constant(T llvmType, int value) { + return new LLVMIdentifier<>(llvmType, value + "", false); + } + + public LLVMIdentifier constant(T llvmType, float value) { + return new LLVMIdentifier<>(llvmType, value + "", false); + } + + public LLVMIdentifier constant(T llvmType, boolean value) { + return new LLVMIdentifier<>(llvmType, value + "", false); + } + + public LLVMIdentifier> constantNull(LLVMPointer llvmType) { + return new LLVMIdentifier<>(llvmType, "null", false); + } + + public StructConstant constant(LLVMStructType llvmType, List> arguments) { + return new StructConstant(llvmType, arguments); + } + + public ArrayConstant constant(LLVMArrayType llvmType, List> arguments) { + return new ArrayConstant(llvmType, arguments); + } + + public LLVMIdentifier> elementPointerTo( + LLVMIdentifier> identifier) { + LLVMArrayType arrayType = identifier.getType(); + T typeInArray = arrayType.getInternalType(); + LLVMPointer pointer = pointer(typeInArray); + return new LLVMIdentifier<>(pointer, "getelementptr inbounds (" + arrayType + "* " + identifier.getName() + + ", i32 0, i32 0)", false); + } + + public FunctionSignature newFunction(T type, String s, + List> llvmTypes) { + return new FunctionSignature<>(type, "@" + s, llvmTypes); + } + + public LLVMIdentifier bitcast(LLVMIdentifier identifier, LLVMType toType) { + return new LLVMIdentifier<>(toType, "bitcast (" + identifier + " to " + toType + ")", false); + } + + public LLVMIdentifier newLocal(T type, boolean resolvable) { + return new LLVMIdentifier<>(type, "%" + newName(), resolvable); + } + + public LLVMIdentifier nameless(T type) { + return new LLVMIdentifier<>(type, "", false); + } + + public LLVMIdentifier voidId() { + return nameless(voidType()); + } +} diff --git a/src/main/java/de/uni/bremen/monty/moco/codegeneration/identifier/StructConstant.java b/src/main/java/de/uni/bremen/monty/moco/codegeneration/identifier/StructConstant.java new file mode 100644 index 0000000..31814fa --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/codegeneration/identifier/StructConstant.java @@ -0,0 +1,64 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.codegeneration.identifier; + +import de.uni.bremen.monty.moco.codegeneration.types.LLVMType; +import de.uni.bremen.monty.moco.codegeneration.types.LLVMStructType; +import org.apache.commons.lang3.StringUtils; + +import java.util.List; + +public class StructConstant extends LLVMIdentifier { + + private List> arguments; + + StructConstant(LLVMStructType type, List> arguments) { + super(type, "", false); + this.arguments = arguments; + } + + public List> getArguments() { + return arguments; + } + + @Override + public String getName() { + return " { " + StringUtils.join(arguments, ", ") + " }"; + } +} diff --git a/src/main/java/de/uni/bremen/monty/moco/codegeneration/types/LLVMArrayType.java b/src/main/java/de/uni/bremen/monty/moco/codegeneration/types/LLVMArrayType.java new file mode 100644 index 0000000..3555729 --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/codegeneration/types/LLVMArrayType.java @@ -0,0 +1,84 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.codegeneration.types; + +/** {@inheritDoc} */ +public class LLVMArrayType extends LLVMType { + + private final T internalType; + private final int size; + + LLVMArrayType(T internalType, int size) { + super(); + this.internalType = internalType; + this.size = size; + } + + @Override + public String toString() { + return "[" + size + " x " + internalType.toString() + "]"; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + LLVMArrayType llvmArray = (LLVMArrayType) o; + + if (size != llvmArray.size) return false; + + return internalType.equals(llvmArray.internalType); + } + + @Override + public int hashCode() { + int result = internalType.hashCode(); + result = 31 * result + size; + return result; + } + + public T getInternalType() { + return internalType; + } + + public int getSize() { + return size; + } +} diff --git a/src/main/java/de/uni/bremen/monty/moco/codegeneration/types/LLVMFunctionType.java b/src/main/java/de/uni/bremen/monty/moco/codegeneration/types/LLVMFunctionType.java new file mode 100644 index 0000000..d6c6d5d --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/codegeneration/types/LLVMFunctionType.java @@ -0,0 +1,83 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ + +package de.uni.bremen.monty.moco.codegeneration.types; + +import org.apache.commons.lang3.StringUtils; +import java.util.List; +import java.util.Objects; + +/** A function type in LLVM. This is the type of a pointer to a function. */ +public class LLVMFunctionType extends LLVMType { + + private LLVMType returnType; + private List parameter; + + LLVMFunctionType(LLVMType returnType, List parameter) { + this.returnType = returnType; + this.parameter = parameter; + } + + public LLVMType getReturnType() { + return returnType; + } + + public List getParameter() { + return parameter; + } + + @Override + public String toString() { + return returnType.toString() + " ( " + StringUtils.join(parameter, ",") + " )"; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + LLVMFunctionType that = (LLVMFunctionType) o; + return returnType.equals(that.returnType) && parameter.equals(that.parameter); + } + + @Override + public int hashCode() { + return Objects.hash(returnType, parameter); + } +} diff --git a/src/main/java/de/uni/bremen/monty/moco/codegeneration/types/LLVMPointer.java b/src/main/java/de/uni/bremen/monty/moco/codegeneration/types/LLVMPointer.java new file mode 100644 index 0000000..2d95655 --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/codegeneration/types/LLVMPointer.java @@ -0,0 +1,74 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.codegeneration.types; + +/** {@inheritDoc} */ +public class LLVMPointer extends LLVMType { + private T internalType; + + LLVMPointer(T internalType) { + this.internalType = internalType; + } + + @Override + public String toString() { + return internalType.toString() + "*"; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + LLVMPointer that = (LLVMPointer) o; + + if (!internalType.equals(that.internalType)) return false; + + return true; + } + + @Override + public int hashCode() { + return internalType.hashCode(); + } + + public T getInternalType() { + return internalType; + } +} diff --git a/src/main/java/de/uni/bremen/monty/moco/codegeneration/types/LLVMSimpleType.java b/src/main/java/de/uni/bremen/monty/moco/codegeneration/types/LLVMSimpleType.java new file mode 100644 index 0000000..222b8ec --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/codegeneration/types/LLVMSimpleType.java @@ -0,0 +1,72 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.codegeneration.types; + +/** {@inheritDoc} */ +public class LLVMSimpleType extends LLVMType { + + private String type; + + LLVMSimpleType(String type) { + this.type = type; + } + + @Override + public String toString() { + return type; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + LLVMSimpleType llvmType = (LLVMSimpleType) o; + + if (type != null ? !type.equals(llvmType.type) : llvmType.type != null) return false; + + return true; + } + + @Override + public int hashCode() { + return type != null ? type.hashCode() : 0; + } + +} diff --git a/src/main/java/de/uni/bremen/monty/moco/codegeneration/types/LLVMStructType.java b/src/main/java/de/uni/bremen/monty/moco/codegeneration/types/LLVMStructType.java new file mode 100644 index 0000000..d614b6b --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/codegeneration/types/LLVMStructType.java @@ -0,0 +1,72 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.codegeneration.types; + +/** A struct type in LLVM. In LLVM there are no classes, only structs. So the attributes of a class can be modeled as a + * struct but the functions have to be defined somewhere else. */ +public class LLVMStructType extends LLVMType { + + private String name; + + LLVMStructType(String name) { + this.name = name; + } + + @Override + public String toString() { + return name; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + LLVMStructType that = (LLVMStructType) o; + + if (!name.equals(that.name)) return false; + + return true; + } + + @Override + public int hashCode() { + return name.hashCode(); + } +} diff --git a/src/main/java/de/uni/bremen/monty/moco/codegeneration/types/LLVMType.java b/src/main/java/de/uni/bremen/monty/moco/codegeneration/types/LLVMType.java new file mode 100644 index 0000000..0ed0eb8 --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/codegeneration/types/LLVMType.java @@ -0,0 +1,61 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.codegeneration.types; + +/** An LLVMType represents a type for LLVM-IR. This can be a LLVMSimpleType like 'i64' or an composed Type like 'i8*'. + * SubTypes like LLVMPointer or LLVMArrayType are designed that they can be composed freely. + * + * If you want an Pointer to an Array with Pointers to boolean values you can write: + * LLVMPointer>> type = pointer(array(pointer(int1()),2)) using the factory Methods + * in LLVMTypeFactory. + * + * {@link #toString()} is overwritten in such a way, that it results in the String that represent this type in LLVM-IR + * e.g. type.toString() == "[2 x i1*]*" + * + * Only use {@link LLVMTypeFactory} to instantiate LLVMTypes. */ +public abstract class LLVMType { + + public abstract String toString(); + + @Override + public abstract boolean equals(Object o); + + @Override + public abstract int hashCode(); +} diff --git a/src/main/java/de/uni/bremen/monty/moco/codegeneration/types/LLVMTypeFactory.java b/src/main/java/de/uni/bremen/monty/moco/codegeneration/types/LLVMTypeFactory.java new file mode 100644 index 0000000..f43ce80 --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/codegeneration/types/LLVMTypeFactory.java @@ -0,0 +1,154 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.codegeneration.types; + +import java.util.List; +import org.apache.commons.lang3.StringUtils; + +public class LLVMTypeFactory { + + public static LLVMInt64 int64() { + return new LLVMInt64(); + } + + public static LLVMInt8 int8() { + return new LLVMInt8(); + } + + public static LLVMInt32 int32() { + return new LLVMInt32(); + } + + public static LLVMBool int1() { + return new LLVMBool(); + } + + public static LLVMFloat float32() { + return new LLVMFloat(); + } + + public static LLVMDouble double64() { + return new LLVMDouble(); + } + + public static LLVMPointer pointer(T type) { + return new LLVMPointer<>(type); + } + + public static LLVMArrayType array(T type, int size) { + return new LLVMArrayType<>(type, size); + } + + public static LLVMNotDefinedType notDefined() { + return new LLVMNotDefinedType(); + } + + public static LLVMVoidType voidType() { + return new LLVMVoidType(); + } + + public static interface LLVMIntType { + } + + public static class LLVMVoidType extends LLVMSimpleType { + public LLVMVoidType() { + super("void"); + } + } + + public static class LLVMNotDefinedType extends LLVMSimpleType { + public LLVMNotDefinedType() { + super("..."); + } + } + + public abstract static class LLVMInt extends LLVMSimpleType { + LLVMInt(String type) { + super(type); + } + } + + public static class LLVMInt64 extends LLVMInt { + public LLVMInt64() { + super("i64"); + } + } + + public static class LLVMInt8 extends LLVMInt { + public LLVMInt8() { + super("i8"); + } + } + + public static class LLVMInt32 extends LLVMInt { + public LLVMInt32() { + super("i32"); + } + } + + public static class LLVMBool extends LLVMSimpleType implements LLVMIntType { + public LLVMBool() { + super("i1"); + } + } + + public static class LLVMFloat extends LLVMSimpleType { + public LLVMFloat() { + super("float"); + } + } + + public static class LLVMDouble extends LLVMSimpleType { + public LLVMDouble() { + super("double"); + } + } + + public static LLVMStructType struct(String name) { + return new LLVMStructType("%" + name); + } + + public static LLVMStructType struct(List types) { + return new LLVMStructType(" { " + StringUtils.join(types, ", ") + " }"); + } + + public static LLVMFunctionType function(LLVMType returnType, List parameter) { + return new LLVMFunctionType(returnType, parameter); + } +} diff --git a/src/main/java/de/uni/bremen/monty/moco/codegeneration/types/TypeConverter.java b/src/main/java/de/uni/bremen/monty/moco/codegeneration/types/TypeConverter.java new file mode 100644 index 0000000..02b945d --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/codegeneration/types/TypeConverter.java @@ -0,0 +1,217 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ + +package de.uni.bremen.monty.moco.codegeneration.types; + +import de.uni.bremen.monty.moco.ast.ASTNode; +import de.uni.bremen.monty.moco.ast.CoreClasses; +import de.uni.bremen.monty.moco.ast.declaration.*; +import de.uni.bremen.monty.moco.codegeneration.identifier.LLVMIdentifier; +import de.uni.bremen.monty.moco.codegeneration.identifier.LLVMIdentifierFactory; +import de.uni.bremen.monty.moco.codegeneration.context.CodeContext; +import de.uni.bremen.monty.moco.codegeneration.context.CodeContext.Linkage; + +import java.util.*; + +import static de.uni.bremen.monty.moco.codegeneration.types.LLVMTypeFactory.*; + +public class TypeConverter { + private Map typeMap = new HashMap<>(); + private LLVMIdentifierFactory llvmIdentifierFactory; + private CodeContext constantContext; + + public TypeConverter(LLVMIdentifierFactory llvmIdentifierFactory, CodeContext constantContext) { + this.llvmIdentifierFactory = llvmIdentifierFactory; + this.constantContext = constantContext; + initPreDefinedTypes(); + } + + private void initPreDefinedTypes() { + typeMap.put(CoreClasses.stringType(), pointer(int8())); + typeMap.put(CoreClasses.voidType(), voidType()); + } + + private LLVMPointer convertType(ProcedureDeclaration type) { + List parameter = new ArrayList<>(); + final ASTNode grandFatherNode = type.getParentNode().getParentNode(); + if (grandFatherNode instanceof ClassDeclaration) { + ClassDeclaration typeDeclaration = (ClassDeclaration) grandFatherNode; + parameter.add(mapToLLVMType(typeDeclaration)); + } + for (VariableDeclaration varDecl : type.getParameter()) { + parameter.add(mapToLLVMType(varDecl.getType())); + } + if (type instanceof FunctionDeclaration) { + FunctionDeclaration func = (FunctionDeclaration) type; + return pointer(function(mapToLLVMType(func.getReturnType()), parameter)); + } + return pointer(function(voidType(), parameter)); + } + + private LLVMPointer convertType(ClassDeclaration type) { + return pointer(struct(type.getMangledIdentifier().getSymbol())); + } + + public TypeDeclaration mapToBoxedType(LLVMType type) { + if (type instanceof LLVMBool) { + return CoreClasses.boolType(); + } else if (type instanceof LLVMInt) { + return CoreClasses.intType(); + } else if (type instanceof LLVMDouble) { + return CoreClasses.floatType(); + } else if (type instanceof LLVMInt8) { + return CoreClasses.charType(); + } + return null; + } + + private T convertType(TypeDeclaration type) { + if (type instanceof ProcedureDeclaration) { + return (T) convertType((ProcedureDeclaration) type); + } + return (T) convertType((ClassDeclaration) type); + } + + private void addType(TypeDeclaration typeDecl) { + if (typeDecl == CoreClasses.arrayType()) { + addArray(typeDecl); + } else if (typeDecl instanceof ClassDeclaration) { + addClass((ClassDeclaration) typeDecl); + } + } + + private void addClass(ClassDeclaration classDecl) { + String mangledNodeName = classDecl.getMangledIdentifier().getSymbol(); + LLVMStructType llvmClassType = struct(classDecl.getMangledIdentifier().getSymbol()); + List llvmClassTypeDeclarations = new ArrayList<>(); + + LLVMStructType llvmVMTType = struct(mangledNodeName + "_vmt_type"); + List llvmVMTTypeDeclarations = new ArrayList<>(); + llvmClassTypeDeclarations.add(pointer(llvmVMTType)); + + LLVMIdentifier llvmVMTDataIdentifier = + llvmIdentifierFactory.newGlobal(mangledNodeName + "_vmt_data", (LLVMType) llvmVMTType); + List> llvmVMTDataInitializer = new ArrayList<>(); + + List recursiveSuperClassDeclarations = classDecl.getSuperClassDeclarationsRecursive(); + LLVMArrayType llvmCTDataType = array(pointer(int8()), recursiveSuperClassDeclarations.size() + 1); + LLVMIdentifier llvmCTDataIdentifier = + llvmIdentifierFactory.newGlobal(mangledNodeName + "_ct_data", (LLVMType) llvmCTDataType); + List> llvmCTDataInitializer = new ArrayList<>(); + + llvmVMTTypeDeclarations.add(pointer(llvmCTDataType)); + llvmVMTDataInitializer.add((LLVMIdentifier) (LLVMIdentifier) llvmIdentifierFactory.pointerTo(llvmCTDataIdentifier)); + + for (ClassDeclaration classDeclaration : recursiveSuperClassDeclarations) { + // Ensure that addType() was called for this classDeclaration so that a VMT/CT was generated. + mapToLLVMType(classDeclaration); + LLVMIdentifier vmtDataIdent = + llvmIdentifierFactory.newGlobal( + classDeclaration.getMangledIdentifier().getSymbol() + "_vmt_data", + (LLVMType) pointer(struct(classDeclaration.getMangledIdentifier().getSymbol() + "_vmt_type"))); + llvmCTDataInitializer.add(llvmIdentifierFactory.bitcast(vmtDataIdent, pointer(int8()))); + } + llvmCTDataInitializer.add((LLVMIdentifier) (LLVMIdentifier) llvmIdentifierFactory.constantNull(pointer(int8()))); + + if (classDecl == CoreClasses.intType()) { + llvmClassTypeDeclarations.add(LLVMTypeFactory.int64()); + } else if (classDecl == CoreClasses.boolType()) { + llvmClassTypeDeclarations.add(LLVMTypeFactory.int1()); + } else if (classDecl == CoreClasses.floatType()) { + llvmClassTypeDeclarations.add(LLVMTypeFactory.double64()); + } else if (classDecl == CoreClasses.charType()) { + llvmClassTypeDeclarations.add(LLVMTypeFactory.int8()); + } + + for (ClassDeclaration classDeclaration : recursiveSuperClassDeclarations) { + for (Declaration decl : classDeclaration.getBlock().getDeclarations()) { + if (decl instanceof VariableDeclaration) { + llvmClassTypeDeclarations.add(mapToLLVMType(((VariableDeclaration) decl).getType())); + } + } + } + for (ProcedureDeclaration procedure : classDecl.getVirtualMethodTable()) { + if (!procedure.isInitializer()) { + LLVMType signature = mapToLLVMType(procedure); + llvmVMTTypeDeclarations.add(signature); + llvmVMTDataInitializer.add(llvmIdentifierFactory.newGlobal( + procedure.getMangledIdentifier().getSymbol(), + signature)); + } + } + constantContext.type(llvmVMTType, llvmVMTTypeDeclarations); + constantContext.type(llvmClassType, llvmClassTypeDeclarations); + constantContext.global( + Linkage.priv, + llvmCTDataIdentifier, + true, + llvmIdentifierFactory.constant(llvmCTDataType, llvmCTDataInitializer)); + constantContext.global( + Linkage.priv, + llvmVMTDataIdentifier, + true, + llvmIdentifierFactory.constant(llvmVMTType, llvmVMTDataInitializer)); + } + + private void addArray(TypeDeclaration typeDecl) { + // Temporary until object or generic + LLVMType llvmType = mapToLLVMType((TypeDeclaration) CoreClasses.intType()); + List list = Arrays.asList(int64(), array(llvmType, 0)); + LLVMStructType type = struct(typeDecl.getMangledIdentifier().getSymbol()); + constantContext.type(type, list); + } + + public LLVMPointer mapToLLVMType(ClassDeclaration type) { + return (LLVMPointer) mapToLLVMType((TypeDeclaration) type); + } + + public LLVMPointer mapToLLVMType(ProcedureDeclaration type) { + return (LLVMPointer) mapToLLVMType((TypeDeclaration) type); + } + + public T mapToLLVMType(TypeDeclaration type) { + T llvmType = (T) typeMap.get(type); + if (llvmType == null) { + llvmType = convertType(type); + typeMap.put(type, llvmType); + addType(type); + } + return llvmType; + } +} diff --git a/src/main/java/de/uni/bremen/monty/moco/codegeneration/voodoo/BlackMagic.java b/src/main/java/de/uni/bremen/monty/moco/codegeneration/voodoo/BlackMagic.java new file mode 100644 index 0000000..a4abf65 --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/codegeneration/voodoo/BlackMagic.java @@ -0,0 +1,93 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ + +package de.uni.bremen.monty.moco.codegeneration.voodoo; + +import de.uni.bremen.monty.moco.codegeneration.Native; +import de.uni.bremen.monty.moco.codegeneration.context.CodeContext; +import de.uni.bremen.monty.moco.codegeneration.context.Operations; +import de.uni.bremen.monty.moco.codegeneration.identifier.LLVMIdentifier; +import de.uni.bremen.monty.moco.codegeneration.types.LLVMType; +import de.uni.bremen.monty.moco.exception.NotYetImplementedException; +import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +public class BlackMagic { + private Operations operations; + + public BlackMagic(Operations operations) { + this.operations = operations; + } + + public LLVMIdentifier generateNativeFunction(CodeContext c, String symbol, List> arguments) { + Method[] methods = Operations.class.getMethods(); + for (Method method : methods) { + if (correctMethod(method, symbol)) { + try { + return (LLVMIdentifier) method.invoke(operations, mergeArguments(c, arguments)); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + } + throw new NotYetImplementedException("\"" + symbol + "\" is not defined yet"); + } + + private Object[] mergeArguments(CodeContext c, List> arguments) { + ArrayList mergedArgs = new ArrayList(); + mergedArgs.add(c); + mergedArgs.addAll(arguments); + return mergedArgs.toArray(); + } + + private boolean correctMethod(Method method, String symbol) { + Native nativeAnnotation = method.getAnnotation(Native.class); + if (nativeAnnotation != null) { + boolean isOperation = nativeAnnotation.value().equals(symbol); + boolean otherNativeFunction = nativeAnnotation.value().equals(symbol); + + return otherNativeFunction || isOperation; + } + return false; + } +} diff --git a/src/main/java/de/uni/bremen/monty/moco/exception/InvalidControlFlowException.java b/src/main/java/de/uni/bremen/monty/moco/exception/InvalidControlFlowException.java new file mode 100644 index 0000000..0beaa4a --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/exception/InvalidControlFlowException.java @@ -0,0 +1,47 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.exception; + +import de.uni.bremen.monty.moco.ast.ASTNode; + +public class InvalidControlFlowException extends MontyBaseException { + public InvalidControlFlowException(ASTNode node, String message) { + super(node, message); + } +} diff --git a/src/main/java/de/uni/bremen/monty/moco/exception/InvalidExpressionException.java b/src/main/java/de/uni/bremen/monty/moco/exception/InvalidExpressionException.java new file mode 100644 index 0000000..13066be --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/exception/InvalidExpressionException.java @@ -0,0 +1,47 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.exception; + +import de.uni.bremen.monty.moco.ast.ASTNode; + +public class InvalidExpressionException extends MontyBaseException { + public InvalidExpressionException(ASTNode node, String message) { + super(node, message); + } +} diff --git a/src/main/java/de/uni/bremen/monty/moco/exception/InvalidPlaceToDeclareException.java b/src/main/java/de/uni/bremen/monty/moco/exception/InvalidPlaceToDeclareException.java new file mode 100644 index 0000000..8badd49 --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/exception/InvalidPlaceToDeclareException.java @@ -0,0 +1,47 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.exception; + +import de.uni.bremen.monty.moco.ast.ASTNode; + +public class InvalidPlaceToDeclareException extends MontyBaseException { + public InvalidPlaceToDeclareException(ASTNode node, String message) { + super(node, message); + } +} diff --git a/src/main/java/de/uni/bremen/monty/moco/exception/MontyBaseException.java b/src/main/java/de/uni/bremen/monty/moco/exception/MontyBaseException.java new file mode 100644 index 0000000..e7b89ad --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/exception/MontyBaseException.java @@ -0,0 +1,59 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ + +package de.uni.bremen.monty.moco.exception; + +import de.uni.bremen.monty.moco.ast.ASTNode; + +public class MontyBaseException extends RuntimeException { + protected ASTNode node; + + public MontyBaseException(String message) { + super(message); + } + + public MontyBaseException(ASTNode node, String message) { + super(message); + this.node = node; + } + + public ASTNode getNode() { + return node; + } +} diff --git a/src/main/java/de/uni/bremen/monty/moco/exception/NotYetImplementedException.java b/src/main/java/de/uni/bremen/monty/moco/exception/NotYetImplementedException.java new file mode 100644 index 0000000..430e353 --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/exception/NotYetImplementedException.java @@ -0,0 +1,49 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.exception; + +public class NotYetImplementedException extends RuntimeException { + + public NotYetImplementedException() { + } + + public NotYetImplementedException(String message) { + super(message); + } +} diff --git a/src/main/java/de/uni/bremen/monty/moco/exception/RedeclarationException.java b/src/main/java/de/uni/bremen/monty/moco/exception/RedeclarationException.java new file mode 100644 index 0000000..5d73586 --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/exception/RedeclarationException.java @@ -0,0 +1,47 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.exception; + +import de.uni.bremen.monty.moco.ast.ASTNode; + +public class RedeclarationException extends MontyBaseException { + public RedeclarationException(ASTNode node, String message) { + super(node, message); + } +} diff --git a/src/main/java/de/uni/bremen/monty/moco/exception/TypeMismatchException.java b/src/main/java/de/uni/bremen/monty/moco/exception/TypeMismatchException.java new file mode 100644 index 0000000..dbee276 --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/exception/TypeMismatchException.java @@ -0,0 +1,47 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.exception; + +import de.uni.bremen.monty.moco.ast.ASTNode; + +public class TypeMismatchException extends MontyBaseException { + public TypeMismatchException(ASTNode node, String message) { + super(node, message); + } +} diff --git a/src/main/java/de/uni/bremen/monty/moco/exception/UnknownIdentifierException.java b/src/main/java/de/uni/bremen/monty/moco/exception/UnknownIdentifierException.java new file mode 100644 index 0000000..d6f9fc4 --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/exception/UnknownIdentifierException.java @@ -0,0 +1,48 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.exception; + +import de.uni.bremen.monty.moco.ast.ResolvableIdentifier; + +public class UnknownIdentifierException extends MontyBaseException { + + public UnknownIdentifierException(ResolvableIdentifier identifier) { + super("Identifier is not defined: " + identifier); + } +} diff --git a/src/main/java/de/uni/bremen/monty/moco/exception/UnknownTypeException.java b/src/main/java/de/uni/bremen/monty/moco/exception/UnknownTypeException.java new file mode 100644 index 0000000..2cb3278 --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/exception/UnknownTypeException.java @@ -0,0 +1,48 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.exception; + +import de.uni.bremen.monty.moco.ast.ResolvableIdentifier; + +public class UnknownTypeException extends MontyBaseException { + + public UnknownTypeException(ResolvableIdentifier identifier) { + super("Type is not defined: " + identifier); + } +} diff --git a/src/main/java/de/uni/bremen/monty/moco/util/MontyFile.java b/src/main/java/de/uni/bremen/monty/moco/util/MontyFile.java new file mode 100644 index 0000000..a66585f --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/util/MontyFile.java @@ -0,0 +1,87 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ + +package de.uni.bremen.monty.moco.util; + +import org.apache.commons.io.filefilter.DirectoryFileFilter; +import org.apache.commons.io.filefilter.SuffixFileFilter; + +import java.io.*; +import java.net.URI; +import java.util.Arrays; + +public class MontyFile extends File implements MontyResource { + + public MontyFile(URI uri) { + super(uri); + } + + @Override + public MontyResource[] listSubPackages() { + File[] files = listFiles((FileFilter) DirectoryFileFilter.DIRECTORY); + MontyResource[] montyResources = convertAllFiles(files); + Arrays.sort(montyResources); + return montyResources; + } + + private MontyResource[] convertAllFiles(File[] files) { + MontyResource[] resources = new MontyResource[files.length]; + for (int i = 0; i < files.length; i++) { + resources[i] = new MontyFile(files[i].toURI()); + } + return resources; + } + + @Override + public InputStream toInputStream() throws FileNotFoundException { + return new FileInputStream(this); + } + + @Override + public MontyResource[] listSubModules() { + MontyResource[] montyResources = convertAllFiles(listFiles((FilenameFilter) new SuffixFileFilter(".monty"))); + Arrays.sort(montyResources); + return montyResources; + } + + public MontyFile(String pathname) { + super(pathname); + } + +} diff --git a/src/main/java/de/uni/bremen/monty/moco/util/MontyJar.java b/src/main/java/de/uni/bremen/monty/moco/util/MontyJar.java new file mode 100644 index 0000000..456d4e5 --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/util/MontyJar.java @@ -0,0 +1,126 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ + +package de.uni.bremen.monty.moco.util; + +import org.apache.commons.lang3.StringUtils; + +import java.io.IOException; +import java.io.InputStream; +import java.net.JarURLConnection; +import java.net.URL; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; +import java.util.Enumeration; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; + +public class MontyJar implements MontyResource { + + private final JarFile jarFile; + private final JarEntry jarEntry; + private final static Comparator comparator = createComparator(); + + public MontyJar(URL url) throws IOException { + JarURLConnection urlConnection = (JarURLConnection) url.openConnection(); + jarFile = urlConnection.getJarFile(); + jarEntry = urlConnection.getJarEntry(); + } + + public MontyJar(JarFile jarFile, JarEntry jarEntry) { + this.jarFile = jarFile; + this.jarEntry = jarEntry; + } + + @Override + public MontyResource[] listSubPackages() { + return getSubResources(true); + } + + @Override + public InputStream toInputStream() throws IOException { + return jarFile.getInputStream(jarEntry); + } + + @Override + public String getName() { + return jarEntry.getName(); + } + + @Override + public MontyResource[] listSubModules() throws IOException { + return getSubResources(false); + } + + private MontyResource[] getSubResources(boolean showFiles) { + ArrayList list = new ArrayList<>(); + + Enumeration entries = jarFile.entries(); + while (entries.hasMoreElements()) { + JarEntry x = entries.nextElement(); + + if (x.getName().startsWith(jarEntry.getName())) { + String substring = x.getName().substring(jarEntry.getName().length()); + + if (!substring.equals("")) { + if (showFiles == substring.contains("/")) { + if (!showFiles || StringUtils.countMatches(substring, "/") == 1 + && substring.indexOf("/") == substring.length() - 1) { + list.add(new MontyJar(jarFile, x)); + } + } + } + + } + } + MontyResource[] montyResources = list.toArray(new MontyResource[list.size()]); + Arrays.sort(montyResources, comparator); + return montyResources; + } + + private static Comparator createComparator() { + return new Comparator() { + @Override + public int compare(MontyResource o1, MontyResource o2) { + return o1.getName().compareTo(o2.getName()); + } + }; + } +} diff --git a/src/main/java/de/uni/bremen/monty/moco/util/MontyResource.java b/src/main/java/de/uni/bremen/monty/moco/util/MontyResource.java new file mode 100644 index 0000000..04cddb4 --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/util/MontyResource.java @@ -0,0 +1,54 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ + +package de.uni.bremen.monty.moco.util; + +import java.io.IOException; +import java.io.InputStream; + +public interface MontyResource { + + abstract public MontyResource[] listSubPackages(); + + abstract public InputStream toInputStream() throws IOException; + + abstract public String getName(); + + abstract public MontyResource[] listSubModules() throws IOException; +} diff --git a/src/main/java/de/uni/bremen/monty/moco/util/Params.java b/src/main/java/de/uni/bremen/monty/moco/util/Params.java new file mode 100644 index 0000000..c8dc423 --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/util/Params.java @@ -0,0 +1,146 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.util; + +import java.io.File; + +public class Params { + private String inputFolder; + private String mainModule; + + private boolean debugParseTree; + private String inputFile; + private String outputFile; + private boolean usePrintVisitor; + private boolean generateOnlyLLVM; + private boolean keepLLVMCode; + private boolean stopOnFirstError; + private String llFile; + + public Params(String[] args) { + if (args.length == 0 || args[0].equals("-h") || args[0].equals("--help")) { + printHelp(); + } + + for (int i = 0; i < args.length; i++) { + String arg = args[i]; + if (arg.equals("-p")) { + usePrintVisitor = true; + } else if (arg.equals("-ll")) { + generateOnlyLLVM = true; + } else if (arg.equals("-o")) { + outputFile = args[++i]; + } else if (arg.equals("-k")) { + keepLLVMCode = true; + } else if (arg.equals("-s")) { + debugParseTree = true; + } else if (arg.equals("-e")) { + stopOnFirstError = true; + } else { + if (new File(args[i]).isDirectory()) { + inputFolder = args[i]; + } else if (inputFolder != null) { + mainModule = args[i]; + } else { + inputFile = args[i]; + } + } + } + + if (inputFile == null && (inputFolder == null || mainModule == null)) { + printHelp(); + } + } + + public String getInputFile() { + return inputFile; + } + + public String getOutputFile() { + return outputFile; + } + + public boolean usePrintVisitor() { + return usePrintVisitor; + } + + public boolean isGenerateOnlyLLVM() { + return generateOnlyLLVM; + } + + public boolean isKeepLLVMCode() { + return keepLLVMCode; + } + + public boolean isStopOnFirstError() { + return stopOnFirstError; + } + + public boolean isDebugParseTree() { + return debugParseTree; + } + + public void printHelp() { + System.out.println("moco [args] inputFile [-o outputFile]"); + System.out.println("execute monty File"); + + System.out.println("-s\tdebug ANTLR parse Tree"); + System.out.println("-p\tprint AST without code generation"); + System.out.println("-ll\tgenerate only LLVM code"); + System.out.println("-k\tkeep LLVM Code"); + System.out.println("-e\tstop on first error"); + System.exit(-1); + } + + public void setLlFile(String llFile) { + this.llFile = llFile; + } + + public String getLlFile() { + return llFile; + } + + public String getInputFolder() { + return inputFolder; + } + + public String getMainModule() { + return mainModule; + } +} diff --git a/src/main/java/de/uni/bremen/monty/moco/util/ParseTreePrinter.java b/src/main/java/de/uni/bremen/monty/moco/util/ParseTreePrinter.java new file mode 100644 index 0000000..21f58b7 --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/util/ParseTreePrinter.java @@ -0,0 +1,127 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.util; + +import org.antlr.v4.runtime.Parser; +import org.antlr.v4.runtime.ParserRuleContext; +import org.antlr.v4.runtime.misc.Utils; +import org.antlr.v4.runtime.tree.ErrorNode; +import org.antlr.v4.runtime.tree.ParseTreeListener; +import org.antlr.v4.runtime.tree.TerminalNode; +import org.antlr.v4.runtime.tree.Trees; + +import java.util.Arrays; +import java.util.List; + +public class ParseTreePrinter implements ParseTreeListener { + private final List ruleNames; + private final StringBuilder builder = new StringBuilder(); + private int intend = 0; + private ParserRuleContext lastOne; + private boolean intended; + + public ParseTreePrinter(Parser parser) { + this.ruleNames = Arrays.asList(parser.getRuleNames()); + } + + @Override + public void visitTerminal(TerminalNode node) { + if (builder.length() > 0) { + builder.append(' '); + } + + append(Utils.escapeWhitespace(Trees.getNodeText(node, ruleNames), false)); + } + + @Override + public void visitErrorNode(ErrorNode node) { + if (builder.length() > 0) { + builder.append(' '); + } + + append(Utils.escapeWhitespace(Trees.getNodeText(node, ruleNames), false)); + } + + @Override + public void enterEveryRule(ParserRuleContext ctx) { + builder.append("\n"); + intended = false; + + if (builder.length() > 0) { + builder.append(' '); + } + + if (!ctx.equals(lastOne)) { + intend++; + } + + int ruleIndex = ctx.getRuleIndex(); + String ruleName; + if (ruleIndex >= 0 && ruleIndex < ruleNames.size()) { + ruleName = ruleNames.get(ruleIndex); + } else { + ruleName = Integer.toString(ruleIndex); + } + + append(ruleName); + lastOne = ctx; + } + + private void append(String ruleName) { + if (!intended) { + for (int i = 0; i < intend; i++) { + builder.append(' '); + } + intended = true; + } + builder.append(ruleName); + } + + @Override + public void exitEveryRule(ParserRuleContext ctx) { + if (ctx.getChildCount() > 0) { + intend--; + } + } + + @Override + public String toString() { + return builder.toString(); + } +} diff --git a/src/main/java/de/uni/bremen/monty/moco/visitor/BaseVisitor.java b/src/main/java/de/uni/bremen/monty/moco/visitor/BaseVisitor.java new file mode 100644 index 0000000..f393647 --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/visitor/BaseVisitor.java @@ -0,0 +1,449 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.visitor; + +import de.uni.bremen.monty.moco.ast.ASTNode; +import de.uni.bremen.monty.moco.ast.Block; +import de.uni.bremen.monty.moco.ast.Import; +import de.uni.bremen.monty.moco.ast.Package; +import de.uni.bremen.monty.moco.ast.declaration.*; +import de.uni.bremen.monty.moco.ast.expression.*; +import de.uni.bremen.monty.moco.ast.expression.literal.*; +import de.uni.bremen.monty.moco.ast.statement.*; +import de.uni.bremen.monty.moco.exception.MontyBaseException; + +/** This is the base-visitor to be subclassed by all visitors. + * + * It implements methods for all node-types that call node.visitChildren() (so the node must implement this method). + * Override if necessary. + * + * If you want to visit a node in the implementation of a visit()-method just use visit(node). */ +public class BaseVisitor { + + /** Count the exceptions caught in visit(ASTNode) **/ + private int errorCounter; + + /** Stop on the first error that is encountered **/ + private boolean stopOnFirstError; + + /** Comfort method to visit a node via double-dispatch. + * + * @param node + * the node to visit */ + public final void visitDoubleDispatched(ASTNode node) { + try { + onEnterEachNode(node); + node.visit(this); + onExitEachNode(node); + } catch (RuntimeException exception) { + errorCounter += 1; + if (stopOnFirstError) { + throw exception; + } else { + logError(exception); + } + } + } + + /** Returns information used in the exceptions that includes the ASTNodes name (optional additional information) and + * (if available) the position. + * + * @return the node information */ + public String getNodeInformation(ASTNode node) { + if (node == null) { + return "null"; + } else if (node.getPosition() != null) { + return String.format("%s at %s", node.toString(), node.getPosition().toString()); + } + return node.toString(); + } + + /** Log an exception. + *

+ * This method logs the exception or prints it if it's not a Monty exception. */ + public void logError(RuntimeException exception) { + if (exception instanceof MontyBaseException) { + MontyBaseException exc = (MontyBaseException) exception; + System.err.println(String.format( + "%s caught error in %s: %s", + getClass().getSimpleName(), + getNodeInformation(exc.getNode()), + exc.getMessage())); + } else { + exception.printStackTrace(); + } + } + + /** Was there an error during the execution of this visitor? + * + * @return true if no error was caught, false otherwise */ + public boolean foundError() { + return errorCounter != 0; + } + + // Declaration + + /** Visitor method to visit a ModuleDeclaration. + * + * @param node + * the node to visit */ + public void visit(ModuleDeclaration node) { + onEnterChildrenEachNode(node); + node.visitChildren(this); + onExitChildrenEachNode(node); + } + + /** Visitor method to visit a ClassDeclaration. + * + * @param node + * the node to visit */ + public void visit(ClassDeclaration node) { + onEnterChildrenEachNode(node); + node.visitChildren(this); + onExitChildrenEachNode(node); + } + + /** Visitor method to visit a FunctionDeclaration. + * + * @param node + * the node to visit */ + public void visit(FunctionDeclaration node) { + onEnterChildrenEachNode(node); + node.visitChildren(this); + onExitChildrenEachNode(node); + } + + /** Visitor method to visit a ProcedureDeclaration. + * + * @param node + * the node to visit */ + public void visit(ProcedureDeclaration node) { + onEnterChildrenEachNode(node); + node.visitChildren(this); + onExitChildrenEachNode(node); + } + + /** Visitor method to visit a VariableDeclaration. + * + * @param node + * the node to visit */ + public void visit(VariableDeclaration node) { + onEnterChildrenEachNode(node); + node.visitChildren(this); + onExitChildrenEachNode(node); + } + + // Expression + + /** Visitor method to visit a ConditionalExpression. + * + * @param node + * the node to visit */ + public void visit(ConditionalExpression node) { + onEnterChildrenEachNode(node); + node.visitChildren(this); + onExitChildrenEachNode(node); + } + + /** Visitor method to visit a SelfExpression. + * + * @param node + * the node to visit */ + public void visit(SelfExpression node) { + onEnterChildrenEachNode(node); + node.visitChildren(this); + onExitChildrenEachNode(node); + } + + /** Visitor method to visit a ParentExpression. + * + * @param node + * the node to visit */ + public void visit(ParentExpression node) { + onEnterChildrenEachNode(node); + node.visitChildren(this); + onExitChildrenEachNode(node); + } + + /** Visitor method to visit a CastExpression. + * + * @param node + * the node to visit */ + public void visit(CastExpression node) { + onEnterChildrenEachNode(node); + node.visitChildren(this); + onExitChildrenEachNode(node); + } + + /** Visitor method to visit a IsExpression. + * + * @param node + * the node to visit */ + public void visit(IsExpression node) { + onEnterChildrenEachNode(node); + node.visitChildren(this); + onExitChildrenEachNode(node); + } + + /** Visitor method to visit a FunctionCall. + * + * @param node + * the node to visit */ + public void visit(FunctionCall node) { + onEnterChildrenEachNode(node); + node.visitChildren(this); + onExitChildrenEachNode(node); + } + + /** Visitor method to visit a MemberAccess. + * + * @param node + * the node to visit */ + public void visit(MemberAccess node) { + onEnterChildrenEachNode(node); + node.visitChildren(this); + onExitChildrenEachNode(node); + } + + /** Visitor method to visit a VariableAccess. + * + * @param node + * the node to visit */ + public void visit(VariableAccess node) { + onEnterChildrenEachNode(node); + node.visitChildren(this); + onExitChildrenEachNode(node); + } + + // Literal + + /** Visitor method to visit a BooleanLiteral. + * + * @param node + * the node to visit */ + public void visit(BooleanLiteral node) { + onEnterChildrenEachNode(node); + node.visitChildren(this); + onExitChildrenEachNode(node); + } + + /** Visitor method to visit a FloatLiteral. + * + * @param node + * the node to visit */ + public void visit(FloatLiteral node) { + onEnterChildrenEachNode(node); + node.visitChildren(this); + onExitChildrenEachNode(node); + } + + /** Visitor method to visit a IntegerLiteral. + * + * @param node + * the node to visit */ + public void visit(IntegerLiteral node) { + onEnterChildrenEachNode(node); + node.visitChildren(this); + onExitChildrenEachNode(node); + } + + /** Visitor method to visit a StringLiteral. + * + * @param node + * the node to visit */ + public void visit(StringLiteral node) { + onEnterChildrenEachNode(node); + node.visitChildren(this); + onExitChildrenEachNode(node); + } + + /** Visitor method to visit a ArrayLiteral. + * + * @param node + * the node to visit */ + public void visit(ArrayLiteral node) { + onEnterChildrenEachNode(node); + node.visitChildren(this); + onExitChildrenEachNode(node); + } + + /** Visitor method to visit a CharacterLiteral. + * + * @param node + * the node to visit */ + public void visit(CharacterLiteral node) { + onEnterChildrenEachNode(node); + node.visitChildren(this); + onExitChildrenEachNode(node); + } + + // Statements + + /** Visitor method to visit a Assignment. + * + * @param node + * the node to visit */ + public void visit(Assignment node) { + onEnterChildrenEachNode(node); + node.visitChildren(this); + onExitChildrenEachNode(node); + } + + /** Visitor method to visit a BreakStatement. + * + * @param node + * the node to visit */ + public void visit(BreakStatement node) { + onEnterChildrenEachNode(node); + node.visitChildren(this); + onExitChildrenEachNode(node); + } + + /** Visitor method to visit a SkipStatement. + * + * @param node + * the node to visit */ + public void visit(SkipStatement node) { + onEnterChildrenEachNode(node); + node.visitChildren(this); + onExitChildrenEachNode(node); + } + + /** Visitor method to visit a ConditionalStatement. + * + * @param node + * the node to visit */ + public void visit(ConditionalStatement node) { + onEnterChildrenEachNode(node); + node.visitChildren(this); + onExitChildrenEachNode(node); + } + + /** Visitor method to visit a ContinueStatement. + * + * @param node + * the node to visit */ + public void visit(ContinueStatement node) { + onEnterChildrenEachNode(node); + node.visitChildren(this); + onExitChildrenEachNode(node); + } + + /** Visitor method to visit a ReturnStatement. + * + * @param node + * the node to visit */ + public void visit(ReturnStatement node) { + onEnterChildrenEachNode(node); + node.visitChildren(this); + onExitChildrenEachNode(node); + } + + /** Visitor method to visit a WhileLoop. + * + * @param node + * the node to visit */ + public void visit(WhileLoop node) { + onEnterChildrenEachNode(node); + node.visitChildren(this); + onExitChildrenEachNode(node); + } + + /** Visitor method to visit a TryStatement. + * + * @param node + * the node to visit */ + public void visit(TryStatement node) { + onEnterChildrenEachNode(node); + node.visitChildren(this); + onExitChildrenEachNode(node); + } + + // Other + + /** Visitor method to visit a Block. + * + * @param node + * the node to visit */ + public void visit(Block node) { + onEnterChildrenEachNode(node); + node.visitChildren(this); + onExitChildrenEachNode(node); + } + + /** Visitor method to visit a Package. + * + * @param node + * the node to visit */ + public void visit(Package node) { + onEnterChildrenEachNode(node); + node.visitChildren(this); + onExitChildrenEachNode(node); + } + + /** Visitor method to visit a Import. + * + * @param node + * the node to visit */ + public void visit(Import node) { + onEnterChildrenEachNode(node); + node.visitChildren(this); + onExitChildrenEachNode(node); + } + + protected void onEnterEachNode(ASTNode node) { + + } + + protected void onExitEachNode(ASTNode node) { + + } + + protected void onEnterChildrenEachNode(ASTNode node) { + + } + + protected void onExitChildrenEachNode(ASTNode node) { + + } + + public void setStopOnFirstError(boolean stopOnFirstError) { + this.stopOnFirstError = stopOnFirstError; + } +} diff --git a/src/main/java/de/uni/bremen/monty/moco/visitor/CodeGenerationVisitor.java b/src/main/java/de/uni/bremen/monty/moco/visitor/CodeGenerationVisitor.java new file mode 100644 index 0000000..a957fc8 --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/visitor/CodeGenerationVisitor.java @@ -0,0 +1,643 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.visitor; + +import de.uni.bremen.monty.moco.ast.ASTNode; +import de.uni.bremen.monty.moco.ast.Block; +import de.uni.bremen.monty.moco.ast.CoreClasses; +import de.uni.bremen.monty.moco.ast.Package; +import de.uni.bremen.monty.moco.ast.declaration.*; +import de.uni.bremen.monty.moco.ast.expression.*; +import de.uni.bremen.monty.moco.ast.expression.literal.*; +import de.uni.bremen.monty.moco.ast.statement.*; +import de.uni.bremen.monty.moco.codegeneration.CodeGenerator; +import de.uni.bremen.monty.moco.codegeneration.CodeWriter; +import de.uni.bremen.monty.moco.codegeneration.context.CodeContext; +import de.uni.bremen.monty.moco.codegeneration.context.ContextUtils; +import de.uni.bremen.monty.moco.codegeneration.identifier.LLVMIdentifier; +import de.uni.bremen.monty.moco.codegeneration.identifier.LLVMIdentifierFactory; +import de.uni.bremen.monty.moco.codegeneration.types.LLVMStructType; +import de.uni.bremen.monty.moco.codegeneration.types.LLVMType; +import de.uni.bremen.monty.moco.codegeneration.types.LLVMPointer; +import de.uni.bremen.monty.moco.codegeneration.types.LLVMTypeFactory; +import de.uni.bremen.monty.moco.codegeneration.types.TypeConverter; +import de.uni.bremen.monty.moco.util.Params; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Stack; + +import static de.uni.bremen.monty.moco.codegeneration.types.LLVMTypeFactory.pointer; + +/** The CodeGenerationVisitor has the following tasks: + * + *

+ *

    + *
  • Process the AST
  • + *
  • Delegates as much work as possible to the CodeGenerator
  • + *
  • Tell the CodeGenerator in which {@link CodeContext} to write
  • + *
  • Evaluated expression should be given Statements as Arguments, see {@link #stack}
  • + *
+ *

*/ +public class CodeGenerationVisitor extends BaseVisitor { + + private final LLVMIdentifierFactory llvmIdentifierFactory = new LLVMIdentifierFactory(); + private ContextUtils contextUtils = new ContextUtils(); + private final CodeGenerator codeGenerator; + private final CodeWriter codeWriter; + + /** Each Expression pushes it's evaluated value onto the Stack. The value is represented by a LLVMIdentifier where + * the evaluated value is stored at runtime. + * + * Statements or complex Expressions can pop those values from the stack, which they use as parameters for further + * calculation. + * + * e.g. a := 3 is an Assignment having a VariableAccess and IntLiteral as children. VariableAccess and IntLiteral + * are expressions, thus pushing their values on the stack. An Assignment on the other hand is an Statement and + * return nothing, so doesn't push sth. on the stack, but instead it needs two Arguments. Those are popped from the + * Stack and yield the the evaluated VariableAccess and IntLiteral. + * + * Of course this only works, if the Assignment first process the children and afterwards popping from the stack. */ + private Stack> stack = new Stack<>(); + + /** Only Expressions push to a Stack. So this is a Stack of Stacks so every Statement has its own stack. + * + * e.g. the FunctionCall as a statement would leave behind a non-empty stack. */ + private Stack>> stackOfStacks = new Stack<>(); + + public CodeGenerationVisitor(Params params) throws IOException { + TypeConverter typeConverter = new TypeConverter(llvmIdentifierFactory, contextUtils.constant()); + this.codeWriter = new CodeWriter(params); + this.codeGenerator = new CodeGenerator(typeConverter, llvmIdentifierFactory); + } + + private void openNewFunctionScope() { + contextUtils.addNewContext(); + llvmIdentifierFactory.openScope(); + } + + private void closeFunctionContext() { + contextUtils.active().close(); + contextUtils.closeContext(); + llvmIdentifierFactory.closeScope(); + } + + private List> buildLLVMParameter(ProcedureDeclaration node) { + List> llvmParameter = new ArrayList<>(); + + if (node.isMethod() || node.isInitializer()) { + LLVMType selfType = codeGenerator.mapToLLVMType(node.getDefiningClass()); + LLVMIdentifier selfReference = llvmIdentifierFactory.newLocal("self", selfType, false); + llvmParameter.add(selfReference); + } + + for (VariableDeclaration param : node.getParameter()) { + LLVMType llvmType = codeGenerator.mapToLLVMType(param.getType()); + llvmType = llvmType instanceof LLVMStructType ? pointer(llvmType) : llvmType; + boolean resolvable = llvmType instanceof LLVMStructType; + LLVMIdentifier e = + llvmIdentifierFactory.newLocal(param.getMangledIdentifier().getSymbol(), llvmType, resolvable); + + llvmParameter.add(e); + } + return llvmParameter; + } + + private void addFunction(ProcedureDeclaration node, TypeDeclaration returnType) { + List> llvmParameter = buildLLVMParameter(node); + String name = node.getMangledIdentifier().getSymbol(); + codeGenerator.addFunction(contextUtils.active(), returnType, llvmParameter, name); + } + + private void addNativeFunction(ProcedureDeclaration node, TypeDeclaration returnType) { + List> llvmParameter = buildLLVMParameter(node); + String name = node.getMangledIdentifier().getSymbol(); + codeGenerator.addNativeFunction(contextUtils.active(), returnType, llvmParameter, name); + } + + private boolean isNative(ASTNode node) { + while (node.getParentNode() != null) { + node = node.getParentNode(); + if (node instanceof Package) { + if (((Package) node).isNativePackage()) { + return true; + } + } + } + return false; + } + + protected void writeData() throws IOException { + codeWriter.write(contextUtils.getData()); + } + + @Override + protected void onEnterEachNode(ASTNode node) { + contextUtils.setNode(node); + } + + @Override + protected void onExitChildrenEachNode(ASTNode node) { + contextUtils.setNode(node); + } + + @Override + public void visit(Package node) { + contextUtils.setNode(node); + if (node.getParentNode() == null) { + openNewFunctionScope(); + codeGenerator.addMain(contextUtils.active()); + + super.visit(node); + + codeGenerator.returnMain(contextUtils.active()); + closeFunctionContext(); + + try { + writeData(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } else { + super.visit(node); + } + } + + @Override + public void visit(Block node) { + for (Declaration declaration : node.getDeclarations()) { + visitDoubleDispatched(declaration); + } + for (Statement statement : node.getStatements()) { + stackOfStacks.push(stack); + stack = new Stack<>(); + visitDoubleDispatched(statement); + stack = stackOfStacks.pop(); + } + } + + @Override + public void visit(Assignment node) { + super.visit(node); + LLVMIdentifier source = stack.pop(); + LLVMIdentifier target = stack.pop(); + codeGenerator.assign(contextUtils.active(), target, source); + } + + @Override + public void visit(ClassDeclaration node) { + // These are not boxed yet. So they cant inherit from object and cant have initializers. + List treatSpecial = + Arrays.asList(CoreClasses.stringType(), CoreClasses.arrayType(), CoreClasses.voidType()); + if (!treatSpecial.contains(node)) { + openNewFunctionScope(); + codeGenerator.buildConstructor(contextUtils.active(), node); + closeFunctionContext(); + } + super.visit(node); + } + + @Override + public void visit(VariableDeclaration node) { + super.visit(node); + if (!node.isAttribute()) { + if (node.getIsGlobal()) { + codeGenerator.declareGlobalVariable( + contextUtils.constant(), + node.getMangledIdentifier().getSymbol(), + node.getType()); + } else { + codeGenerator.declareLocalVariable( + contextUtils.active(), + node.getMangledIdentifier().getSymbol(), + node.getType()); + } + } + } + + @Override + public void visit(VariableAccess node) { + super.visit(node); + + VariableDeclaration varDeclaration = (VariableDeclaration) node.getDeclaration(); + + LLVMIdentifier llvmIdentifier; + if (varDeclaration.getIsGlobal()) { + llvmIdentifier = + codeGenerator.resolveGlobalVarName(node.getMangledIdentifier().getSymbol(), node.getType()); + } else if (varDeclaration.isAttribute()) { + LLVMIdentifier leftIdentifier = stack.pop(); + llvmIdentifier = + codeGenerator.accessMember( + contextUtils.active(), + (LLVMIdentifier>) leftIdentifier, + varDeclaration.getAttributeIndex(), + node.getType(), + !node.getLValue()); + } else { + llvmIdentifier = + codeGenerator.resolveLocalVarName( + node.getMangledIdentifier().getSymbol(), + node.getType(), + !varDeclaration.isParameter()); + } + stack.push(llvmIdentifier); + } + + @SuppressWarnings("unchecked") + @Override + public void visit(SelfExpression node) { + stack.push(codeGenerator.resolveLocalVarName("self", node.getType(), false)); + } + + @SuppressWarnings("unchecked") + @Override + public void visit(ParentExpression node) { + LLVMIdentifier self = codeGenerator.resolveLocalVarName("self", node.getSelfType(), false); + LLVMIdentifier result = + codeGenerator.castClass( + contextUtils.active(), + (LLVMIdentifier>) self, + node.getSelfType(), + (ClassDeclaration) node.getType(), + codeGenerator.createLabelPrefix("cast", node)); + stack.push((LLVMIdentifier) result); + } + + /** {@inheritDoc} */ + @Override + public void visit(CastExpression node) { + super.visit(node); + LLVMIdentifier object = stack.pop(); + LLVMIdentifier result = + codeGenerator.castClass( + contextUtils.active(), + (LLVMIdentifier>) object, + (ClassDeclaration) node.getExpression().getType(), + (ClassDeclaration) node.getType(), + codeGenerator.createLabelPrefix("cast", node)); + stack.push((LLVMIdentifier) result); + } + + /** {@inheritDoc} */ + @Override + public void visit(IsExpression node) { + super.visit(node); + LLVMIdentifier object = stack.pop(); + LLVMIdentifier result = + codeGenerator.isClass( + contextUtils.active(), + (LLVMIdentifier>) object, + (ClassDeclaration) node.getExpression().getType(), + (ClassDeclaration) node.getToType()); + LLVMIdentifier boxedResult = + codeGenerator.boxType(contextUtils.active(), (LLVMIdentifier) result, CoreClasses.boolType()); + stack.push(boxedResult); + } + + @Override + public void visit(MemberAccess node) { + super.visit(node); + // If right is VariableAccess, everything is done in visit(VariableAccess) + // If right is FunctionCall, everything is done in visit(FunctionCall) + } + + @SuppressWarnings("unchecked") + @Override + public void visit(StringLiteral node) { + super.visit(node); + + LLVMIdentifier addr = + codeGenerator.addConstantString(contextUtils.constant(), node.getValue()); + stack.push((LLVMIdentifier) addr); + } + + @SuppressWarnings("unchecked") + @Override + public void visit(CharacterLiteral node) { + super.visit(node); + LLVMIdentifier addr = codeGenerator.loadChar(node.getValue()); + // Boxing + CodeContext c = contextUtils.active(); + LLVMIdentifier box = codeGenerator.boxType(c, (LLVMIdentifier) addr, node.getType()); + stack.push(box); + } + + @SuppressWarnings("unchecked") + @Override + public void visit(IntegerLiteral node) { + super.visit(node); + + LLVMIdentifier addr = codeGenerator.loadInt(node.getValue()); + // Boxing + CodeContext c = contextUtils.active(); + LLVMIdentifier box = codeGenerator.boxType(c, (LLVMIdentifier) addr, node.getType()); + stack.push(box); + } + + @SuppressWarnings("unchecked") + @Override + public void visit(BooleanLiteral node) { + super.visit(node); + + LLVMIdentifier addr = codeGenerator.loadBool(node.getValue()); + // Boxing + CodeContext c = contextUtils.active(); + LLVMIdentifier box = codeGenerator.boxType(c, (LLVMIdentifier) addr, node.getType()); + stack.push(box); + } + + @SuppressWarnings("unchecked") + @Override + public void visit(FloatLiteral node) { + super.visit(node); + + LLVMIdentifier addr = codeGenerator.loadFloat(node.getValue()); + // Boxing + CodeContext c = contextUtils.active(); + LLVMIdentifier box = codeGenerator.boxType(c, (LLVMIdentifier) addr, node.getType()); + stack.push(box); + } + + @Override + public void visit(ArrayLiteral node) { + super.visit(node); + + ClassDeclaration type = (ClassDeclaration) node.getType(); + LLVMIdentifier> array = + codeGenerator.addArray(contextUtils.active(), node.getEntries().size(), type); + for (int i = node.getEntries().size() - 1; i >= 0; i--) { + codeGenerator.setArrayElement(contextUtils.active(), array, i, stack.pop()); + } + + stack.push((LLVMIdentifier) array); + } + + @Override + public void visit(ConditionalExpression node) { + + String ifPre = codeGenerator.createLabelPrefix("ifexpr", node); + String ifTrue = ifPre + ".true"; + String ifFalse = ifPre + ".false"; + String ifEnd = ifPre + ".end"; + + visitDoubleDispatched(node.getCondition()); + + LLVMIdentifier condition = stack.pop(); + codeGenerator.branch(contextUtils.active(), condition, ifTrue, ifFalse); + + contextUtils.active().label(ifTrue); + visitDoubleDispatched(node.getThenExpression()); + LLVMIdentifier thenExpr = stack.pop(); + contextUtils.active().branch(ifEnd); + + contextUtils.active().label(ifFalse); + visitDoubleDispatched(node.getElseExpression()); + LLVMIdentifier elseExpr = stack.pop(); + contextUtils.active().branch(ifEnd); + + contextUtils.active().label(ifEnd); + List> identifiers = new ArrayList<>(); + identifiers.add(thenExpr); + identifiers.add(elseExpr); + List labels = new ArrayList<>(); + labels.add(ifTrue); + labels.add(ifFalse); + stack.push(contextUtils.active().phi( + thenExpr.getType(), + thenExpr.needToBeResolved(), + identifiers, + llvmIdentifierFactory.newLocal(thenExpr.getType(), thenExpr.needToBeResolved()), + labels)); + } + + @SuppressWarnings("unchecked") + @Override + public void visit(FunctionCall node) { + super.visit(node); + + List expectedParameters = new ArrayList<>(); + for (VariableDeclaration varDeclaration : node.getDeclaration().getParameter()) { + expectedParameters.add(varDeclaration.getType()); + } + List> arguments = new ArrayList<>(node.getArguments().size()); + for (int i = 0; i < node.getArguments().size(); i++) { + arguments.add(stack.pop()); + } + Collections.reverse(arguments); + + ProcedureDeclaration declaration = node.getDeclaration(); + ClassDeclaration definingClass = declaration.getDefiningClass(); + + List treatSpecial = + Arrays.asList( + CoreClasses.intType(), + CoreClasses.boolType(), + CoreClasses.floatType(), + CoreClasses.charType()); + if (declaration.isInitializer() && treatSpecial.contains(definingClass)) { + // Instead of calling the initializer of this boxed type with a boxed value as arguments just push the + // argument on the stack and return. + stack.push((LLVMIdentifier) arguments.get(0)); + return; + } + + if (declaration.isMethod() || declaration.isInitializer()) { + expectedParameters.add(0, definingClass); + if (declaration.isMethod() + || (declaration.isInitializer() && (node.getParentNode() instanceof MemberAccess))) { + arguments.add(0, stack.pop()); + } else if (declaration.isInitializer()) { + LLVMIdentifier selfReference = + codeGenerator.callConstructor(contextUtils.active(), definingClass); + codeGenerator.callVoid( + contextUtils.active(), + definingClass.getDefaultInitializer().getMangledIdentifier().getSymbol(), + Arrays.> asList(selfReference), + Arrays. asList(definingClass)); + arguments.add(0, selfReference); + } + } + + if (declaration.isMethod() && !declaration.isInitializer()) { + if (declaration instanceof FunctionDeclaration) { + stack.push((LLVMIdentifier) codeGenerator.callMethod( + contextUtils.active(), + (FunctionDeclaration) declaration, + arguments, + expectedParameters)); + } else { + codeGenerator.callVoidMethod(contextUtils.active(), declaration, arguments, expectedParameters); + } + } else { + if (declaration instanceof FunctionDeclaration) { + stack.push((LLVMIdentifier) codeGenerator.call( + contextUtils.active(), + declaration.getMangledIdentifier().getSymbol(), + node.getType(), + arguments, + expectedParameters)); + } else { + if (declaration.isInitializer()) { + stack.push((LLVMIdentifier) arguments.get(0)); + } + codeGenerator.callVoid( + contextUtils.active(), + declaration.getMangledIdentifier().getSymbol(), + arguments, + expectedParameters); + } + } + } + + @Override + public void visit(FunctionDeclaration node) { + openNewFunctionScope(); + if (isNative(node)) { + addNativeFunction(node, node.getReturnType()); + } else { + addFunction(node, node.getReturnType()); + visitDoubleDispatched(node.getBody()); + } + closeFunctionContext(); + } + + @Override + public void visit(ProcedureDeclaration node) { + openNewFunctionScope(); + + if (isNative(node) && !node.isInitializer()) { + addNativeFunction(node, CoreClasses.voidType()); + } else { + addFunction(node, CoreClasses.voidType()); + + visitDoubleDispatched(node.getBody()); + if (node.isInitializer()) { + codeGenerator.returnValue( + contextUtils.active(), + (LLVMIdentifier) (LLVMIdentifier) llvmIdentifierFactory.voidId(), + CoreClasses.voidType()); + } + } + closeFunctionContext(); + } + + @Override + public void visit(ReturnStatement node) { + super.visit(node); + if (node.getParameter() != null) { + ASTNode parent = node; + while (!(parent instanceof FunctionDeclaration)) { + parent = parent.getParentNode(); + } + LLVMIdentifier returnValue = stack.pop(); + codeGenerator.returnValue( + contextUtils.active(), + returnValue, + ((FunctionDeclaration) parent).getReturnType()); + } else { + codeGenerator.returnValue( + contextUtils.active(), + (LLVMIdentifier) (LLVMIdentifier) llvmIdentifierFactory.voidId(), + CoreClasses.voidType()); + } + } + + @Override + public void visit(ConditionalStatement node) { + visitDoubleDispatched(node.getCondition()); + + String ifPre = codeGenerator.createLabelPrefix("if", node); + + String ifTrue = ifPre + ".true"; + String ifFalse = ifPre + ".false"; + String ifEnd = ifPre + ".end"; + + LLVMIdentifier condition = stack.pop(); + codeGenerator.branch(contextUtils.active(), condition, ifTrue, ifFalse); + + contextUtils.active().label(ifTrue); + visitDoubleDispatched(node.getThenBlock()); + contextUtils.active().branch(ifEnd); + + contextUtils.active().label(ifFalse); + visitDoubleDispatched(node.getElseBlock()); + contextUtils.active().branch(ifEnd); + + contextUtils.active().label(ifEnd); + } + + @Override + public void visit(WhileLoop node) { + + String whlPre = codeGenerator.createLabelPrefix("while", node); + String whileCond = whlPre + ".condition"; + String whileBlk = whlPre + ".block"; + String whileEnd = whlPre + ".end"; + + contextUtils.active().branch(whileCond); + contextUtils.active().label(whileCond); + visitDoubleDispatched(node.getCondition()); + + LLVMIdentifier condition = stack.pop(); + codeGenerator.branch(contextUtils.active(), condition, whileBlk, whileEnd); + + contextUtils.active().label(whileBlk); + visitDoubleDispatched(node.getBody()); + contextUtils.active().branch(whileCond); + contextUtils.active().label(whileEnd); + } + + @Override + public void visit(SkipStatement node) { + super.visit(node); + String whlPre = codeGenerator.getLabelPrefix(node.getLoop()); + contextUtils.active().branch(whlPre + ".condition"); + } + + @Override + public void visit(BreakStatement node) { + super.visit(node); + String whlPre = codeGenerator.getLabelPrefix(node.getLoop()); + contextUtils.active().branch(whlPre + ".end"); + } +} diff --git a/src/main/java/de/uni/bremen/monty/moco/visitor/ControlFlowVisitor.java b/src/main/java/de/uni/bremen/monty/moco/visitor/ControlFlowVisitor.java new file mode 100644 index 0000000..8b3d3d4 --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/visitor/ControlFlowVisitor.java @@ -0,0 +1,168 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.visitor; + +import de.uni.bremen.monty.moco.ast.ASTNode; +import de.uni.bremen.monty.moco.ast.Block; +import de.uni.bremen.monty.moco.ast.Package; +import de.uni.bremen.monty.moco.ast.declaration.Declaration; +import de.uni.bremen.monty.moco.ast.declaration.FunctionDeclaration; +import de.uni.bremen.monty.moco.ast.declaration.ProcedureDeclaration; +import de.uni.bremen.monty.moco.ast.statement.BreakStatement; +import de.uni.bremen.monty.moco.ast.statement.ConditionalStatement; +import de.uni.bremen.monty.moco.ast.statement.ContinueStatement; +import de.uni.bremen.monty.moco.ast.statement.ReturnStatement; +import de.uni.bremen.monty.moco.ast.statement.SkipStatement; +import de.uni.bremen.monty.moco.ast.statement.Statement; +import de.uni.bremen.monty.moco.ast.statement.WhileLoop; +import de.uni.bremen.monty.moco.exception.InvalidControlFlowException; + +/** This visitor must traverse the entire AST to validate the intended AST-structure. */ +public class ControlFlowVisitor extends BaseVisitor { + + /** Set to `true` if the current statement-list needs to contain a ReturnStatement */ + private boolean needsReturnStatement; + + @Override + public void visit(Package node) { + if (!node.isNativePackage()) { + super.visit(node); + } + } + + /** {@inheritDoc} */ + @Override + public void visit(FunctionDeclaration node) { + needsReturnStatement = true; + super.visit(node); + if (needsReturnStatement) { + throw new InvalidControlFlowException(node, "ReturnStatement needed."); + } + } + + /** {@inheritDoc} */ + @Override + public void visit(Block node) { + boolean needsReturnStatementCopy = needsReturnStatement; + for (Declaration declaration : node.getDeclarations()) { + visitDoubleDispatched(declaration); + } + needsReturnStatement = needsReturnStatementCopy; + for (Statement statement : node.getStatements()) { + visitDoubleDispatched(statement); + } + } + + /** {@inheritDoc} */ + @Override + public void visit(ConditionalStatement node) { + visitDoubleDispatched(node.getCondition()); + boolean needsReturnStatementCopy = needsReturnStatement; + visitDoubleDispatched(node.getThenBlock()); + boolean needsReturnStatementCopyThen = needsReturnStatement; + visitDoubleDispatched(node.getElseBlock()); + boolean needsReturnStatementCopyElse = needsReturnStatement; + + if (needsReturnStatementCopy && !needsReturnStatementCopyThen && !needsReturnStatementCopyElse) { + needsReturnStatement = false; + } else { + needsReturnStatement = needsReturnStatementCopy; + } + } + + /** {@inheritDoc} */ + @Override + public void visit(WhileLoop node) { + boolean needsReturnStatementCopy = needsReturnStatement; + super.visit(node); + needsReturnStatement = needsReturnStatementCopy; + } + + /** {@inheritDoc} */ + @Override + public void visit(ContinueStatement node) { + super.visit(node); + for (ASTNode currentNode = node; currentNode != null; currentNode = currentNode.getParentNode()) { + if (currentNode instanceof WhileLoop) { + return; + } + } + throw new InvalidControlFlowException(node, "Unable to find enclosing WhileLoop."); + } + + /** {@inheritDoc} */ + @Override + public void visit(BreakStatement node) { + super.visit(node); + for (ASTNode currentNode = node; currentNode != null; currentNode = currentNode.getParentNode()) { + if (currentNode instanceof WhileLoop) { + node.setLoop((WhileLoop) currentNode); + return; + } + } + throw new InvalidControlFlowException(node, "Unable to find enclosing While-Loop for BreakStatement."); + } + + /** {@inheritDoc} */ + @Override + public void visit(SkipStatement node) { + super.visit(node); + for (ASTNode currentNode = node; currentNode != null; currentNode = currentNode.getParentNode()) { + if (currentNode instanceof WhileLoop) { + node.setLoop((WhileLoop) currentNode); + return; + } + } + throw new InvalidControlFlowException(node, "Unable to find enclosing While-Loop for SkipStatement."); + } + + /** {@inheritDoc} */ + @Override + public void visit(ReturnStatement node) { + super.visit(node); + needsReturnStatement = false; + for (ASTNode currentNode = node; currentNode != null; currentNode = currentNode.getParentNode()) { + if (currentNode instanceof ProcedureDeclaration) { + return; + } + } + + throw new InvalidControlFlowException(node, "Unable to find enclosing Function-/ProcedureDeclaration."); + } +} diff --git a/src/main/java/de/uni/bremen/monty/moco/visitor/DeclarationVisitor.java b/src/main/java/de/uni/bremen/monty/moco/visitor/DeclarationVisitor.java new file mode 100644 index 0000000..05f3bb2 --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/visitor/DeclarationVisitor.java @@ -0,0 +1,204 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.visitor; + +import de.uni.bremen.monty.moco.ast.*; +import de.uni.bremen.monty.moco.ast.statement.*; +import de.uni.bremen.monty.moco.ast.expression.*; +import de.uni.bremen.monty.moco.ast.Package; +import de.uni.bremen.monty.moco.ast.declaration.*; +import de.uni.bremen.monty.moco.exception.InvalidPlaceToDeclareException; + +import java.util.List; +import java.util.ArrayList; +import java.util.Arrays; + +/** This visitor must traverse the entire AST, set up scopes and define declarations. + *

+ * For every node that opens a new scope this scope must be created and assigned: + * + *

+ * currentScope = node.setScope(new Scope(currentScope));
+ * 
+ * + * For every other node the associated scope must be set: + * + *
+ * node.setScope(currentScope);
+ * 
+ * + * Every declaration must be defined using the currentScope. */ +public class DeclarationVisitor extends BaseVisitor { + + /** The current scope for the ast node. */ + private Scope currentScope = new Scope(null); + + // Declaration + + /** {@inheritDoc} */ + @Override + public void visit(ModuleDeclaration node) { + if (!(node.getParentNode() instanceof Package)) { + throw new InvalidPlaceToDeclareException(node, "A module must be the child of an package. Here: " + + getNodeInformation(node) + " parent: " + getNodeInformation(node.getParentNode())); + } + super.visit(node); + } + + /** {@inheritDoc} */ + @Override + public void visit(ClassDeclaration node) { + if (!(node.getParentNode().getParentNode() instanceof ModuleDeclaration)) { + throw new InvalidPlaceToDeclareException(node, "A class may only be declared in a module."); + } + Block classBlock = node.getBlock(); + + currentScope.define(node); + currentScope = new ClassScope(currentScope); + + // These are not boxed yet. So they cant inherit from object and cant have initializers. + List treatSpecial = + Arrays.asList(CoreClasses.stringType(), CoreClasses.arrayType(), CoreClasses.voidType()); + + if (!treatSpecial.contains(node)) { + if (node != CoreClasses.objectType() && node.getSuperClassIdentifiers().isEmpty()) { + node.getSuperClassIdentifiers().add(new ResolvableIdentifier("Object")); + } + + ProcedureDeclaration defaultInitializer = buildDefaultInitializer(node); + node.setDefaultInitializer(defaultInitializer); + classBlock.addDeclaration(defaultInitializer); + // The default initializer contains these statements so they should no longer be inside the class-block. + classBlock.getStatements().clear(); + } + + super.visit(node); + + node.setScope(classBlock.getScope()); + currentScope = currentScope.getParentScope(); + } + + /** {@inheritDoc} */ + @Override + public void visit(FunctionDeclaration node) { + currentScope.define(node); + currentScope = new Scope(currentScope); + super.visit(node); + node.setScope(node.getBody().getScope()); + currentScope = currentScope.getParentScope(); + } + + /** {@inheritDoc} */ + @Override + public void visit(ProcedureDeclaration node) { + currentScope.define(node); + currentScope = new Scope(currentScope); + super.visit(node); + node.setScope(node.getBody().getScope()); + currentScope = currentScope.getParentScope(); + } + + /** {@inheritDoc} */ + @Override + public void visit(VariableDeclaration node) { + // the parent is the Block of the ModuleDeclaration + if (node.getParentNode().getParentNode() instanceof ModuleDeclaration) { + node.setIsGlobal(true); + } + currentScope.define(node.getIdentifier(), node); + super.visit(node); + } + + // Other + + /** {@inheritDoc} */ + @Override + public void visit(Block node) { + boolean backToParentScope = false; + + if (node.getParentNode() instanceof ClassDeclaration) { + currentScope = new ClassScope(currentScope); + backToParentScope = true; + } else if (!(node.getParentNode() instanceof ModuleDeclaration)) { + currentScope = new Scope(currentScope); + backToParentScope = true; + } + + super.visit(node); + + if (backToParentScope) { + currentScope = currentScope.getParentScope(); + } + } + + @Override + protected void onEnterChildrenEachNode(ASTNode node) { + node.setScope(currentScope); + } + + private ProcedureDeclaration buildDefaultInitializer(ClassDeclaration node) { + + ProcedureDeclaration initializer = + new ProcedureDeclaration(node.getPosition(), new Identifier(node.getIdentifier().getSymbol() + + "_definit"), new Block(node.getPosition()), new ArrayList(), + ProcedureDeclaration.DeclarationType.INITIALIZER); + initializer.setParentNode(node.getBlock()); + Block initializerBlock = initializer.getBody(); + initializerBlock.setParentNode(initializer); + + for (ResolvableIdentifier superclass : node.getSuperClassIdentifiers()) { + SelfExpression self = new SelfExpression(node.getPosition()); + FunctionCall call = + new FunctionCall(node.getPosition(), new ResolvableIdentifier(superclass.getSymbol() + "_definit"), + new ArrayList()); + MemberAccess defaultInitializerCall = new MemberAccess(node.getPosition(), self, call); + + self.setParentNode(defaultInitializerCall); + call.setParentNode(defaultInitializerCall); + defaultInitializerCall.setParentNode(initializerBlock); + initializerBlock.addStatement(defaultInitializerCall); + } + + for (Statement stm : node.getBlock().getStatements()) { + initializerBlock.addStatement(stm); + } + + return initializer; + } +} diff --git a/src/main/java/de/uni/bremen/monty/moco/visitor/NameManglingVisitor.java b/src/main/java/de/uni/bremen/monty/moco/visitor/NameManglingVisitor.java new file mode 100644 index 0000000..1afb6ec --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/visitor/NameManglingVisitor.java @@ -0,0 +1,308 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ + +package de.uni.bremen.monty.moco.visitor; + +import java.util.ArrayList; +import java.util.EnumMap; +import java.util.Stack; +import java.util.concurrent.atomic.AtomicInteger; + +import de.uni.bremen.monty.moco.ast.ASTNode; +import de.uni.bremen.monty.moco.ast.CoreClasses; +import de.uni.bremen.monty.moco.ast.Identifier; +import de.uni.bremen.monty.moco.ast.declaration.ClassDeclaration; +import de.uni.bremen.monty.moco.ast.declaration.FunctionDeclaration; +import de.uni.bremen.monty.moco.ast.declaration.ModuleDeclaration; +import de.uni.bremen.monty.moco.ast.declaration.ProcedureDeclaration; +import de.uni.bremen.monty.moco.ast.declaration.TypeDeclaration; +import de.uni.bremen.monty.moco.ast.declaration.VariableDeclaration; +import de.uni.bremen.monty.moco.ast.expression.VariableAccess; +import de.uni.bremen.monty.moco.ast.statement.ConditionalStatement; +import de.uni.bremen.monty.moco.ast.statement.WhileLoop; + +enum Mangled { + MODULE, CLASS, FUNC, PROC, BLOCK, VAR, TYPE, IF, ELSE, WHILE +} + +/** The NameManglingVisitor uses the following pattern to mangle the names: + * + * _ : '.'; + * + * $ : '$'; + * + * + * module : 'module'_name; + * + * class : 'class'_name; + * + * func : 'func'_name$type($type)*; + * + * proc : 'proc'_name($type)*; + * + * var : 'var'_name$type; + * + * type : 'type'_module(_class)?((_block|_proc|_func)*(_proc|_func))?; + * + * block : 'block'_(IF|TRY|WHILE|HANDLE|ELSE)_number; + * + * mangled : packet_module(_class)?((_block|_proc|_func)*(_proc|_func|_var))?; * */ +public class NameManglingVisitor extends BaseVisitor { + + /** Various stacks for interlaced and nested prefixes. */ + private Stack numbers; + private Stack moduleNames; + private Stack classNames; + private Stack> parentScopes; + + /** Used for mapping prefixes in the pattern. */ + private EnumMap nameManglingPrefixes; + + /** Constructor. */ + public NameManglingVisitor() { + numbers = new Stack<>(); + moduleNames = new Stack<>(); + classNames = new Stack<>(); + parentScopes = new Stack<>(); + + initNameManglingPrefixes(); + manglePredefinedTypes(); + } + + /** Initialize the mapping of prefixes. */ + private void initNameManglingPrefixes() { + nameManglingPrefixes = new EnumMap<>(Mangled.class); + + nameManglingPrefixes.put(Mangled.MODULE, "M."); + nameManglingPrefixes.put(Mangled.CLASS, ".C."); + nameManglingPrefixes.put(Mangled.FUNC, ".F."); + nameManglingPrefixes.put(Mangled.PROC, ".P."); + nameManglingPrefixes.put(Mangled.BLOCK, ".B."); + nameManglingPrefixes.put(Mangled.VAR, ".V."); + nameManglingPrefixes.put(Mangled.TYPE, "$"); + nameManglingPrefixes.put(Mangled.IF, "IF."); + nameManglingPrefixes.put(Mangled.ELSE, "ELSE."); + nameManglingPrefixes.put(Mangled.WHILE, "WHILE."); + } + + /** This function mangles the base types. Current module for base types is "std". */ + private void manglePredefinedTypes() { + final String prefix = + nameManglingPrefixes.get(Mangled.MODULE) + "std" + nameManglingPrefixes.get(Mangled.CLASS); + + CoreClasses.stringType().setMangledIdentifier(new Identifier(prefix + "String")); + CoreClasses.arrayType().setMangledIdentifier(new Identifier(prefix + "Array")); + } + + @Override + public void visit(ModuleDeclaration node) { + if (node.getMangledIdentifier() == null) { + numbers.push(new AtomicInteger(-1)); + parentScopes.push(new ArrayList()); + + String moduleName = escapeForLLVM(node.getIdentifier()); + moduleName = nameManglingPrefixes.get(Mangled.MODULE) + moduleName; + + moduleNames.push(moduleName); + node.setMangledIdentifier(new Identifier(moduleName)); + super.visit(node); + + numbers.pop(); + moduleNames.pop(); + parentScopes.pop(); + } + } + + @Override + public void visit(ClassDeclaration node) { + if (node.getMangledIdentifier() == null) { + final String className = nameManglingPrefixes.get(Mangled.CLASS) + escapeForLLVM(node.getIdentifier()); + + classNames.push(className); + node.setMangledIdentifier(new Identifier(moduleNames.peek() + className)); + super.visit(node); + classNames.pop(); + } + } + + @Override + public void visit(FunctionDeclaration node) { + if (node.getMangledIdentifier() == null) { + String funcName = nameManglingPrefixes.get(Mangled.FUNC) + escapeForLLVM(node.getIdentifier()); + funcName += nameManglingPrefixes.get(Mangled.TYPE) + mangleTypeDeclaration(node.getReturnType()); + + mangleProcedureDeclaration(node, funcName); + } + } + + @Override + public void visit(ProcedureDeclaration node) { + if (node.getMangledIdentifier() == null) { + final String procName = nameManglingPrefixes.get(Mangled.PROC) + escapeForLLVM(node.getIdentifier()); + + mangleProcedureDeclaration(node, procName); + } + } + + @Override + public void visit(VariableDeclaration node) { + if (node.getMangledIdentifier() == null) { + String varName = + nameManglingPrefixes.get(Mangled.VAR) + escapeForLLVM(node.getIdentifier()) + + nameManglingPrefixes.get(Mangled.TYPE) + mangleTypeDeclaration(node.getType()); + + final String wholeName = buildNameHelper() + varName; + node.setMangledIdentifier(new Identifier(wholeName)); + } + } + + @Override + public void visit(VariableAccess node) { + if (node.getMangledIdentifier() == null) { + visitDoubleDispatched(node.getDeclaration()); + } + } + + @Override + public void visit(ConditionalStatement node) { + AtomicInteger number = numbers.peek(); + number.incrementAndGet(); + String blockName = nameManglingPrefixes.get(Mangled.BLOCK) + nameManglingPrefixes.get(Mangled.IF) + number; + visitDoubleDispatched(node.getCondition()); + parentScopes.peek().add(blockName); + + visitDoubleDispatched(node.getThenBlock()); + parentScopes.peek().remove(blockName); + number.incrementAndGet(); + blockName = nameManglingPrefixes.get(Mangled.BLOCK) + nameManglingPrefixes.get(Mangled.ELSE) + number; + + visitDoubleDispatched(node.getElseBlock()); + parentScopes.peek().remove(blockName); + } + + @Override + public void visit(WhileLoop node) { + final AtomicInteger number = numbers.peek(); + number.incrementAndGet(); + final String whileName = + nameManglingPrefixes.get(Mangled.BLOCK) + nameManglingPrefixes.get(Mangled.WHILE) + number; + parentScopes.peek().add(whileName); + super.visit(node); + parentScopes.peek().remove(whileName); + } + + /** If a TypeDeclaration is not mangled yet, it has to be in some other ModuleDeclaration. The other + * ModuleDeclaration must be mangled first. + * + * @param node + * TypeDeclaration to mangle + * @return mangled Identifier */ + private String mangleTypeDeclaration(TypeDeclaration node) { + ASTNode tmp = node; + if (node.getMangledIdentifier() == null) { + while (!(tmp instanceof ModuleDeclaration)) { + tmp = tmp.getParentNode(); + } + visitDoubleDispatched(tmp); + visitDoubleDispatched(node); + } + return node.getMangledIdentifier().getSymbol(); + } + + /** This function mangles the parameters of FunctionDeclaration and ProcedureDeclaration. + * + * @param node + * FunctionDeclaration or ProcedureDeclaration to mangle + * @param procName + * some prefix to build the full mangled name */ + private void mangleProcedureDeclaration(ProcedureDeclaration node, String procName) { + for (final VariableDeclaration variableDeclaration : node.getParameter()) { + if (variableDeclaration.getIdentifier().getSymbol().equals("self")) { + variableDeclaration.setMangledIdentifier(new Identifier("self")); + } else { + procName += + nameManglingPrefixes.get(Mangled.TYPE) + mangleTypeDeclaration(variableDeclaration.getType()); + visitDoubleDispatched(variableDeclaration); + } + } + + parentScopes.peek().add(procName); + final String wholeName = buildNameHelper(); + + node.setMangledIdentifier(new Identifier(wholeName)); + visitDoubleDispatched(node.getBody()); + parentScopes.peek().remove(procName); + } + + /** Builds the name with module, class and parentScopes. + * + * @return prefix of mangled name */ + private String buildNameHelper() { + final StringBuilder wholeName = new StringBuilder(); + wholeName.append(moduleNames.peek()); + + if (!classNames.isEmpty()) { + wholeName.append(classNames.peek()); + } + + for (final String prevScope : parentScopes.peek()) { + wholeName.append(prevScope); + } + + return wholeName.toString(); + } + + private String escapeForLLVM(Identifier identifier) { + String string = identifier.getSymbol(); + string = string.replaceAll("\\[\\]", "_array_access"); + string = string.replaceAll("%", "_rem"); + string = string.replaceAll("\\*", "_mult"); + string = string.replaceAll("/", "_div"); + string = string.replaceAll("\\+", "_plus"); + string = string.replaceAll("-", "_minus"); + string = string.replaceAll("<=", "_lesser_equal"); + string = string.replaceAll(">=", "_greater_equal"); + string = string.replaceAll("!=", "_not_equal"); + string = string.replaceAll("=", "_equal"); + string = string.replaceAll("<", "_lesser"); + string = string.replaceAll(">", "_greater"); + string = string.replaceAll("%", "_rem"); + return string; + } +} diff --git a/src/main/java/de/uni/bremen/monty/moco/visitor/PrintVisitor.java b/src/main/java/de/uni/bremen/monty/moco/visitor/PrintVisitor.java new file mode 100644 index 0000000..3f82644 --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/visitor/PrintVisitor.java @@ -0,0 +1,136 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.visitor; + +import de.uni.bremen.monty.moco.ast.ASTNode; +import de.uni.bremen.monty.moco.ast.declaration.VariableDeclaration; +import de.uni.bremen.monty.moco.ast.expression.VariableAccess; +import de.uni.bremen.monty.moco.ast.expression.literal.BooleanLiteral; +import de.uni.bremen.monty.moco.ast.expression.literal.FloatLiteral; +import de.uni.bremen.monty.moco.ast.expression.literal.IntegerLiteral; +import de.uni.bremen.monty.moco.ast.expression.literal.StringLiteral; +import de.uni.bremen.monty.moco.ast.statement.Assignment; + +/** This visitor traverses the AST and prints useful information to stdout. */ +public class PrintVisitor extends BaseVisitor { + + /** Current level of indentation for printing. */ + private int indentation; + + /** Print the indented. + * + * @param string + * the string to print */ + private void printIndent(String string) { + String indent = new String(new char[indentation]).replace('\0', ' '); + System.err.println(indent + string); + } + + /** {@inheritDoc} */ + @Override + public void visit(VariableDeclaration node) { + printIndent("Symbol: " + node.getIdentifier()); + printIndent("TypeSymbol: " + node.getTypeIdentifier()); + } + + /** {@inheritDoc} */ + @Override + public void visit(VariableAccess node) { + if (node.getType() == null) { + printIndent("Type: null"); + } else { + printIndent("Type: " + node.getType().toString()); + } + printIndent("identifier: " + node.getIdentifier()); + printIndent("L-value: " + node.getLValue()); + } + + // Literal + + /** {@inheritDoc} */ + @Override + public void visit(BooleanLiteral node) { + printIndent("Value: " + node.getValue()); + } + + /** {@inheritDoc} */ + @Override + public void visit(FloatLiteral node) { + printIndent("Value: " + node.getValue()); + } + + /** {@inheritDoc} */ + @Override + public void visit(IntegerLiteral node) { + printIndent("Value: " + node.getValue()); + } + + /** {@inheritDoc} */ + @Override + public void visit(StringLiteral node) { + printIndent("Value: " + node.getValue()); + } + + // Statement + + /** {@inheritDoc} */ + @Override + public void visit(Assignment node) { + printIndent("Left:"); + indentation++; + visitDoubleDispatched(node.getLeft()); + indentation--; + printIndent("Right:"); + indentation++; + visitDoubleDispatched(node.getRight()); + indentation--; + } + + @Override + protected void onEnterEachNode(ASTNode node) { + printIndent(node.getClass().getSimpleName() + "(" + node.getPosition() + "):"); + printIndent("Scope: " + node.getScope()); + indentation++; + } + + @Override + protected void onExitEachNode(ASTNode node) { + indentation--; + } +} diff --git a/src/main/java/de/uni/bremen/monty/moco/visitor/ResolveVisitor.java b/src/main/java/de/uni/bremen/monty/moco/visitor/ResolveVisitor.java new file mode 100644 index 0000000..7f5703c --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/visitor/ResolveVisitor.java @@ -0,0 +1,356 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.visitor; + +import de.uni.bremen.monty.moco.ast.*; +import de.uni.bremen.monty.moco.ast.declaration.*; +import de.uni.bremen.monty.moco.ast.expression.*; +import de.uni.bremen.monty.moco.ast.expression.literal.*; +import de.uni.bremen.monty.moco.exception.UnknownIdentifierException; +import de.uni.bremen.monty.moco.exception.UnknownTypeException; + +import java.util.List; +import java.util.Arrays; +import java.util.ArrayList; + +/** This visitor must traverse the entire AST and resolve variables and types. */ +public class ResolveVisitor extends VisitOnceVisitor { + + /** Constructor. */ + public ResolveVisitor() { + super(); + } + + /** {@inheritDoc} */ + @Override + public void visit(ClassDeclaration node) { + ClassScope scope = (ClassScope) node.getScope(); + List superClasses = node.getSuperClassDeclarations(); + for (ResolvableIdentifier identifier : node.getSuperClassIdentifiers()) { + TypeDeclaration type = scope.resolveType(identifier); + superClasses.add(type); + if (type instanceof ClassDeclaration) { + scope.addParentClassScope((ClassScope) type.getScope()); + } + } + super.visit(node); + + int attributeIndex = 1; + List virtualMethodTable = node.getVirtualMethodTable(); + // This can only deal with single inheritance! + if (!superClasses.isEmpty()) { + TypeDeclaration type = superClasses.get(0); + if (type instanceof ClassDeclaration) { + ClassDeclaration clazz = (ClassDeclaration) type; + attributeIndex = clazz.getLastAttributeIndex(); + virtualMethodTable.addAll(clazz.getVirtualMethodTable()); + } + } + + // Make room for the ctable pointer + int vmtIndex = virtualMethodTable.size() + 1; + + for (Declaration decl : node.getBlock().getDeclarations()) { + if (decl instanceof VariableDeclaration) { + VariableDeclaration varDecl = (VariableDeclaration) decl; + varDecl.setAttributeIndex(attributeIndex++); + } else if (decl instanceof ProcedureDeclaration) { + ProcedureDeclaration procDecl = (ProcedureDeclaration) decl; + if (!procDecl.isInitializer()) { + boolean foundEntry = false; + for (int i = 0; !foundEntry && i < virtualMethodTable.size(); i++) { + ProcedureDeclaration vmtEntry = virtualMethodTable.get(i); + if (procDecl.matchesType(vmtEntry)) { + virtualMethodTable.set(i, procDecl); + procDecl.setVMTIndex(vmtEntry.getVMTIndex()); + foundEntry = true; + } + } + if (!foundEntry) { + virtualMethodTable.add(procDecl); + procDecl.setVMTIndex(vmtIndex++); + } + } + } + } + node.setLastAttributeIndex(attributeIndex); + } + + /** {@inheritDoc} */ + @Override + public void visit(VariableDeclaration node) { + super.visit(node); + Scope scope = node.getScope(); + node.setType(scope.resolveType(node.getTypeIdentifier())); + } + + /** {@inheritDoc} */ + @Override + public void visit(VariableAccess node) { + super.visit(node); + + Scope scope = node.getScope(); + Declaration declaration = scope.resolve(node.getIdentifier()); + + if (declaration instanceof VariableDeclaration) { + VariableDeclaration variable = (VariableDeclaration) declaration; + node.setDeclaration(variable); + visitDoubleDispatched(variable); + node.setType(variable.getType()); + if (!(scope instanceof ClassScope) && findEnclosingClass(node) == CoreClasses.voidType()) { + if (node.getDeclaration() == null + || node.getDeclaration().getPosition().getLineNumber() > node.getPosition().getLineNumber()) { + throw new UnknownIdentifierException(node.getIdentifier()); + } + } + } else if (declaration instanceof TypeDeclaration) { + TypeDeclaration type = (TypeDeclaration) declaration; + node.setDeclaration(declaration); + node.setType(type); + } + } + + /** {@inheritDoc} */ + @Override + public void visit(SelfExpression node) { + super.visit(node); + node.setType(findEnclosingClass(node)); + } + + /** {@inheritDoc} */ + @Override + public void visit(ParentExpression node) { + super.visit(node); + node.setType(node.getScope().resolveType(node.getParentIdentifier())); + node.setSelfType(findEnclosingClass(node)); + } + + /** {@inheritDoc} */ + @Override + public void visit(CastExpression node) { + super.visit(node); + node.setType(node.getScope().resolveType(node.getCastIdentifier())); + } + + /** {@inheritDoc} */ + @Override + public void visit(IsExpression node) { + super.visit(node); + node.setToType(node.getScope().resolveType(node.getIsIdentifier())); + node.setType(CoreClasses.boolType()); + } + + /** {@inheritDoc} */ + @Override + public void visit(MemberAccess node) { + visitDoubleDispatched(node.getLeft()); + if (node.getLeft().getType() instanceof ClassDeclaration) { + node.getRight().setScope(node.getLeft().getType().getScope()); + } + visitDoubleDispatched(node.getRight()); + node.setType(node.getRight().getType()); + } + + /** {@inheritDoc} */ + @Override + public void visit(ConditionalExpression node) { + super.visit(node); + node.setType(node.getThenExpression().getType()); + } + + /** {@inheritDoc} */ + @Override + public void visit(IntegerLiteral node) { + node.setType(CoreClasses.intType()); + super.visit(node); + } + + /** {@inheritDoc} */ + @Override + public void visit(FloatLiteral node) { + node.setType(CoreClasses.floatType()); + super.visit(node); + } + + /** {@inheritDoc} */ + @Override + public void visit(CharacterLiteral node) { + node.setType(CoreClasses.charType()); + super.visit(node); + } + + /** {@inheritDoc} */ + @Override + public void visit(BooleanLiteral node) { + node.setType(CoreClasses.boolType()); + super.visit(node); + } + + /** {@inheritDoc} */ + @Override + public void visit(ArrayLiteral node) { + node.setType(CoreClasses.arrayType()); + super.visit(node); + } + + /** {@inheritDoc} */ + @Override + public void visit(FunctionDeclaration node) { + Scope scope = node.getScope(); + node.setReturnType(scope.resolveType(node.getReturnTypeIdentifier())); + super.visit(node); + } + + /** {@inheritDoc} */ + @Override + public void visit(ProcedureDeclaration node) { + if (node.isMethod() && node.getIdentifier().getSymbol().equals("initializer")) { + node.setDeclarationType(ProcedureDeclaration.DeclarationType.INITIALIZER); + } + super.visit(node); + } + + /** {@inheritDoc} */ + @Override + public void visit(FunctionCall node) { + super.visit(node); + + Scope scope = node.getScope(); + TypeDeclaration declaration = null; + + try { + declaration = scope.resolveType(node.getIdentifier()); + } catch (UnknownTypeException ute) { + } + + if (declaration != null && declaration instanceof ClassDeclaration) { + ClassDeclaration classDecl = (ClassDeclaration) declaration; + node.setType(declaration); + ProcedureDeclaration initializer = findMatchingInitializer(node, classDecl); + node.setDeclaration((initializer != null) ? initializer : classDecl.getDefaultInitializer()); + } else { + ProcedureDeclaration procedure = findMatchingProcedure(node, scope.resolveProcedure(node.getIdentifier())); + node.setDeclaration(procedure); + if (procedure instanceof FunctionDeclaration) { + FunctionDeclaration function = (FunctionDeclaration) procedure; + visitDoubleDispatched(function); + node.setType(function.getReturnType()); + } else { + node.setType(CoreClasses.voidType()); + } + } + } + + /** Find an enclosing class of this node. + * + * If the search is not sucessfull this method returns CoreClasses.voidType(). */ + private ClassDeclaration findEnclosingClass(ASTNode node) { + for (ASTNode parent = node; parent != null; parent = parent.getParentNode()) { + if (parent instanceof ClassDeclaration) { + return (ClassDeclaration) parent; + } + } + return CoreClasses.voidType(); + } + + /** Searches the given class declaration in order to find a initializer declaration that matches the signature of the + * given initializer node. + * + * @param node + * a function call node representing a initializer + * @param classDeclaration + * the class declaration searched for a matching initializer. + * @return the matching initializer if one is found for the given function call or null otherwise */ + private ProcedureDeclaration findMatchingInitializer(FunctionCall node, ClassDeclaration classDeclaration) { + + List procedures = new ArrayList<>(); + + // iterate through the declarations of the given class + for (Declaration declaration : classDeclaration.getBlock().getDeclarations()) { + // find a matching declaration + if ("initializer".equals(declaration.getIdentifier().getSymbol())) { + // and verify that it is a procedure... + if (declaration instanceof ProcedureDeclaration) { + // and not a function + if (!(declaration instanceof FunctionDeclaration)) { + procedures.add((ProcedureDeclaration) declaration); + } + } + } + } + + if (procedures.isEmpty()) { + return null; + } else { + return findMatchingProcedure(node, procedures); + } + } + + /** Searches the given list of procedures in order to find one that matches the signature of the given function call. + * + * @param node + * a function call node representing the function call + * @param procedures + * the possible procedure declarations for this call + * @return the matching declaration if one is found for the given function call or the first in the list otherwise */ + private ProcedureDeclaration findMatchingProcedure(FunctionCall node, List procedures) { + + List callParams = node.getArguments(); + for (ProcedureDeclaration procedure : procedures) { + List procParams = procedure.getParameter(); + + if (callParams.size() == procParams.size()) { + boolean allParamsMatch = true; + for (int i = 0; i < callParams.size(); i++) { + Expression callParam = callParams.get(i); + VariableDeclaration procParam = procParams.get(i); + visit(procParam); + if (!callParam.getType().matchesType(procParam.getType())) { + allParamsMatch = false; + break; + } + } + if (allParamsMatch) { + return procedure; + } + } + } + return procedures.get(0); + } +} diff --git a/src/main/java/de/uni/bremen/monty/moco/visitor/SetParentVisitor.java b/src/main/java/de/uni/bremen/monty/moco/visitor/SetParentVisitor.java new file mode 100644 index 0000000..fe5c180 --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/visitor/SetParentVisitor.java @@ -0,0 +1,59 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.visitor; + +import de.uni.bremen.monty.moco.ast.ASTNode; + +/** This visitor traverses the AST and sets the parent for every AST-Node */ +public class SetParentVisitor extends BaseVisitor { + + /** The current parent for the ast node. */ + private ASTNode currentParent; + + @Override + protected void onEnterChildrenEachNode(ASTNode node) { + node.setParentNode(currentParent); + currentParent = node; + } + + @Override + protected void onExitChildrenEachNode(ASTNode node) { + currentParent = node.getParentNode(); + } +} diff --git a/src/main/java/de/uni/bremen/monty/moco/visitor/TypeCheckVisitor.java b/src/main/java/de/uni/bremen/monty/moco/visitor/TypeCheckVisitor.java new file mode 100644 index 0000000..98d541a --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/visitor/TypeCheckVisitor.java @@ -0,0 +1,278 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.visitor; + +import java.util.List; +import de.uni.bremen.monty.moco.ast.ASTNode; +import de.uni.bremen.monty.moco.ast.CoreClasses; +import de.uni.bremen.monty.moco.ast.declaration.*; +import de.uni.bremen.monty.moco.ast.expression.*; +import de.uni.bremen.monty.moco.ast.expression.literal.*; +import de.uni.bremen.monty.moco.ast.statement.Assignment; +import de.uni.bremen.monty.moco.ast.statement.ConditionalStatement; +import de.uni.bremen.monty.moco.ast.statement.ReturnStatement; +import de.uni.bremen.monty.moco.exception.*; + +/** This visitor must traverse the entire AST and perform type-safety checks. + * + * This visitor does neither resolve nor set a type. It just checks. */ +public class TypeCheckVisitor extends BaseVisitor { + + /** {@inheritDoc} */ + @Override + public void visit(ClassDeclaration node) { + for (TypeDeclaration type : node.getSuperClassDeclarations()) { + if (!(type instanceof ClassDeclaration)) { + throw new TypeMismatchException(node, String.format("Declaration of superclass is not a class.")); + } + } + super.visit(node); + } + + /** {@inheritDoc} */ + @Override + public void visit(VariableAccess node) { + super.visit(node); + Declaration declaration = node.getDeclaration(); + if (!(declaration instanceof VariableDeclaration) && !(declaration instanceof TypeDeclaration)) { + throw new TypeMismatchException(node, String.format("%s does not resolve to a type.", node.getIdentifier())); + } + } + + /** {@inheritDoc} */ + @Override + public void visit(SelfExpression node) { + super.visit(node); + if (node.getType() == CoreClasses.voidType()) { + throw new TypeMismatchException(node, "No enclosing class found."); + } + } + + /** {@inheritDoc} */ + @Override + public void visit(ParentExpression node) { + super.visit(node); + if (node.getSelfType() == CoreClasses.voidType()) { + throw new TypeMismatchException(node, "No enclosing class found."); + } + if (!node.getSelfType().getSuperClassDeclarations().contains(node.getType())) { + throw new TypeMismatchException(node, "Class not a direct parent class"); + } + } + + /** {@inheritDoc} */ + @Override + public void visit(CastExpression node) { + super.visit(node); + if (!(node.getExpression().getType() instanceof ClassDeclaration)) { + throw new TypeMismatchException(node, "It is not possible to cast something different than a class."); + } + if (!node.getType().matchesType(node.getExpression().getType())) { + throw new TypeMismatchException(node, "Impossible cast"); + } + } + + /** {@inheritDoc} */ + @Override + public void visit(IsExpression node) { + super.visit(node); + if (!(node.getExpression().getType() instanceof ClassDeclaration)) { + throw new TypeMismatchException(node, + "It is not possible to check something different than an instance of a class."); + } + } + + /** {@inheritDoc} */ + @Override + public void visit(MemberAccess node) { + super.visit(node); + if (!(node.getLeft().getType() instanceof ClassDeclaration)) { + throw new TypeMismatchException(node, "Left part is not an instance of a class declaration."); + } else if (node.getLeft() instanceof VariableAccess) { + VariableAccess varAcc = (VariableAccess) node.getLeft(); + if (varAcc.getDeclaration() instanceof ClassDeclaration) { + throw new TypeMismatchException(node, String.format( + "Invalid left part %s on member access", + node.getLeft().getClass().getSimpleName())); + } + } else if (!(node.getRight() instanceof FunctionCall) && !(node.getRight() instanceof VariableAccess) + && !(node.getRight() instanceof MemberAccess)) { + throw new TypeMismatchException(node, String.format( + "Invalid right part %s on member access.", + node.getLeft().getClass().getSimpleName())); + } + } + + /** {@inheritDoc} */ + @Override + public void visit(Assignment node) { + super.visit(node); + if (!node.getRight().getType().matchesType(node.getLeft().getType())) { + throw new TypeMismatchException(node, String.format( + "%s does not match %s", + node.getRight().getType().getIdentifier().getSymbol(), + node.getLeft().getType().getIdentifier().getSymbol())); + } + if (node.getLeft() instanceof VariableAccess) { + ((VariableAccess) node.getLeft()).setLValue(); + } else if (node.getLeft() instanceof MemberAccess) { + MemberAccess ma = (MemberAccess) node.getLeft(); + if (ma.getRight() instanceof VariableAccess) { + ((VariableAccess) ma.getRight()).setLValue(); + } + } else { + throw new InvalidExpressionException(node, "Left side is no variable"); + } + } + + /** {@inheritDoc} */ + @Override + public void visit(ConditionalExpression node) { + super.visit(node); + if (!node.getThenExpression().getType().matchesType(node.getElseExpression().getType())) { + throw new TypeMismatchException(node, String.format( + "%s does not match %s", + node.getThenExpression().getType().getIdentifier().getSymbol(), + node.getElseExpression().getType().getIdentifier().getSymbol())); + } else if (!node.getCondition().getType().matchesType(CoreClasses.boolType())) { + throw new TypeMismatchException(node, String.format( + "%s is not a bool type.", + node.getThenExpression().getType().getIdentifier().getSymbol())); + } + } + + /** {@inheritDoc} */ + @Override + public void visit(ArrayLiteral node) { + super.visit(node); + for (Expression entry : node.getEntries()) { + if (!entry.getType().matchesType(CoreClasses.intType())) { + throw new TypeMismatchException(node, "Array entries must be Int"); + } + } + } + + /** {@inheritDoc} */ + @Override + public void visit(ConditionalStatement node) { + super.visit(node); + if (!node.getCondition().getType().matchesType(CoreClasses.boolType())) { + throw new TypeMismatchException(node, + String.format("%s is not a bool type.", node.getCondition().getType())); + } + } + + /** {@inheritDoc} */ + @Override + public void visit(FunctionDeclaration node) { + super.visit(node); + if (!(node.getReturnType() instanceof ClassDeclaration)) { + throw new TypeMismatchException(node, "Must return a class type."); + } + } + + /** {@inheritDoc} */ + @Override + public void visit(FunctionCall node) { + super.visit(node); + TypeDeclaration declaration = node.getDeclaration(); + + // FunctionDeclaration extends ProcedureDeclaration + if (!(declaration instanceof ProcedureDeclaration)) { + throw new TypeMismatchException(node, String.format("%s is not a callable.", node.getIdentifier())); + } + + ProcedureDeclaration procedure = (ProcedureDeclaration) declaration; + if (declaration instanceof FunctionDeclaration) { + FunctionDeclaration function = (FunctionDeclaration) declaration; + if (function.isInitializer()) { + throw new TypeMismatchException(node, "Contructor of has to be a procedure."); + } + if (!node.getType().matchesType(function.getReturnType())) { + throw new TypeMismatchException(node, "Returntype of function call does not match declaration."); + } + } else { + if (!procedure.isInitializer() && node.getType() != CoreClasses.voidType()) { + throw new TypeMismatchException(node, "Function call of procedure must not return anything."); + } + } + + boolean callMatchesDeclaration = true; + + List callParams = node.getArguments(); + List declParams = procedure.getParameter(); + if (callParams.size() == declParams.size()) { + for (int i = 0; i < callParams.size(); i++) { + Expression callParam = callParams.get(i); + VariableDeclaration declParam = declParams.get(i); + if (!callParam.getType().matchesType(declParam.getType())) { + callMatchesDeclaration = false; + break; + } + } + } else { + callMatchesDeclaration = false; + } + + if (!callMatchesDeclaration) { + throw new TypeMismatchException(node, "Arguments of function call do not match declaration."); + } + } + + /** {@inheritDoc} */ + @Override + public void visit(ReturnStatement node) { + super.visit(node); + ASTNode parent = node; + while (!(parent instanceof ProcedureDeclaration)) { + parent = parent.getParentNode(); + } + + if (parent instanceof FunctionDeclaration) { + FunctionDeclaration func = (FunctionDeclaration) parent; + if (!(node.getParameter().getType().matchesType(func.getReturnType()))) { + throw new TypeMismatchException(node, String.format( + "Expected to return %s:", + func.getReturnType().getIdentifier())); + } + } else if (node.getParameter() != null) { + throw new TypeMismatchException(node, "Expected to return void."); + } + } +} diff --git a/src/main/java/de/uni/bremen/monty/moco/visitor/VisitOnceVisitor.java b/src/main/java/de/uni/bremen/monty/moco/visitor/VisitOnceVisitor.java new file mode 100644 index 0000000..577668a --- /dev/null +++ b/src/main/java/de/uni/bremen/monty/moco/visitor/VisitOnceVisitor.java @@ -0,0 +1,321 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ + +package de.uni.bremen.monty.moco.visitor; + +import de.uni.bremen.monty.moco.ast.ASTNode; +import de.uni.bremen.monty.moco.ast.Block; +import de.uni.bremen.monty.moco.ast.Import; +import de.uni.bremen.monty.moco.ast.Package; +import de.uni.bremen.monty.moco.ast.declaration.*; +import de.uni.bremen.monty.moco.ast.expression.*; +import de.uni.bremen.monty.moco.ast.expression.literal.*; +import de.uni.bremen.monty.moco.ast.statement.*; + +import java.util.HashMap; +import java.util.Map; + +public class VisitOnceVisitor extends BaseVisitor { + + private Map visited = new HashMap<>(); + + @Override + public void visit(ModuleDeclaration node) { + if (shouldVisit(node)) { + return; + } + super.visit(node); + this.visited.put(node, true); + } + + @Override + public void visit(ArrayLiteral node) { + if (shouldVisit(node)) { + return; + } + super.visit(node); + this.visited.put(node, true); + } + + @Override + public void visit(Package node) { + if (shouldVisit(node)) { + return; + } + super.visit(node); + this.visited.put(node, true); + } + + @Override + public void visit(ClassDeclaration node) { + if (shouldVisit(node)) { + return; + } + super.visit(node); + this.visited.put(node, true); + } + + @Override + public void visit(FunctionDeclaration node) { + if (shouldVisit(node)) { + return; + } + super.visit(node); + this.visited.put(node, true); + } + + @Override + public void visit(ProcedureDeclaration node) { + if (shouldVisit(node)) { + return; + } + super.visit(node); + this.visited.put(node, true); + } + + @Override + public void visit(VariableDeclaration node) { + if (shouldVisit(node)) { + return; + } + super.visit(node); + this.visited.put(node, true); + } + + @Override + public void visit(ConditionalExpression node) { + if (shouldVisit(node)) { + return; + } + super.visit(node); + this.visited.put(node, true); + } + + @Override + public void visit(SelfExpression node) { + if (shouldVisit(node)) { + return; + } + super.visit(node); + this.visited.put(node, true); + } + + @Override + public void visit(CastExpression node) { + if (shouldVisit(node)) { + return; + } + super.visit(node); + this.visited.put(node, true); + } + + @Override + public void visit(IsExpression node) { + if (shouldVisit(node)) { + return; + } + super.visit(node); + this.visited.put(node, true); + } + + public void visit(ParentExpression node) { + if (shouldVisit(node)) { + return; + } + super.visit(node); + this.visited.put(node, true); + } + + @Override + public void visit(FunctionCall node) { + if (shouldVisit(node)) { + return; + } + super.visit(node); + this.visited.put(node, true); + } + + @Override + public void visit(MemberAccess node) { + if (shouldVisit(node)) { + return; + } + super.visit(node); + this.visited.put(node, true); + } + + @Override + public void visit(VariableAccess node) { + if (shouldVisit(node)) { + return; + } + super.visit(node); + this.visited.put(node, true); + } + + @Override + public void visit(BooleanLiteral node) { + if (shouldVisit(node)) { + return; + } + super.visit(node); + this.visited.put(node, true); + } + + @Override + public void visit(FloatLiteral node) { + if (shouldVisit(node)) { + return; + } + super.visit(node); + this.visited.put(node, true); + } + + @Override + public void visit(IntegerLiteral node) { + if (shouldVisit(node)) { + return; + } + super.visit(node); + this.visited.put(node, true); + } + + @Override + public void visit(StringLiteral node) { + if (shouldVisit(node)) { + return; + } + super.visit(node); + this.visited.put(node, true); + } + + @Override + public void visit(Assignment node) { + if (shouldVisit(node)) { + return; + } + super.visit(node); + this.visited.put(node, true); + } + + @Override + public void visit(BreakStatement node) { + if (shouldVisit(node)) { + return; + } + super.visit(node); + this.visited.put(node, true); + } + + @Override + public void visit(SkipStatement node) { + if (shouldVisit(node)) { + return; + } + super.visit(node); + this.visited.put(node, true); + } + + @Override + public void visit(ConditionalStatement node) { + if (shouldVisit(node)) { + return; + } + super.visit(node); + this.visited.put(node, true); + } + + @Override + public void visit(ContinueStatement node) { + if (shouldVisit(node)) { + return; + } + super.visit(node); + this.visited.put(node, true); + } + + @Override + public void visit(ReturnStatement node) { + if (shouldVisit(node)) { + return; + } + super.visit(node); + this.visited.put(node, true); + } + + @Override + public void visit(WhileLoop node) { + if (shouldVisit(node)) { + return; + } + super.visit(node); + this.visited.put(node, true); + } + + @Override + public void visit(Block node) { + if (shouldVisit(node)) { + return; + } + super.visit(node); + this.visited.put(node, true); + } + + @Override + public void visit(Import node) { + if (shouldVisit(node)) { + return; + } + super.visit(node); + this.visited.put(node, true); + } + + private boolean shouldVisit(ASTNode node) { + Boolean visited1 = this.visited.get(node); + if (visited1 != null) { + if (!visited1) { + throw new RuntimeException("Cyclic dependency detected."); + } + return true; + } + this.visited.put(node, false); + return false; + } + +} diff --git a/src/main/resources/ast.png b/src/main/resources/ast.png new file mode 100644 index 0000000..90fcafc Binary files /dev/null and b/src/main/resources/ast.png differ diff --git a/src/main/resources/checkstyle.xml b/src/main/resources/checkstyle.xml new file mode 100644 index 0000000..14bca0a --- /dev/null +++ b/src/main/resources/checkstyle.xml @@ -0,0 +1,183 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/corelib/Array.monty b/src/main/resources/corelib/Array.monty new file mode 100644 index 0000000..4314af6 --- /dev/null +++ b/src/main/resources/corelib/Array.monty @@ -0,0 +1,2 @@ +Int operator[](Array array, Int index): + pass diff --git a/src/main/resources/corelib/Bool.monty b/src/main/resources/corelib/Bool.monty new file mode 100644 index 0000000..8ad7d54 --- /dev/null +++ b/src/main/resources/corelib/Bool.monty @@ -0,0 +1,21 @@ +class Bool: + + initializer(Bool b): + pass + + + Bool operator_not(): + pass + + + Bool operator_xor(Bool other): + pass + + + Bool operator_and(Bool other): + pass + + + Bool operator_or(Bool other): + pass + + + Bool operator=(Bool other): + pass + + + Bool operator!=(Bool other): + pass diff --git a/src/main/resources/corelib/Char.monty b/src/main/resources/corelib/Char.monty new file mode 100644 index 0000000..50aa2a8 --- /dev/null +++ b/src/main/resources/corelib/Char.monty @@ -0,0 +1,3 @@ +class Char: + + initializer(Char c): + pass diff --git a/src/main/resources/corelib/Float.monty b/src/main/resources/corelib/Float.monty new file mode 100644 index 0000000..b88660a --- /dev/null +++ b/src/main/resources/corelib/Float.monty @@ -0,0 +1,36 @@ +class Float: + + initializer(Float f): + pass + + + Float operator-(): + pass + + + Float operator+(Float other): + pass + + + Float operator-(Float other): + pass + + + Float operator*(Float other): + pass + + + Float operator/(Float other): + pass + + + Bool operator<(Float other): + pass + + + Bool operator>(Float other): + pass + + + Bool operator<=(Float other): + pass + + + Bool operator>=(Float other): + pass + + + Bool operator=(Float other): + pass + + + Bool operator!=(Float other): + pass diff --git a/src/main/resources/corelib/Int.monty b/src/main/resources/corelib/Int.monty new file mode 100644 index 0000000..6e16990 --- /dev/null +++ b/src/main/resources/corelib/Int.monty @@ -0,0 +1,39 @@ +class Int: + + initializer(Int i): + pass + + + Int operator-(): + pass + + + Int operator+(Int other): + pass + + + Int operator-(Int other): + pass + + + Int operator*(Int other): + pass + + + Int operator/(Int other): + pass + + + Int operator%(Int other): + pass + + + Bool operator<(Int other): + pass + + + Bool operator>(Int other): + pass + + + Bool operator<=(Int other): + pass + + + Bool operator>=(Int other): + pass + + + Bool operator=(Int other): + pass + + + Bool operator!=(Int other): + pass diff --git a/src/main/resources/corelib/Object.monty b/src/main/resources/corelib/Object.monty new file mode 100644 index 0000000..ffc1871 --- /dev/null +++ b/src/main/resources/corelib/Object.monty @@ -0,0 +1,2 @@ +class Object: + pass diff --git a/src/main/resources/corelib/Print.monty b/src/main/resources/corelib/Print.monty new file mode 100644 index 0000000..ca8367a --- /dev/null +++ b/src/main/resources/corelib/Print.monty @@ -0,0 +1,14 @@ +print(String arg1): + pass + +print(Int arg1): + pass + +print(Float arg1): + pass + +print(Bool arg1): + pass + +print(Char arg1): + pass diff --git a/src/main/resources/find-missing-license.sh b/src/main/resources/find-missing-license.sh new file mode 100755 index 0000000..cccf4f8 --- /dev/null +++ b/src/main/resources/find-missing-license.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +DIR="$SCRIPT_DIR/../../[mt]*/" + +for i in $(find $DIR -iname *.java) +do + grep "General Public License" $i > /dev/null + STATUS=$? + + if [ $STATUS -ne 0 ] + then + REALPATH=$(readlink -m $i) + echo "[WARNING] $REALPATH lacks license header" + fi +done diff --git a/src/main/resources/java-code-conv.xml b/src/main/resources/java-code-conv.xml new file mode 100644 index 0000000..84f13bb --- /dev/null +++ b/src/main/resources/java-code-conv.xml @@ -0,0 +1,291 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/log4j.properies b/src/main/resources/log4j.properies new file mode 100644 index 0000000..a970538 --- /dev/null +++ b/src/main/resources/log4j.properies @@ -0,0 +1 @@ +log4j.rootLogger = DEBUG \ No newline at end of file diff --git a/src/main/resources/moco-code-conv.xml b/src/main/resources/moco-code-conv.xml new file mode 100644 index 0000000..6a7f0a3 --- /dev/null +++ b/src/main/resources/moco-code-conv.xml @@ -0,0 +1,295 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/rm_trailing_whitespace.sh b/src/main/resources/rm_trailing_whitespace.sh new file mode 100755 index 0000000..c410cd2 --- /dev/null +++ b/src/main/resources/rm_trailing_whitespace.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash + +SRC_DIR=$1 + +echo $1 > /tmp/rm_result + +if [[ -z "$1" ]]; then + SRC_DIR="../.." +fi + +# find all java files and remove trailing ws (using system dependent sed command) +OS=`uname -s` +if [[ $OS == "Linux" ]]; then + find $SRC_DIR -type f -name "*.java" -print0 | xargs -0 sed -i -r -e 's/\s+$//g' +elif [[ $OS == "Darwin" ]]; then + find "$SRC_DIR" -type f -name "*.java" -print0 | xargs -0 sed -E -e "s/[[:space:]]+$//" -i '' +fi \ No newline at end of file diff --git a/src/main/resources/std_llvm_include.ll b/src/main/resources/std_llvm_include.ll new file mode 100644 index 0000000..aa1e4cf --- /dev/null +++ b/src/main/resources/std_llvm_include.ll @@ -0,0 +1,57 @@ +; Begin of the standard declarations and definitions every Monty program needs. +declare void @exit(i32 %status) noreturn +declare i8* @malloc(i32 %size) nounwind +declare i32 @printf(i8* %format, ... ) nounwind + +@.stringFormat = private constant [3 x i8] c"%s\00"; +@.floatFormat = private constant [3 x i8] c"%g\00"; +@.intFormat = private constant [3 x i8] c"%i\00"; +@.charFormat = private constant [3 x i8] c"%c\00"; + +; Search the sourceCTData array of pointers to vmtData for the toVMTPtr +; pointer for class inheritance-test. +define i1 @vmt_isa_class([0 x i8*]* %sourceCTData, i8* %toVMTPtr) { + %cnt = alloca i32 + store i32 0, i32* %cnt + br label %loop.start + + loop.start: + %cnt_val = load i32* %cnt + %index = getelementptr [0 x i8*]* %sourceCTData, i32 0, i32 %cnt_val + %ptr = load i8** %index + ; If the end of the array is reached (null terminated) fail.. + %cmp_null = icmp eq i8* %ptr, null + br i1 %cmp_null, label %loop.failure, label %loop.next + + loop.next: + %cnt_inr = add i32 %cnt_val, 1 + store i32 %cnt_inr, i32* %cnt + ; If the pointers are equal the class equals or inherits. + %cmp = icmp eq i8* %toVMTPtr, %ptr + br i1 %cmp, label %loop.success, label %loop.start + + loop.failure: + ret i1 0 + loop.success: + ret i1 1 +} + +; Check if the given index is within bounds (0 <= index < array.size). If not exit(3) +define void @array_bounds_check({ i64, [0 x i8*] }* %array, i64 %index) { + %gt_zero = icmp sge i64 %index, 0 + br i1 %gt_zero, label %bounds.next, label %bounds.error + + bounds.next: + %size_field = getelementptr inbounds {i64, [0 x i8*]}* %array, i32 0, i32 0 + %size = load i64* %size_field + %lt_size = icmp slt i64 %index, %size + br i1 %lt_size, label %bounds.success, label %bounds.error + + bounds.error: + call void @exit(i32 3) + ret void + bounds.success: + ret void +} +; End of the standard declarations and definitions every Monty program needs. + diff --git a/src/site/site.xml b/src/site/site.xml new file mode 100644 index 0000000..fc98acb --- /dev/null +++ b/src/site/site.xml @@ -0,0 +1,18 @@ + + + + + Monty's CocoNut + http://www.informatik.uni-bremen.de/monty/img/logo.png + http://www.informatik.uni-bremen.de/monty/ + + + + org.apache.maven.skins + maven-fluido-skin + 1.3.1 + + diff --git a/src/test/java/de/uni/bremen/monty/moco/CompileFilesBaseTest.java b/src/test/java/de/uni/bremen/monty/moco/CompileFilesBaseTest.java new file mode 100644 index 0000000..4ad9399 --- /dev/null +++ b/src/test/java/de/uni/bremen/monty/moco/CompileFilesBaseTest.java @@ -0,0 +1,96 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco; + +import de.uni.bremen.monty.moco.util.MultiOutputStream; +import org.apache.commons.io.FileUtils; + +import java.io.File; +import java.io.FilenameFilter; +import java.net.URI; +import java.net.URISyntaxException; + +import java.util.Arrays; +import java.util.Collection; + +public class CompileFilesBaseTest { + protected File file; + protected String fileName; + + public CompileFilesBaseTest(File file, String fileName) { + this.file = file; + this.fileName = fileName; + } + + protected static Collection buildParameterObject(Collection programFiles) { + Object[][] a = new Object[programFiles.size()][1]; + int i = 0; + for (File programFile : programFiles) { + a[i++] = new Object[] { programFile, programFile.getName() }; + } + return Arrays.asList(a); + } + + protected static Collection getFiles4Filter(String folderPath, String[] filter) throws URISyntaxException { + Class aClass = CompileTestProgramsTest.class; + ClassLoader classLoader = aClass.getClassLoader(); + File testprogramFolder = new File(classLoader.getResource(folderPath).toURI()); + return FileUtils.listFiles(testprogramFolder, filter, true); + } + + protected static Collection getAllMontyFiles(String folderPath) throws URISyntaxException { + return getFiles4Filter(folderPath, new String[] { "monty" }); + } + + protected static File getLastModifiedMontyFile(String folderPath) throws URISyntaxException { + + final File[] montyFilesInDir = + getFiles4Filter(folderPath, new String[] { "monty", "ignore" }).toArray(new File[0]); + File latestModifiedMontyProgram = montyFilesInDir[0]; + + for (File file : montyFilesInDir) { + if (file.lastModified() > latestModifiedMontyProgram.lastModified()) { + latestModifiedMontyProgram = file; + } + } + + return latestModifiedMontyProgram; + } + +} diff --git a/src/test/java/de/uni/bremen/monty/moco/CompileLatestTestProgramsTest.java b/src/test/java/de/uni/bremen/monty/moco/CompileLatestTestProgramsTest.java new file mode 100644 index 0000000..dae8601 --- /dev/null +++ b/src/test/java/de/uni/bremen/monty/moco/CompileLatestTestProgramsTest.java @@ -0,0 +1,94 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ + +package de.uni.bremen.monty.moco; + +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.PrintStream; +import java.util.Arrays; +import java.util.Collection; + +import static de.uni.bremen.monty.moco.IntegrationTestUtils.*; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.isEmptyString; +import static org.junit.runners.Parameterized.Parameters; + +@Ignore +@RunWith(Parameterized.class) +public class CompileLatestTestProgramsTest extends CompileFilesBaseTest { + + public CompileLatestTestProgramsTest(File file, String fileName) { + super(file, fileName); + } + + @Parameters(name = "Program: {1}") + public static Collection data() throws Exception { + + File[] programFiles = { getLastModifiedMontyFile("testPrograms/") }; + return buildParameterObject(Arrays.asList(programFiles)); + } + + @Test + public void compileProgramTest() throws IOException { + final PrintStream bufferOut = System.out; + final PrintStream bufferErr = System.err; + final ByteArrayOutputStream outStream = setStdout(); + final ByteArrayOutputStream errorStream = setStdErr(file); + + Main.main(new String[] { "-k", file.getAbsolutePath(), "-e" }); + + if (outputFileExists(file)) { + assertThat(getOutput(errorStream), is(isEmptyString())); + assertThat(getOutput(outStream), is(expectedResultFromFile(file))); + } else { + assertThat(getOutput(errorStream), is(expectedErrorFromFile(file))); + assertThat(getOutput(outStream), is(isEmptyString())); + } + System.setOut(bufferOut); + System.setErr(bufferErr); + } +} diff --git a/src/test/java/de/uni/bremen/monty/moco/CompileTestProgramsTest.java b/src/test/java/de/uni/bremen/monty/moco/CompileTestProgramsTest.java new file mode 100644 index 0000000..df0c053 --- /dev/null +++ b/src/test/java/de/uni/bremen/monty/moco/CompileTestProgramsTest.java @@ -0,0 +1,91 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco; + +import static de.uni.bremen.monty.moco.IntegrationTestUtils.*; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.PrintStream; +import java.util.Collection; +import org.apache.commons.lang3.StringUtils; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.isEmptyString; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; + +@RunWith(Parameterized.class) +public class CompileTestProgramsTest extends CompileFilesBaseTest { + + public CompileTestProgramsTest(File file, String fileName) { + super(file, fileName); + } + + @Parameters(name = "Program: {1}") + public static Collection data() throws Exception { + Collection programFiles = getAllMontyFiles("testPrograms/"); + + return buildParameterObject(programFiles); + } + + @Test + public void compileProgramTest() throws IOException { + final PrintStream bufferOut = System.out; + final PrintStream bufferErr = System.err; + final ByteArrayOutputStream outStream = setStdout(); + final ByteArrayOutputStream errorStream = setStdErr(file); + + Main.main(new String[] { "-k", file.getAbsolutePath(), "-e" }); + + if (outputFileExists(file)) { + assertThat(getOutput(errorStream), is(isEmptyString())); + assertThat(getOutput(outStream), is(expectedResultFromFile(file))); + } else { + // chop the last char to not contain /n in the string + assertThat(StringUtils.chop(getOutput(errorStream)), is(expectedErrorFromFile(file))); + assertThat(getOutput(outStream), is(isEmptyString())); + } + System.setOut(bufferOut); + System.setErr(bufferErr); + } + +} diff --git a/src/test/java/de/uni/bremen/monty/moco/IntegrationTestUtils.java b/src/test/java/de/uni/bremen/monty/moco/IntegrationTestUtils.java new file mode 100644 index 0000000..46f85fa --- /dev/null +++ b/src/test/java/de/uni/bremen/monty/moco/IntegrationTestUtils.java @@ -0,0 +1,106 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ + +package de.uni.bremen.monty.moco; + +import static de.uni.bremen.monty.moco.IntegrationTestUtils.outputFileExists; +import de.uni.bremen.monty.moco.util.MultiOutputStream; + +import java.io.*; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; + +public class IntegrationTestUtils { + protected static String getOutput(ByteArrayOutputStream outStream) { + return new String(outStream.toByteArray()); + + } + + protected static ByteArrayOutputStream setStdout() { + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + System.setOut(new PrintStream(byteArrayOutputStream)); + return byteArrayOutputStream; + } + + protected static ByteArrayOutputStream setStdErr(File file) { + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + + if (outputFileExists(file)) { + OutputStream errStream = new MultiOutputStream(byteArrayOutputStream, System.err); + System.setErr(new PrintStream(errStream)); + } else { + + System.setErr(new PrintStream(byteArrayOutputStream)); + } + + return byteArrayOutputStream; + } + + protected static ByteArrayOutputStream setStdErr() { + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + OutputStream errStream = new MultiOutputStream(byteArrayOutputStream, System.err); + System.setErr(new PrintStream(errStream)); + return byteArrayOutputStream; + } + + protected static String getExpectedResultFromFile(String outputFile) throws IOException { + byte[] encoded = Files.readAllBytes(Paths.get(outputFile)); + return new String(encoded, StandardCharsets.UTF_8); + } + + protected static String expectedResultFromFile(File file) throws IOException { + String outputFile = changeFileExtension(file, ".output"); + return IntegrationTestUtils.getExpectedResultFromFile(outputFile); + } + + private static String changeFileExtension(File file, String newExtension) { + return file.getAbsolutePath().substring(0, file.getAbsolutePath().lastIndexOf('.')) + newExtension; + } + + protected static String expectedErrorFromFile(File file) throws IOException { + String outputFile = changeFileExtension(file, ".error"); + return IntegrationTestUtils.getExpectedResultFromFile(outputFile); + } + + protected static boolean outputFileExists(File file) { + String outputFile = changeFileExtension(file, ".output"); + return new File(outputFile).exists(); + } +} diff --git a/src/test/java/de/uni/bremen/monty/moco/ModuleProgramsTest.java b/src/test/java/de/uni/bremen/monty/moco/ModuleProgramsTest.java new file mode 100644 index 0000000..e88697e --- /dev/null +++ b/src/test/java/de/uni/bremen/monty/moco/ModuleProgramsTest.java @@ -0,0 +1,77 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ + +package de.uni.bremen.monty.moco; + +import org.junit.Test; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.net.URISyntaxException; +import java.net.URL; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.isEmptyString; + +public class ModuleProgramsTest { + + @Test + public void compileProgramTest() throws Exception { + ByteArrayOutputStream outStream = IntegrationTestUtils.setStdout(); + ByteArrayOutputStream errorStream = IntegrationTestUtils.setStdErr(); + + Class aClass = ModuleProgramsTest.class; + ClassLoader classLoader = aClass.getClassLoader(); + String name = "testModuleProgramms/"; + String absolutePath = getAbsolutePath(classLoader, name); + Main.main(new String[] { "-k", absolutePath, "de.dafuq.monty.Module1", "-e" }); + + assertThat(IntegrationTestUtils.getOutput(errorStream), is(isEmptyString())); + String outputFileName = getAbsolutePath(classLoader, name + "de/dafuq/monty/Main.output"); + String expectedResultFromFile = IntegrationTestUtils.getExpectedResultFromFile(outputFileName); + assertThat(IntegrationTestUtils.getOutput(outStream), is(expectedResultFromFile)); + } + + private String getAbsolutePath(ClassLoader classLoader, String name) throws URISyntaxException { + URL testModulesFolder = classLoader.getResource(name); + + return new File(testModulesFolder.toURI()).getAbsolutePath(); + } +} diff --git a/src/test/java/de/uni/bremen/monty/moco/ast/ASTBuilderTest.java b/src/test/java/de/uni/bremen/monty/moco/ast/ASTBuilderTest.java new file mode 100644 index 0000000..1cfa19a --- /dev/null +++ b/src/test/java/de/uni/bremen/monty/moco/ast/ASTBuilderTest.java @@ -0,0 +1,270 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.ast; + +import de.uni.bremen.monty.moco.CompileTestProgramsTest; +import de.uni.bremen.monty.moco.antlr.MontyLexer; +import de.uni.bremen.monty.moco.antlr.MontyParser; +import de.uni.bremen.monty.moco.ast.declaration.*; +import de.uni.bremen.monty.moco.ast.expression.FunctionCall; +import de.uni.bremen.monty.moco.ast.expression.VariableAccess; +import de.uni.bremen.monty.moco.ast.expression.literal.IntegerLiteral; +import de.uni.bremen.monty.moco.ast.expression.literal.StringLiteral; +import de.uni.bremen.monty.moco.ast.statement.Assignment; +import de.uni.bremen.monty.moco.ast.statement.ConditionalStatement; +import org.antlr.v4.runtime.ANTLRInputStream; +import org.antlr.v4.runtime.CommonTokenStream; +import org.apache.commons.io.FileUtils; +import org.junit.Ignore; +import org.junit.Test; + +import java.io.File; +import java.io.IOException; +import java.net.URISyntaxException; + +import static de.uni.bremen.monty.moco.ast.declaration.VariableDeclaration.DeclarationType; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertTrue; + +public class ASTBuilderTest { + + @Test + public void shouldConvertVariableInitialisation() throws Exception { + ModuleDeclaration ast = buildASTfrom("varDecl"); + + VariableDeclaration declaration = (VariableDeclaration) ast.getBlock().getDeclarations().get(0); + + Assignment statement = (Assignment) ast.getBlock().getStatements().get(0); + VariableAccess left = (VariableAccess) statement.getLeft(); + StringLiteral right = (StringLiteral) statement.getRight(); + + assertThat(declaration.getIdentifier().getSymbol(), is("s")); + assertThat(left.getIdentifier().getSymbol(), is("s")); + assertThat(right.getValue(), is("Hallo")); + + } + + @Test + public void shouldConvertDeclarationType() throws Exception { + ModuleDeclaration ast = buildASTfrom("declarationType"); + + ClassDeclaration classDecl = (ClassDeclaration) ast.getBlock().getDeclarations().get(0); + VariableDeclaration memberDecl = (VariableDeclaration) classDecl.getBlock().getDeclarations().get(0); + VariableDeclaration memberInit = (VariableDeclaration) classDecl.getBlock().getDeclarations().get(1); + ProcedureDeclaration memberProc = (ProcedureDeclaration) classDecl.getBlock().getDeclarations().get(2); + FunctionDeclaration memberFun = (FunctionDeclaration) classDecl.getBlock().getDeclarations().get(3); + + VariableDeclaration varDecl = (VariableDeclaration) ast.getBlock().getDeclarations().get(1); + VariableDeclaration varInit = (VariableDeclaration) ast.getBlock().getDeclarations().get(2); + FunctionDeclaration funDecl = (FunctionDeclaration) ast.getBlock().getDeclarations().get(3); + ProcedureDeclaration procDecl = (ProcedureDeclaration) ast.getBlock().getDeclarations().get(4); + + assertThat(varDecl.getDeclarationType(), is(VariableDeclaration.DeclarationType.VARIABLE)); + assertThat(varInit.getDeclarationType(), is(VariableDeclaration.DeclarationType.VARIABLE)); + assertThat( + funDecl.getParameter().get(0).getDeclarationType(), + is(VariableDeclaration.DeclarationType.PARAMETER)); + assertThat( + procDecl.getParameter().get(0).getDeclarationType(), + is(VariableDeclaration.DeclarationType.PARAMETER)); + + assertThat(memberDecl.getDeclarationType(), is(VariableDeclaration.DeclarationType.ATTRIBUTE)); + assertThat(memberInit.getDeclarationType(), is(VariableDeclaration.DeclarationType.ATTRIBUTE)); + assertThat( + memberProc.getParameter().get(0).getDeclarationType(), + is(VariableDeclaration.DeclarationType.PARAMETER)); + assertThat( + memberFun.getParameter().get(0).getDeclarationType(), + is(VariableDeclaration.DeclarationType.PARAMETER)); + + assertThat(memberProc.getDeclarationType(), is(ProcedureDeclaration.DeclarationType.METHOD)); + assertThat(memberFun.getDeclarationType(), is(ProcedureDeclaration.DeclarationType.METHOD)); + assertThat(funDecl.getDeclarationType(), is(ProcedureDeclaration.DeclarationType.UNBOUND)); + assertThat(procDecl.getDeclarationType(), is(ProcedureDeclaration.DeclarationType.UNBOUND)); + + } + + @Test + public void shouldConvertIf() throws Exception { + ModuleDeclaration ast = buildASTfrom("ifElse"); + + ConditionalStatement condStmt = (ConditionalStatement) ast.getBlock().getStatements().get(0); + + VariableAccess condition = (VariableAccess) condStmt.getCondition(); + FunctionCall thenBlock = (FunctionCall) condStmt.getThenBlock().getStatements().get(0); + Block elseBlock = condStmt.getElseBlock(); + + assertThat(condition.getIdentifier().getSymbol(), is("a")); + + assertThat(getValue(thenBlock), is(1)); + assertTrue(elseBlock.isEmpty()); + } + + @Test + public void shouldConvertIfElse() throws Exception { + ModuleDeclaration ast = buildASTfrom("ifElse"); + + ConditionalStatement condStmt = (ConditionalStatement) ast.getBlock().getStatements().get(1); + + VariableAccess condition = (VariableAccess) condStmt.getCondition(); + FunctionCall thenBlock = (FunctionCall) condStmt.getThenBlock().getStatements().get(0); + FunctionCall elseBlock = (FunctionCall) condStmt.getElseBlock().getStatements().get(0); + + assertThat(condition.getIdentifier().getSymbol(), is("a")); + + assertThat(getValue(thenBlock), is(1)); + assertThat(getValue(elseBlock), is(2)); + } + + @Test + public void shouldConvertIfWithElseAndElseIf() throws Exception { + ModuleDeclaration ast = buildASTfrom("ifElse"); + + ConditionalStatement condStmt = (ConditionalStatement) ast.getBlock().getStatements().get(2); + + VariableAccess firstCondition = (VariableAccess) condStmt.getCondition(); + FunctionCall firstThenBlock = (FunctionCall) condStmt.getThenBlock().getStatements().get(0); + ConditionalStatement firstElseBlock = (ConditionalStatement) condStmt.getElseBlock().getStatements().get(0); + + VariableAccess secondCondition = (VariableAccess) firstElseBlock.getCondition(); + FunctionCall secondThenBlock = (FunctionCall) firstElseBlock.getThenBlock().getStatements().get(0); + FunctionCall secondElseBlock = (FunctionCall) firstElseBlock.getElseBlock().getStatements().get(0); + + assertThat(firstCondition.getIdentifier().getSymbol(), is("a")); + assertThat(secondCondition.getIdentifier().getSymbol(), is("b")); + + assertThat(getValue(firstThenBlock), is(1)); + assertThat(getValue(secondThenBlock), is(2)); + assertThat(getValue(secondElseBlock), is(3)); + + } + + @Test + public void shouldConvertIfWithElseAnd2ElseIf() throws Exception { + ModuleDeclaration ast = buildASTfrom("ifElse"); + + ConditionalStatement condStmt = (ConditionalStatement) ast.getBlock().getStatements().get(3); + + VariableAccess firstCondition = (VariableAccess) condStmt.getCondition(); + FunctionCall firstThenBlock = (FunctionCall) condStmt.getThenBlock().getStatements().get(0); + ConditionalStatement firstElseBlock = (ConditionalStatement) condStmt.getElseBlock().getStatements().get(0); + + VariableAccess secondCondition = (VariableAccess) firstElseBlock.getCondition(); + FunctionCall secondThenBlock = (FunctionCall) firstElseBlock.getThenBlock().getStatements().get(0); + ConditionalStatement secondElseBlock = + (ConditionalStatement) firstElseBlock.getElseBlock().getStatements().get(0); + + VariableAccess thirdCondition = (VariableAccess) secondElseBlock.getCondition(); + FunctionCall thirdThenBlock = (FunctionCall) secondElseBlock.getThenBlock().getStatements().get(0); + FunctionCall thirdElseBlock = (FunctionCall) secondElseBlock.getElseBlock().getStatements().get(0); + + assertThat(firstCondition.getIdentifier().getSymbol(), is("a")); + assertThat(secondCondition.getIdentifier().getSymbol(), is("b")); + assertThat(thirdCondition.getIdentifier().getSymbol(), is("c")); + + assertThat(getValue(firstThenBlock), is(1)); + assertThat(getValue(secondThenBlock), is(2)); + assertThat(getValue(thirdThenBlock), is(3)); + assertThat(getValue(thirdElseBlock), is(4)); + + } + + @Test + public void shouldConvertIfWith2ElseIf() throws Exception { + ModuleDeclaration ast = buildASTfrom("ifElse"); + + ConditionalStatement condStmt = (ConditionalStatement) ast.getBlock().getStatements().get(4); + + VariableAccess firstCondition = (VariableAccess) condStmt.getCondition(); + FunctionCall firstThenBlock = (FunctionCall) condStmt.getThenBlock().getStatements().get(0); + ConditionalStatement firstElseBlock = (ConditionalStatement) condStmt.getElseBlock().getStatements().get(0); + + VariableAccess secondCondition = (VariableAccess) firstElseBlock.getCondition(); + FunctionCall secondThenBlock = (FunctionCall) firstElseBlock.getThenBlock().getStatements().get(0); + ConditionalStatement secondElseBlock = + (ConditionalStatement) firstElseBlock.getElseBlock().getStatements().get(0); + + VariableAccess thirdCondition = (VariableAccess) secondElseBlock.getCondition(); + FunctionCall thirdThenBlock = (FunctionCall) secondElseBlock.getThenBlock().getStatements().get(0); + + assertThat(firstCondition.getIdentifier().getSymbol(), is("a")); + assertThat(secondCondition.getIdentifier().getSymbol(), is("b")); + assertThat(thirdCondition.getIdentifier().getSymbol(), is("c")); + + assertThat(getValue(firstThenBlock), is(1)); + assertThat(getValue(secondThenBlock), is(2)); + assertThat(getValue(thirdThenBlock), is(3)); + + assertTrue(secondElseBlock.getElseBlock().isEmpty()); + + } + + private int getValue(FunctionCall print) { + return ((IntegerLiteral) print.getArguments().get(0)).getValue(); + } + + private ModuleDeclaration buildASTfrom(String varDecl) throws IOException, URISyntaxException { + String fileName = "testAstBuilder/" + varDecl + ".monty"; + + String montyProgram = getFileContent(fileName); + MontyParser parser = createMontyParser(montyProgram); + return buildAST(fileName, parser); + } + + private ModuleDeclaration buildAST(String fileName, MontyParser parser) { + ASTBuilder astBuilder = new ASTBuilder(fileName); + ASTNode rootNode = astBuilder.visitModuleDeclaration(parser.moduleDeclaration()); + return (ModuleDeclaration) rootNode; + } + + private MontyParser createMontyParser(String montyProgram) { + ANTLRInputStream input = new ANTLRInputStream(montyProgram + "\n"); + MontyLexer lexer = new MontyLexer(input); + CommonTokenStream tokens = new CommonTokenStream(lexer); + return new MontyParser(tokens); + } + + private String getFileContent(String fileName) throws URISyntaxException, IOException { + Class aClass = CompileTestProgramsTest.class; + ClassLoader classLoader = aClass.getClassLoader(); + File file = new File(classLoader.getResource(fileName).toURI()); + return FileUtils.readFileToString(file); + } +} diff --git a/src/test/java/de/uni/bremen/monty/moco/ast/ControlFlowTest.java b/src/test/java/de/uni/bremen/monty/moco/ast/ControlFlowTest.java new file mode 100644 index 0000000..c271bbd --- /dev/null +++ b/src/test/java/de/uni/bremen/monty/moco/ast/ControlFlowTest.java @@ -0,0 +1,894 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.ast; + +import de.uni.bremen.monty.moco.ast.declaration.FunctionDeclaration; +import de.uni.bremen.monty.moco.ast.declaration.ModuleDeclaration; +import de.uni.bremen.monty.moco.ast.declaration.ProcedureDeclaration; +import de.uni.bremen.monty.moco.ast.declaration.VariableDeclaration; +import de.uni.bremen.monty.moco.ast.expression.Expression; +import de.uni.bremen.monty.moco.ast.expression.literal.BooleanLiteral; +import de.uni.bremen.monty.moco.ast.expression.literal.StringLiteral; +import de.uni.bremen.monty.moco.ast.statement.*; +import de.uni.bremen.monty.moco.exception.InvalidControlFlowException; +import de.uni.bremen.monty.moco.visitor.ControlFlowVisitor; +import de.uni.bremen.monty.moco.visitor.DeclarationVisitor; +import de.uni.bremen.monty.moco.visitor.SetParentVisitor; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +public class ControlFlowTest { + + private SetParentVisitor setParentVisitor; + private ControlFlowVisitor controlFlowVisitor; + + // MODULE + private Block moduleBlock; + private List moduleImports; + private Package aPackage; + private ModuleDeclaration moduleDeclaration; + + // MODULE LOOP + private Expression moduleLoopCondition; + private Block moduleLoopBlock; + private WhileLoop moduleLoop; + private ContinueStatement moduleLoopContinueStatement; + private BreakStatement moduleLoopBreakStatement; + private Expression moduleLoopLoopCondition; + private Block moduleLoopLoopBlock; + + // MODULE LOOP LOOP + private WhileLoop moduleLoopLoop; + private ContinueStatement moduleLoopLoopContinueStatement; + private BreakStatement moduleLoopLoopBreakStatement; + private Expression moduleLoopLoopConditionalStatementCondition; + private Block moduleLoopLoopConditionalStatementThenBlock; + private Block moduleLoopLoopConditionalStatementElseBlock; + private ConditionalStatement moduleLoopLoopConditionalStatement; + private Expression moduleLoopLoopThenConditionalStatementCondition; + private Block moduleLoopLoopThenConditionalStatementThenBlock; + private Block moduleLoopLoopThenConditionalStatementElseBlock; + private ConditionalStatement moduleLoopLoopThenConditionalStatement; + private Expression moduleLoopLoopElseConditionalStatementCondition; + private Block moduleLoopLoopElseConditionalStatementThenBlock; + private Block moduleLoopLoopElseConditionalStatementElseBlock; + private ConditionalStatement moduleLoopLoopElseConditionalStatement; + + // MODULE LOOP CONDITIONAL STATEMENT + private Expression moduleLoopConditionalStatementCondition; + private Block moduleLoopConditionalStatementThenBlock; + private Block moduleLoopConditionalStatementElseBlock; + private ConditionalStatement moduleLoopConditionalStatement; + private ContinueStatement moduleLoopConditionalContinueStatement; + private BreakStatement moduleLoopConditionalBreakStatement; + + // MODULE CONDITIONAL STATEMENT + private Expression moduleConditionalStatementCondition; + private Block moduleConditionalStatementThenBlock; + private Block moduleConditionalStatementElseBlock; + private ConditionalStatement moduleConditionalStatement; + + // MODULE STATETEMENTS + private ContinueStatement moduleContinueStatement; + private BreakStatement moduleBreakStatement; + private Expression moduleReturnStatementParameter; + private ReturnStatement moduleReturnStatement; + + // MODULE FUNCTION + private Block moduleFunctionBlock; + private List moduleFunctionParameter; + private FunctionDeclaration moduleFunctionDeclaration; + private Expression moduleFunctionReturnStatementParameter; + private ReturnStatement moduleFunctionReturnStatement; + + // MODULE FUNCTION PROCEDURE + private Block moduleFunctionProcedureBlock; + private List moduleFunctionProcedureParameter; + private ProcedureDeclaration moduleFunctionProcedureDeclaration; + private Expression moduleFunctionProcedureReturnStatementParameter; + private ReturnStatement moduleFunctionProcedureReturnStatement; + + // MODULE FUNCTION CONDITIONAL STATEMENT + private Expression moduleFunctionConditionalStatementCondition; + private Block moduleFunctionConditionalStatementThenBlock; + private Block moduleFunctionConditionalStatementElseBlock; + private ConditionalStatement moduleFunctionConditionalStatement; + private Expression moduleFunctionConditionalReturnThenStatementParameter; + private ReturnStatement moduleFunctionConditionalReturnThenStatement; + private Expression moduleFunctionConditionalReturnElseStatementParameter; + private ReturnStatement moduleFunctionConditionalReturnElseStatement; + private Expression moduleFunctionConditionalConditionalStatementCondition; + private Block moduleFunctionConditionalConditionalStatementThenBlock; + private Block moduleFunctionConditionalConditionalStatementElseBlock; + private ConditionalStatement moduleFunctionConditionalConditionalStatement; + private Expression moduleFunctionConditionalConditionalReturnStatementParameter; + private ReturnStatement moduleFunctionConditionalConditionalReturnStatement; + private Expression moduleFunctionConditionalConditionalConditionalStatementCondition; + private Block moduleFunctionConditionalConditionalConditionalStatementThenBlock; + private Block moduleFunctionConditionalConditionalConditionalStatementElseBlock; + private ConditionalStatement moduleFunctionConditionalConditionalConditionalStatement; + private Expression moduleFunctionConditionalConditionalConditionalThenReturnStatementParameter; + private ReturnStatement moduleFunctionConditionalConditionalConditionalThenReturnStatement; + private Expression moduleFunctionConditionalConditionalConditionalElseReturnStatementParameter; + private ReturnStatement moduleFunctionConditionalConditionalConditionalElseReturnStatement; + + // MODULE FUNCTION LOOP + private Expression moduleFunctionLoopCondition; + private Block moduleFunctionLoopBlock; + private WhileLoop moduleFunctionLoop; + private Expression moduleFunctionLoopReturnStatementParameter; + private ReturnStatement moduleFunctionLoopReturnStatement; + private Expression moduleFunctionLoopLoopCondition; + private Block moduleFunctionLoopLoopBlock; + private WhileLoop moduleFunctionLoopLoop; + private Expression moduleFunctionLoopLoopLoopCondition; + private Block moduleFunctionLoopLoopLoopBlock; + private WhileLoop moduleFunctionLoopLoopLoop; + private Expression moduleFunctionLoopLoopLoopReturnStatementParameter; + private ReturnStatement moduleFunctionLoopLoopLoopReturnStatement; + + // helper + private int counter = 0; + + public Position nextPosition() { + return new Position("TestFile", counter++, 1); + } + + @Before + public void setUpAST() { + + // reset counter + counter = 0; + + // VISITORS --------------------------- + setParentVisitor = new SetParentVisitor(); + setParentVisitor.setStopOnFirstError(true); + controlFlowVisitor = new ControlFlowVisitor(); + controlFlowVisitor.setStopOnFirstError(true); + + // AST -------------------------------- + + // MODULE + moduleBlock = new Block(nextPosition()); + moduleImports = new ArrayList<>(); // empty list is fine here ... + moduleDeclaration = + new ModuleDeclaration(nextPosition(), new Identifier("TestModule"), moduleBlock, moduleImports); + + aPackage = new Package(new Identifier("")); + aPackage.addModule(moduleDeclaration); + + // MODULE LOOP + moduleLoopCondition = new BooleanLiteral(nextPosition(), true); + moduleLoopBlock = new Block(nextPosition()); + moduleLoop = new WhileLoop(nextPosition(), moduleLoopCondition, moduleLoopBlock); + moduleLoopContinueStatement = new ContinueStatement(nextPosition()); + moduleLoopBreakStatement = new BreakStatement(nextPosition()); + // add module loop to module + moduleBlock.addStatement(moduleLoop); + + // MODULE LOOP LOOP + moduleLoopLoopCondition = new BooleanLiteral(nextPosition(), true); + moduleLoopLoopBlock = new Block(nextPosition()); + moduleLoopLoop = new WhileLoop(nextPosition(), moduleLoopLoopCondition, moduleLoopLoopBlock); + moduleLoopLoopContinueStatement = new ContinueStatement(nextPosition()); + moduleLoopLoopBreakStatement = new BreakStatement(nextPosition()); + // add module loop loop to module loop + moduleLoopBlock.addStatement(moduleLoopLoop); + moduleLoopLoopConditionalStatementCondition = new BooleanLiteral(nextPosition(), true); + moduleLoopLoopConditionalStatementThenBlock = new Block(nextPosition()); + moduleLoopLoopConditionalStatementElseBlock = new Block(nextPosition()); + moduleLoopLoopConditionalStatement = + new ConditionalStatement(nextPosition(), moduleLoopLoopConditionalStatementCondition, + moduleLoopLoopConditionalStatementThenBlock, moduleLoopLoopConditionalStatementElseBlock); + moduleLoopLoopThenConditionalStatementCondition = new BooleanLiteral(nextPosition(), true); + moduleLoopLoopThenConditionalStatementThenBlock = new Block(nextPosition()); + moduleLoopLoopThenConditionalStatementElseBlock = new Block(nextPosition()); + moduleLoopLoopThenConditionalStatement = + new ConditionalStatement(nextPosition(), moduleLoopLoopThenConditionalStatementCondition, + moduleLoopLoopThenConditionalStatementThenBlock, + moduleLoopLoopThenConditionalStatementElseBlock); + moduleLoopLoopElseConditionalStatementCondition = new BooleanLiteral(nextPosition(), true); + moduleLoopLoopElseConditionalStatementThenBlock = new Block(nextPosition()); + moduleLoopLoopElseConditionalStatementElseBlock = new Block(nextPosition()); + moduleLoopLoopElseConditionalStatement = + new ConditionalStatement(nextPosition(), moduleLoopLoopElseConditionalStatementCondition, + moduleLoopLoopElseConditionalStatementThenBlock, + moduleLoopLoopElseConditionalStatementElseBlock); + + // MODULE LOOP CONDITIONAL STATEMENT + moduleLoopConditionalStatementCondition = new BooleanLiteral(nextPosition(), true); + moduleLoopConditionalStatementThenBlock = new Block(nextPosition()); + moduleLoopConditionalStatementElseBlock = new Block(nextPosition()); + moduleLoopConditionalStatement = + new ConditionalStatement(nextPosition(), moduleLoopConditionalStatementCondition, + moduleLoopConditionalStatementThenBlock, moduleLoopConditionalStatementElseBlock); + moduleLoopConditionalContinueStatement = new ContinueStatement(nextPosition()); + moduleLoopConditionalBreakStatement = new BreakStatement(nextPosition()); + // add module loop conditional statement to module loop + moduleLoopBlock.addStatement(moduleLoopConditionalStatement); + + // MODULE CONDITIONAL STATEMENT + moduleConditionalStatementCondition = new BooleanLiteral(nextPosition(), true); + moduleConditionalStatementThenBlock = new Block(nextPosition()); + moduleConditionalStatementElseBlock = new Block(nextPosition()); + moduleConditionalStatement = + new ConditionalStatement(nextPosition(), moduleConditionalStatementCondition, + moduleConditionalStatementThenBlock, moduleConditionalStatementElseBlock); + // add statements to module conditional statement (then) + // add module conditional statement to module + moduleBlock.addStatement(moduleConditionalStatement); + + // MODULE STATETEMENTS + moduleContinueStatement = new ContinueStatement(nextPosition()); + moduleBreakStatement = new BreakStatement(nextPosition()); + moduleReturnStatementParameter = new StringLiteral(nextPosition(), "return"); + moduleReturnStatement = new ReturnStatement(nextPosition(), moduleReturnStatementParameter); + // add statements to module + // moduleBlock.addStatement(moduleContinueStatement); + // moduleBlock.addStatement(moduleBreakStatement); + // moduleBlock.addStatement(moduleReturnStatement); + + // MODULE FUNCTION + moduleFunctionBlock = new Block(nextPosition()); + moduleFunctionParameter = new ArrayList<>(); + moduleFunctionDeclaration = + new FunctionDeclaration(nextPosition(), new Identifier("ModuleFunction"), moduleFunctionBlock, + moduleFunctionParameter, new ResolvableIdentifier("String")); + moduleFunctionReturnStatementParameter = new StringLiteral(nextPosition(), "return"); + moduleFunctionReturnStatement = new ReturnStatement(nextPosition(), moduleFunctionReturnStatementParameter); + + // MODULE FUNCTION PROCEDURE + moduleFunctionProcedureBlock = new Block(nextPosition()); + moduleFunctionProcedureParameter = new ArrayList<>(); + moduleFunctionProcedureDeclaration = + new ProcedureDeclaration(nextPosition(), new Identifier("ModuleFunctionProcedure"), + moduleFunctionProcedureBlock, moduleFunctionProcedureParameter); + moduleFunctionProcedureReturnStatementParameter = new StringLiteral(nextPosition(), "return"); + moduleFunctionProcedureReturnStatement = + new ReturnStatement(nextPosition(), moduleFunctionProcedureReturnStatementParameter); + // add module function procedure to module function + // moduleFunctionBlock.addDeclaration(moduleFunctionProcedureDeclaration); + + // MODULE FUNCTION CONDITIONAL STATEMENT + moduleFunctionConditionalStatementCondition = new BooleanLiteral(nextPosition(), false); + moduleFunctionConditionalStatementThenBlock = new Block(nextPosition()); + moduleFunctionConditionalStatementElseBlock = new Block(nextPosition()); + moduleFunctionConditionalStatement = + new ConditionalStatement(nextPosition(), moduleFunctionConditionalStatementCondition, + moduleFunctionConditionalStatementThenBlock, moduleFunctionConditionalStatementElseBlock); + // add module function conditional statement to module function + moduleFunctionBlock.addStatement(moduleFunctionConditionalStatement); + moduleFunctionConditionalReturnThenStatementParameter = new StringLiteral(nextPosition(), "return"); + moduleFunctionConditionalReturnThenStatement = + new ReturnStatement(nextPosition(), moduleFunctionConditionalReturnThenStatementParameter); + moduleFunctionConditionalReturnElseStatementParameter = new StringLiteral(nextPosition(), "return"); + moduleFunctionConditionalReturnElseStatement = + new ReturnStatement(nextPosition(), moduleFunctionConditionalReturnElseStatementParameter); + moduleFunctionConditionalConditionalStatementCondition = new BooleanLiteral(nextPosition(), true); + moduleFunctionConditionalConditionalStatementThenBlock = new Block(nextPosition()); + moduleFunctionConditionalConditionalStatementElseBlock = new Block(nextPosition()); + moduleFunctionConditionalConditionalStatement = + new ConditionalStatement(nextPosition(), moduleFunctionConditionalConditionalStatementCondition, + moduleFunctionConditionalConditionalStatementThenBlock, + moduleFunctionConditionalConditionalStatementElseBlock); + // add module function conditional conditional statement to module + // function conditional else block + moduleFunctionConditionalStatementElseBlock.addStatement(moduleFunctionConditionalConditionalStatement); + moduleFunctionConditionalConditionalReturnStatementParameter = new StringLiteral(nextPosition(), "return"); + moduleFunctionConditionalConditionalReturnStatement = + new ReturnStatement(nextPosition(), moduleFunctionConditionalConditionalReturnStatementParameter); + moduleFunctionConditionalConditionalConditionalStatementCondition = + new BooleanLiteral(new Position("TestFile", 37, 1), false); + moduleFunctionConditionalConditionalConditionalStatementThenBlock = new Block(nextPosition()); + moduleFunctionConditionalConditionalConditionalStatementElseBlock = new Block(nextPosition()); + moduleFunctionConditionalConditionalConditionalStatement = + new ConditionalStatement(nextPosition(), + moduleFunctionConditionalConditionalConditionalStatementCondition, + moduleFunctionConditionalConditionalConditionalStatementThenBlock, + moduleFunctionConditionalConditionalConditionalStatementElseBlock); + // add module function conditional conditional conditional statement to + // module function conditional conditional then block + moduleFunctionConditionalConditionalStatementThenBlock.addStatement(moduleFunctionConditionalConditionalConditionalStatement); + moduleFunctionConditionalConditionalConditionalThenReturnStatementParameter = + new StringLiteral(nextPosition(), "return"); + moduleFunctionConditionalConditionalConditionalThenReturnStatement = + new ReturnStatement(nextPosition(), + moduleFunctionConditionalConditionalConditionalThenReturnStatementParameter); + moduleFunctionConditionalConditionalConditionalElseReturnStatementParameter = + new StringLiteral(nextPosition(), "return"); + moduleFunctionConditionalConditionalConditionalElseReturnStatement = + new ReturnStatement(nextPosition(), + moduleFunctionConditionalConditionalConditionalElseReturnStatementParameter); + + // MODULE FUNCTION LOOP + moduleFunctionLoopCondition = new BooleanLiteral(nextPosition(), true); + moduleFunctionLoopBlock = new Block(nextPosition()); + moduleFunctionLoop = new WhileLoop(nextPosition(), moduleFunctionLoopCondition, moduleFunctionLoopBlock); + // add module function loop to module function + moduleFunctionBlock.addStatement(moduleFunctionLoop); + + moduleFunctionLoopReturnStatementParameter = new StringLiteral(nextPosition(), "return"); + moduleFunctionLoopReturnStatement = + new ReturnStatement(nextPosition(), moduleFunctionLoopReturnStatementParameter); + + moduleFunctionLoopLoopCondition = new BooleanLiteral(nextPosition(), true); + moduleFunctionLoopLoopBlock = new Block(nextPosition()); + moduleFunctionLoopLoop = + new WhileLoop(nextPosition(), moduleFunctionLoopLoopCondition, moduleFunctionLoopLoopBlock); + // ass module function loop loop to module function loop block + moduleFunctionLoopBlock.addStatement(moduleFunctionLoopLoop); + + moduleFunctionLoopLoopLoopCondition = new BooleanLiteral(nextPosition(), true); + moduleFunctionLoopLoopLoopBlock = new Block(nextPosition()); + moduleFunctionLoopLoopLoop = + new WhileLoop(nextPosition(), moduleFunctionLoopLoopLoopCondition, moduleFunctionLoopLoopLoopBlock); + // add module function loop loop loop to module function loop loop block + moduleFunctionLoopLoopBlock.addStatement(moduleFunctionLoopLoopLoop); + + moduleFunctionLoopLoopLoopReturnStatementParameter = new StringLiteral(nextPosition(), "return"); + moduleFunctionLoopLoopLoopReturnStatement = + new ReturnStatement(nextPosition(), moduleFunctionLoopLoopLoopReturnStatementParameter); + + } + + @Test + public void setUpASTTest() { + assertNotNull("setParentVisitor is null", setParentVisitor); + assertNotNull("controlFlowVisitor is null", controlFlowVisitor); + + // MODULE + assertNotNull("moduleDeclaration is null", moduleDeclaration); + assertNotNull("moduleBlock is null", moduleBlock); + assertNotNull("moduleImports is null", moduleImports); + assertNotNull("package is null", aPackage); + + // MODULE LOOP + assertNotNull("moduleLoopCondition is null", moduleLoopCondition); + assertNotNull("moduleLoopBlock is null", moduleLoopBlock); + assertNotNull("moduleLoop is null", moduleLoop); + assertNotNull("moduleLoopContinueStatement is null", moduleLoopContinueStatement); + assertNotNull("moduleLoopBreakStatement is null", moduleLoopBreakStatement); + assertNotNull("moduleLoopLoopCondition is null", moduleLoopLoopCondition); + assertNotNull("moduleLoopLoopBlock is null", moduleLoopLoopBlock); + + // MODULE LOOP LOOP + assertNotNull("moduleLoopLoop is null", moduleLoopLoop); + assertNotNull("moduleLoopLoopContinueStatement is null", moduleLoopLoopContinueStatement); + assertNotNull("moduleLoopLoopBreakStatement is null", moduleLoopLoopBreakStatement); + assertNotNull( + "moduleLoopLoopConditionalStatementCondition is null", + moduleLoopLoopConditionalStatementCondition); + assertNotNull( + "moduleLoopLoopConditionalStatementThenBlock is null", + moduleLoopLoopConditionalStatementThenBlock); + assertNotNull( + "moduleLoopLoopConditionalStatementElseBlock is null", + moduleLoopLoopConditionalStatementElseBlock); + assertNotNull("moduleLoopLoopConditionalStatement is null", moduleLoopLoopConditionalStatement); + assertNotNull( + "moduleLoopLoopThenConditionalStatementCondition is null", + moduleLoopLoopThenConditionalStatementCondition); + assertNotNull( + "moduleLoopLoopThenConditionalStatementThenBlock is null", + moduleLoopLoopThenConditionalStatementThenBlock); + assertNotNull( + "moduleLoopLoopThenConditionalStatementElseBlock is null", + moduleLoopLoopThenConditionalStatementElseBlock); + assertNotNull("moduleLoopLoopThenConditionalStatement is null", moduleLoopLoopThenConditionalStatement); + assertNotNull( + "moduleLoopLoopElseConditionalStatementCondition is null", + moduleLoopLoopElseConditionalStatementCondition); + assertNotNull( + "moduleLoopLoopElseConditionalStatementThenBlock is null", + moduleLoopLoopElseConditionalStatementThenBlock); + assertNotNull( + "moduleLoopLoopElseConditionalStatementElseBlock is null", + moduleLoopLoopElseConditionalStatementElseBlock); + assertNotNull("moduleLoopLoopElseConditionalStatement is null", moduleLoopLoopElseConditionalStatement); + + // MODULE LOOP CONDITIONAL STATEMENT + assertNotNull("moduleLoopConditionalStatementCondition is null", moduleLoopConditionalStatementCondition); + assertNotNull("moduleLoopConditionalStatementThenBlock is null", moduleLoopConditionalStatementThenBlock); + assertNotNull("moduleLoopConditionalStatementElseBlock is null", moduleLoopConditionalStatementElseBlock); + assertNotNull("moduleLoopConditionalStatement is null", moduleLoopConditionalStatement); + assertNotNull("moduleLoopConditionalContinueStatement is null", moduleLoopConditionalContinueStatement); + assertNotNull("moduleLoopConditionalBreakStatement is null", moduleLoopConditionalBreakStatement); + + // MODULE CONDITIONAL STATEMENT + assertNotNull("moduleConditionalStatementCondition is null", moduleConditionalStatementCondition); + assertNotNull("moduleConditionalStatementThenBlock is null", moduleConditionalStatementThenBlock); + assertNotNull("moduleConditionalStatementElseBlock is null", moduleConditionalStatementElseBlock); + assertNotNull("moduleConditionalStatement is null", moduleConditionalStatement); + + // MODULE STATETEMENTS + assertNotNull("moduleContinueStatement is null", moduleContinueStatement); + assertNotNull("moduleBreakStatement is null", moduleBreakStatement); + assertNotNull("moduleReturnStatementParameter is null", moduleReturnStatementParameter); + assertNotNull("moduleReturnStatement is null", moduleReturnStatement); + + // MODULE FUNCTION + assertNotNull("moduleFunctionBlock is null", moduleFunctionBlock); + assertNotNull("moduleFunctionParameter is null", moduleFunctionParameter); + assertNotNull("moduleFunctionDeclaration is null", moduleFunctionDeclaration); + assertNotNull("moduleFunctionReturnStatementParameter is null", moduleFunctionReturnStatementParameter); + assertNotNull("moduleFunctionReturnStatement is null", moduleFunctionReturnStatement); + + // MODULE FUNCTION PROCEDURE + assertNotNull("moduleFunctionProcedureBlock is null", moduleFunctionProcedureBlock); + assertNotNull("moduleFunctionProcedureParameter is null", moduleFunctionProcedureParameter); + assertNotNull("moduleFunctionProcedureDeclaration is null", moduleFunctionProcedureDeclaration); + assertNotNull( + "moduleFunctionProcedureReturnStatementParameter is null", + moduleFunctionProcedureReturnStatementParameter); + assertNotNull("moduleFunctionProcedureReturnStatement is null", moduleFunctionProcedureReturnStatement); + + // MODULE FUNCTION CONDITIONAL STATEMENT + assertNotNull( + "moduleFunctionConditionalStatementCondition is null", + moduleFunctionConditionalStatementCondition); + assertNotNull( + "moduleFunctionConditionalStatementThenBlock is null", + moduleFunctionConditionalStatementThenBlock); + assertNotNull( + "moduleFunctionConditionalStatementElseBlock is null", + moduleFunctionConditionalStatementElseBlock); + assertNotNull("moduleFunctionConditionalStatement is null", moduleFunctionConditionalStatement); + assertNotNull( + "moduleFunctionConditionalReturnThenStatementParameter is null", + moduleFunctionConditionalReturnThenStatementParameter); + assertNotNull( + "moduleFunctionConditionalReturnThenStatement is null", + moduleFunctionConditionalReturnThenStatement); + assertNotNull( + "moduleFunctionConditionalReturnElseStatementParameter is null", + moduleFunctionConditionalReturnElseStatementParameter); + assertNotNull( + "moduleFunctionConditionalReturnElseStatement is null", + moduleFunctionConditionalReturnElseStatement); + assertNotNull( + "moduleFunctionConditionalConditionalStatementCondition is null", + moduleFunctionConditionalConditionalStatementCondition); + assertNotNull( + "moduleFunctionConditionalConditionalStatementThenBlock is null", + moduleFunctionConditionalConditionalStatementThenBlock); + assertNotNull( + "moduleFunctionConditionalConditionalStatementElseBlock is null", + moduleFunctionConditionalConditionalStatementElseBlock); + assertNotNull( + "moduleFunctionConditionalConditionalStatement is null", + moduleFunctionConditionalConditionalStatement); + assertNotNull( + "moduleFunctionConditionalConditionalReturnStatementParameter is null", + moduleFunctionConditionalConditionalReturnStatementParameter); + assertNotNull( + "moduleFunctionConditionalConditionalReturnStatement is null", + moduleFunctionConditionalConditionalReturnStatement); + assertNotNull( + "moduleFunctionConditionalConditionalConditionalStatementCondition is null", + moduleFunctionConditionalConditionalConditionalStatementCondition); + assertNotNull( + "moduleFunctionConditionalConditionalConditionalStatementThenBlock is null", + moduleFunctionConditionalConditionalConditionalStatementThenBlock); + assertNotNull( + "moduleFunctionConditionalConditionalConditionalStatementElseBlock is null", + moduleFunctionConditionalConditionalConditionalStatementElseBlock); + assertNotNull( + "moduleFunctionConditionalConditionalConditionalStatement is null", + moduleFunctionConditionalConditionalConditionalStatement); + assertNotNull( + "moduleFunctionConditionalConditionalConditionalThenReturnStatementParameter is null", + moduleFunctionConditionalConditionalConditionalThenReturnStatementParameter); + assertNotNull( + "moduleFunctionConditionalConditionalConditionalThenReturnStatement is null", + moduleFunctionConditionalConditionalConditionalThenReturnStatement); + assertNotNull( + "moduleFunctionConditionalConditionalConditionalElseReturnStatementParameter is null", + moduleFunctionConditionalConditionalConditionalElseReturnStatementParameter); + assertNotNull( + "moduleFunctionConditionalConditionalConditionalElseReturnStatement is null", + moduleFunctionConditionalConditionalConditionalElseReturnStatement); + + // MODULE FUNCTION LOOP + assertNotNull("moduleFunctionLoopCondition is null", moduleFunctionLoopCondition); + assertNotNull("moduleFunctionLoopBlock is null", moduleFunctionLoopBlock); + assertNotNull("moduleFunctionLoop is null", moduleFunctionLoop); + assertNotNull("moduleFunctionLoopReturnStatementParameter is null", moduleFunctionLoopReturnStatementParameter); + assertNotNull("moduleFunctionLoopReturnStatement is null", moduleFunctionLoopReturnStatement); + assertNotNull("moduleFunctionLoopLoopCondition is null", moduleFunctionLoopLoopCondition); + assertNotNull("moduleFunctionLoopLoopBlock is null", moduleFunctionLoopLoopBlock); + assertNotNull("moduleFunctionLoopLoop is null", moduleFunctionLoopLoop); + assertNotNull("moduleFunctionLoopLoopLoopCondition is null", moduleFunctionLoopLoopLoopCondition); + assertNotNull("moduleFunctionLoopLoopLoopBlock is null", moduleFunctionLoopLoopLoopBlock); + assertNotNull("moduleFunctionLoopLoopLoop is null", moduleFunctionLoopLoopLoop); + assertNotNull( + "moduleFunctionLoopLoopLoopReturnStatementParameter is null", + moduleFunctionLoopLoopLoopReturnStatementParameter); + assertNotNull("moduleFunctionLoopLoopLoopReturnStatement is null", moduleFunctionLoopLoopLoopReturnStatement); + } + + /** Creates a continue statement inside of a while loop. */ + @Test + public void continueStatementTest01() { + // add previously defined statement to module loop + moduleLoopBlock.addStatement(moduleLoopContinueStatement); + + // control flow visitor should not complain about it, since the + // structure is + // valid + setParentVisitor.visit(aPackage); + controlFlowVisitor.visit(aPackage); + } + + /** Creates a continue statement inside of a nested while loop. */ + @Test + public void continueStatementTest02() { + // add previously defined statement to module loop + moduleLoopLoopBlock.addStatement(moduleLoopLoopContinueStatement); + + // control flow visitor should not complain about it, since the + // structure is + // valid + setParentVisitor.visit(aPackage); + controlFlowVisitor.visit(aPackage); + } + + /** Creates a continue statement inside of a conditional statement within a while loop */ + @Test + public void continueStatementTest03() { + // add statements to module loop conditional statement (then) + moduleLoopConditionalStatementThenBlock.addStatement(moduleLoopConditionalContinueStatement); + + // control flow visitor should not complain about it, since the + // structure is + // valid + setParentVisitor.visit(aPackage); + controlFlowVisitor.visit(aPackage); + } + + /** Create continue statement outside of a while loop */ + @Test(expected = InvalidControlFlowException.class) + public void continueStatementTest04() { + moduleBlock.addStatement(moduleContinueStatement); + + // control flow visitor should throw an exception now, since the + // structure is invalid + setParentVisitor.visit(aPackage); + controlFlowVisitor.visit(aPackage); + } + + /** Create break statement outside of a while loop */ + @Test(expected = InvalidControlFlowException.class) + public void breakStatementTest04() { + moduleBlock.addStatement(moduleBreakStatement); + + // control flow visitor should throw an exception now, since the + // structure is invalid + setParentVisitor.visit(aPackage); + controlFlowVisitor.visit(aPackage); + } + + /** Creates return statement outside of a function block */ + @Test(expected = InvalidControlFlowException.class) + public void returnStatementTest01() { + moduleBlock.addStatement(moduleReturnStatement); + + // control flow visitor should throw an exception now, since the + // structure is invalid + setParentVisitor.visit(aPackage); + controlFlowVisitor.visit(aPackage); + } + + /** Creates a return statement inside of a function block */ + @Test + public void returnStatementTest02() { + // add function to module + moduleBlock.addDeclaration(moduleFunctionDeclaration); + // ad a return statement to module function block + moduleFunctionBlock.addStatement(moduleFunctionReturnStatement); + + // control flow visitor should not complain about it, since the + // structure is + // valid + setParentVisitor.visit(aPackage); + controlFlowVisitor.visit(aPackage); + } + + /** Creates a return statement inside of a nested procedure declaration within a function block */ + @Test + public void returnStatementTest03() { + // add function to module + moduleBlock.addDeclaration(moduleFunctionDeclaration); + // add return statement to procedure + moduleFunctionProcedureBlock.addStatement(moduleFunctionProcedureReturnStatement); + // add procedure to function + moduleFunctionBlock.addDeclaration(moduleFunctionProcedureDeclaration); + + // start visitors and expect InvalidControlFlowException, since there's + // no guarantee, that the function always executes a return statement + boolean invalidControlFlow = false; + try { + setParentVisitor.visit(aPackage); + controlFlowVisitor.visit(aPackage); + } catch (InvalidControlFlowException icfe) { + invalidControlFlow = true; + } + // there should have been an InvalidControlFlowException during the + // visit ... + assertTrue("ReturnStatements needed inside the moduleFunction", invalidControlFlow); + + // now, add another return statement to the surrounding function + moduleFunctionBlock.addStatement(moduleFunctionReturnStatement); + + // control flow visitor should not complain anymore, since the + // structure is now valid + setParentVisitor.visit(aPackage); + controlFlowVisitor.visit(aPackage); + } + + /** Creates a return statement inside of a conditional statement within a function block */ + @Test + public void returnStatementTest04() { + // add function to module + moduleBlock.addDeclaration(moduleFunctionDeclaration); + // add module function conditional return statement to module function + // conditional statement + moduleFunctionConditionalStatementElseBlock.addStatement(moduleFunctionConditionalReturnElseStatement); + // add module function conditional statement to module function block + moduleFunctionBlock.addStatement(moduleFunctionConditionalStatement); + + // control flow visitor should definitely complain about it, since there + // is only a return statement in the else block, but neither in the then + // block, nor in the function itself. + boolean invalidControlFlow = false; + try { + setParentVisitor.visit(aPackage); + controlFlowVisitor.visit(aPackage); + } catch (InvalidControlFlowException icfe) { + invalidControlFlow = true; + } + // there should have been an InvalidControlFlowException during the + // visit ... + assertTrue("ReturnStatements does not need to be found inside both conditional branches", invalidControlFlow); + + // now, add another return statement to the surrounding function + moduleFunctionBlock.addStatement(moduleFunctionReturnStatement); + + // run visitors again + setParentVisitor.visit(aPackage); + controlFlowVisitor.visit(aPackage); + + // The controlFlowVisitor should not complain about anything anymore, + // since the structure is now valid. + } + + /** Creates a return statement inside of a conditional statement within a function block again, but resolve errors by + * adding another conditional return statement */ + @Test + public void returnStatementTest05() { + // add function to module + moduleBlock.addDeclaration(moduleFunctionDeclaration); + // add module function conditional return statement to module function + // conditional statement + moduleFunctionConditionalStatementElseBlock.addStatement(moduleFunctionConditionalReturnElseStatement); + // add module function conditional statement to module function block + moduleFunctionBlock.addStatement(moduleFunctionConditionalStatement); + + // control flow visitor should definitely complain about it, since there + // is only a return statement in the else block, but neither in the then + // block, nor in the function itself. + boolean invalidControlFlow = false; + try { + setParentVisitor.visit(aPackage); + controlFlowVisitor.visit(aPackage); + } catch (InvalidControlFlowException icfe) { + invalidControlFlow = true; + } + // there should have been an InvalidControlFlowException during the + // visit ... + assertTrue("ReturnStatements does not need to be found inside both conditional branches", invalidControlFlow); + + // add return statement to conditional statements then block + moduleFunctionConditionalStatementThenBlock.addStatement(moduleFunctionConditionalReturnThenStatement); + + // run visitors again + setParentVisitor.visit(aPackage); + controlFlowVisitor.visit(aPackage); + + // The controlFlowVisitor should not complain about anything, since the + // structure is valid. + } + + /** Creates return statement inside of a 3-times nested conditional statement within a function block */ + @Test + public void returnStatementTest06() { + // add function to module + moduleBlock.addDeclaration(moduleFunctionDeclaration); + // add module function conditional conditional conditional return + // statement to module function conditional conditional conditional then + // block + moduleFunctionConditionalConditionalConditionalStatementElseBlock.addStatement(moduleFunctionConditionalConditionalConditionalElseReturnStatement); + + // control flow should be invalid now, since there's no global return + // statement + boolean invalidControlFlow = false; + try { + setParentVisitor.visit(aPackage); + controlFlowVisitor.visit(aPackage); + } catch (InvalidControlFlowException icfe) { + invalidControlFlow = true; + } + // there should have been an InvalidControlFlowException during the + // visit ... + assertTrue("ReturnStatements does not need to be found inside both conditional branches", invalidControlFlow); + + // resolve these errors by adding another return statement to each + // conditional branch + moduleFunctionConditionalConditionalConditionalStatementThenBlock.addStatement(moduleFunctionConditionalConditionalConditionalThenReturnStatement); + moduleFunctionConditionalConditionalStatementElseBlock.addStatement(moduleFunctionConditionalConditionalReturnStatement); + moduleFunctionConditionalStatementThenBlock.addStatement(moduleFunctionConditionalReturnThenStatement); + + // everything should be just fine now + setParentVisitor.visit(aPackage); + controlFlowVisitor.visit(aPackage); + } + + /** Creates return statement inside a while loop within a function block */ + @Test + public void returnStatementTest07() { + // add function to module + moduleBlock.addDeclaration(moduleFunctionDeclaration); + // add module function loop return statement to module function loop + // block + moduleFunctionLoopBlock.addStatement(moduleFunctionLoopReturnStatement); + + // control flow should be invalid now, since there's no global return + // statement + boolean invalidControlFlow = false; + try { + setParentVisitor.visit(aPackage); + controlFlowVisitor.visit(aPackage); + } catch (InvalidControlFlowException icfe) { + invalidControlFlow = true; + } + // there should have been an InvalidControlFlowException during the + // visit ... + assertTrue("ReturnStatements does not need to be found inside both conditional branches", invalidControlFlow); + + // resolve errors by adding a return statement to module function + moduleFunctionBlock.addStatement(moduleFunctionReturnStatement); + + // everything should be just fine now + setParentVisitor.visit(aPackage); + controlFlowVisitor.visit(aPackage); + } + + /** Create return statement inside of a 3-times nested while loop within a function block */ + @Test + public void returnStatementTest08() { + // add function to module + moduleBlock.addDeclaration(moduleFunctionDeclaration); + // add module function loop loop loop return statement to module + // function loop loop loop block + moduleFunctionLoopLoopLoopBlock.addStatement(moduleFunctionLoopLoopLoopReturnStatement); + + // control flow should be invalid now, since there's no global return + // statement + boolean invalidControlFlow = false; + try { + setParentVisitor.visit(aPackage); + controlFlowVisitor.visit(aPackage); + } catch (InvalidControlFlowException icfe) { + invalidControlFlow = true; + } + // there should have been an InvalidControlFlowException during the + // visit ... + assertTrue("ReturnStatements does not need to be found inside both conditional branches", invalidControlFlow); + + // resolve errors by adding a return statement to module function + moduleFunctionBlock.addStatement(moduleFunctionReturnStatement); + + // everything should be just fine now + setParentVisitor.visit(aPackage); + controlFlowVisitor.visit(aPackage); + } + + /** Creates a conditional statement inside a while loop */ + @Test + public void conditionalStatementTest01() { + moduleLoopBlock.addStatement(moduleLoopConditionalStatement); + + // control flow visitor should not complain about it, since the + // structure is valid + setParentVisitor.visit(aPackage); + controlFlowVisitor.visit(aPackage); + } + + /** Creates a conditional statement inside a conditional statements then block */ + @Test + public void conditionalStatementTest02() { + moduleConditionalStatementThenBlock.addStatement(moduleLoopConditionalStatement); + + // control flow visitor should not complain about it, since the + // structure is valid + setParentVisitor.visit(aPackage); + controlFlowVisitor.visit(aPackage); + } + + /** Creates a conditional statement inside a conditional statements else block */ + @Test + public void conditionalStatementTest03() { + moduleConditionalStatementElseBlock.addStatement(moduleLoopConditionalStatement); + + // control flow visitor should not complain about it, since the + // structure is valid + setParentVisitor.visit(aPackage); + controlFlowVisitor.visit(aPackage); + } + + /** Creates a conditional statement inside of a nested while loop */ + @Test + public void conditionalStatementTest04() { + moduleLoopLoopBlock.addStatement(moduleLoopLoopConditionalStatement); + + // everything should be just fine + setParentVisitor.visit(aPackage); + controlFlowVisitor.visit(aPackage); + } + + /** Creates conditional statement inside of a nested conditional statement within a while loop */ + @Test + public void conditionalStatementTest05() { + // add a conditional statement inside a nested while loop + moduleLoopLoopBlock.addStatement(moduleLoopLoopConditionalStatement); + // add some more conditional statements to the one above + moduleLoopLoopConditionalStatementThenBlock.addStatement(moduleLoopLoopThenConditionalStatement); + moduleLoopLoopConditionalStatementElseBlock.addStatement(moduleLoopLoopElseConditionalStatement); + + // everything should be just fine + setParentVisitor.visit(aPackage); + controlFlowVisitor.visit(aPackage); + } +} diff --git a/src/test/java/de/uni/bremen/monty/moco/ast/DeclarationTest.java b/src/test/java/de/uni/bremen/monty/moco/ast/DeclarationTest.java new file mode 100644 index 0000000..9719b72 --- /dev/null +++ b/src/test/java/de/uni/bremen/monty/moco/ast/DeclarationTest.java @@ -0,0 +1,971 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.ast; + +import de.uni.bremen.monty.moco.ast.declaration.*; +import de.uni.bremen.monty.moco.ast.expression.Expression; +import de.uni.bremen.monty.moco.ast.expression.FunctionCall; +import de.uni.bremen.monty.moco.ast.expression.MemberAccess; +import de.uni.bremen.monty.moco.ast.expression.VariableAccess; +import de.uni.bremen.monty.moco.ast.expression.literal.BooleanLiteral; +import de.uni.bremen.monty.moco.ast.expression.literal.StringLiteral; +import de.uni.bremen.monty.moco.ast.statement.*; +import de.uni.bremen.monty.moco.exception.InvalidPlaceToDeclareException; +import de.uni.bremen.monty.moco.exception.RedeclarationException; +import de.uni.bremen.monty.moco.visitor.DeclarationVisitor; +import de.uni.bremen.monty.moco.visitor.SetParentVisitor; +import org.junit.Before; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; + +import static org.junit.Assert.*; + +/** Test the DeclarationVisitor. + *

+ * Note the following limitations! This does not test:
+ * - Overriding
+ * - Overloading
+ * - Inheritance with multiple super-classes
+ * - Access-modifiers */ +public class DeclarationTest { + + private SetParentVisitor setParentVisitor; + private DeclarationVisitor declarationVisitor; + private int lineCounter = 0; + + // module + private Import moduleImport01; + private Import moduleImport02; + private List moduleImports; + private Block moduleBlock; + private Package aPackage; + private ModuleDeclaration moduleDeclaration; + + // module class + private Block classBlock; + private ClassDeclaration classDeclaration; + private VariableDeclaration classVariableDeclaration; + + private Block classFunctionBlock; + private List classFunctionParams; + private FunctionDeclaration classFunctionDeclaration; + + private Block classProcedureBlock; + private List classProcedureParams; + private ProcedureDeclaration classProcedureDeclaration; + + // module class extends + private Block extendedClassBlock; + private ClassDeclaration extendedClassDeclaration; + + // module function + private Block moduleFunctionBlock; + private VariableDeclaration moduleFunctionParamsVariable01; + private VariableDeclaration moduleFunctionParamsVariable02; + private List moduleFunctionParams; + private FunctionDeclaration moduleFunctionDeclaration; + private VariableDeclaration moduleFunctionVariableDeclaration; + private Block moduleFunctionFunctionBlock; + private List moduleFunctionFunctionParams; + private FunctionDeclaration moduleFunctionFunctionDeclaration; + private Block moduleFunctionProcedureBlock; + private List moduleFunctionProcedureParams; + private ProcedureDeclaration moduleFunctionProcedureDeclaration; + + // module procedure + private Block moduleProcedureBlock; + private VariableDeclaration moduleProcedureParamsVariable01; + private VariableDeclaration moduleProcedureParamsVariable02; + private List moduleProcedureParams; + private ProcedureDeclaration moduleProcedureDeclaration; + private VariableDeclaration moduleProcedureVariableDeclaration; + private Block moduleProcedureFunctionBlock; + private List moduleProcedureFunctionParams; + private FunctionDeclaration moduleProcedureFunctionDeclaration; + private Block moduleProcedureProcedureBlock; + private List moduleProcedureProcedureParams; + private ProcedureDeclaration moduleProcedureProcedureDeclaration; + + // module variable + private VariableDeclaration moduleVariableDeclaration; + + // module loop + private Expression moduleLoopCondition; + private Block moduleLoopBlock; + private WhileLoop moduleLoop; + private ContinueStatement moduleLoopContinueStatement; + private BreakStatement moduleLoopBreakStatement; + + // module conditional + private Expression moduleConditionalStatementCondition; + private ConditionalStatement moduleConditionalStatement; + private Block moduleConditionalStatementThenBlock; + private Block moduleConditionalStatementElseBlock; + + // module function return statement + private Expression moduleReturnStatementParameter; + private ReturnStatement moduleReturnStatement; + + // module procedure call + private Expression moduleProcedureCallFunctionCallParameter01; + private Expression moduleProcedureCallFunctionCallParameter02; + private List moduleProcedureCallFunctionCallParameters; + private FunctionCall moduleProcedureCall; + + // module assignment with function call as left side + private VariableDeclaration moduleAssignmentMemberAccessVariableDeclaration; + private VariableAccess moduleAssignmentMemberAccessVariableAccessClass; + private VariableAccess moduleAssignmentMemberAccessVariableAccessVariable; + private MemberAccess moduleAssignmentMemberAccess; + private Expression moduleAssignmentFunctionCallParameter01; + private Expression moduleAssignmentFunctionCallParameter02; + private List moduleAssignmentFunctionCallParameters; + private FunctionCall moduleAssignmentFunctionCall; + private Assignment moduleAssignment; + + // invalid modul + private Import invalidModuleImport01; + private Import invalidModuleImport02; + private List invalidModuleImports; + private Block invalidModuleBlock; + private ModuleDeclaration invalidModuleDeclaration; + + // invalid class + private List invalidClassSuperClasses; + private Block invalidClassBlock; + private ClassDeclaration invalidClassDeclaration; + + private Position buildPosition() { + return new Position("declarationTest", lineCounter++, 0); + } + + @Before + public void setUpAST() { + lineCounter = 0; + setParentVisitor = new SetParentVisitor(); + setParentVisitor.setStopOnFirstError(true); + declarationVisitor = new DeclarationVisitor(); + declarationVisitor.setStopOnFirstError(true); + + // module + moduleImport01 = new Import(buildPosition(), new ResolvableIdentifier("Dummy")); + moduleImport02 = new Import(buildPosition(), new ResolvableIdentifier("Dummy")); + moduleImports = new ArrayList(); + moduleBlock = new Block(buildPosition()); + aPackage = new Package(new Identifier("")); + moduleDeclaration = + new ModuleDeclaration(buildPosition(), new Identifier("moduleDeclaration"), moduleBlock, moduleImports); + aPackage.addModule(moduleDeclaration); + + // module class + classBlock = new Block(buildPosition()); + List classDeclSuperClasses = new ArrayList(); + classDeclaration = + new ClassDeclaration(buildPosition(), new Identifier("classDeclaration"), classDeclSuperClasses, + classBlock); + classVariableDeclaration = + new VariableDeclaration(buildPosition(), new Identifier("classVariableDeclaration"), + new ResolvableIdentifier("String"), VariableDeclaration.DeclarationType.ATTRIBUTE); + + classFunctionBlock = new Block(buildPosition()); + classFunctionParams = new ArrayList(); + classFunctionDeclaration = + new FunctionDeclaration(buildPosition(), new Identifier("classFunctionDeclaration"), + classFunctionBlock, classFunctionParams, new ResolvableIdentifier("String")); + + classProcedureBlock = new Block(buildPosition()); + classProcedureParams = new ArrayList(); + classProcedureDeclaration = + new ProcedureDeclaration(buildPosition(), new Identifier("classProcedureDeclaration"), + classProcedureBlock, classProcedureParams); + + // module class extended + extendedClassBlock = new Block(buildPosition()); + List extendedClassDeclSuperClasses = new ArrayList(); + extendedClassDeclSuperClasses.add(new ResolvableIdentifier("classDeclaration")); + extendedClassDeclaration = + new ClassDeclaration(buildPosition(), new Identifier("extendedClassDeclaration"), + extendedClassDeclSuperClasses, extendedClassBlock); + + // module function + moduleFunctionBlock = new Block(buildPosition()); + moduleFunctionParamsVariable01 = + new VariableDeclaration(buildPosition(), new Identifier("moduleFunctionParamsVariable01"), + new ResolvableIdentifier("String"), VariableDeclaration.DeclarationType.PARAMETER); + moduleFunctionParamsVariable02 = + new VariableDeclaration(buildPosition(), new Identifier("moduleFunctionParamsVariable02"), + new ResolvableIdentifier("String"), VariableDeclaration.DeclarationType.PARAMETER); + moduleFunctionParams = new ArrayList(); + moduleFunctionDeclaration = + new FunctionDeclaration(buildPosition(), new Identifier("moduleFunctionDeclaration"), + moduleFunctionBlock, moduleFunctionParams, new ResolvableIdentifier("String")); + moduleFunctionVariableDeclaration = + new VariableDeclaration(buildPosition(), new Identifier("moduleFunctionVariableDeclaration"), + new ResolvableIdentifier("String"), VariableDeclaration.DeclarationType.VARIABLE); + moduleFunctionFunctionBlock = new Block(buildPosition()); + moduleFunctionFunctionParams = new ArrayList(); + moduleFunctionFunctionDeclaration = + new FunctionDeclaration(buildPosition(), new Identifier("moduleFunctionFunctionDeclaration"), + moduleFunctionFunctionBlock, moduleFunctionFunctionParams, new ResolvableIdentifier("String")); + moduleFunctionProcedureBlock = new Block(buildPosition()); + moduleFunctionProcedureParams = new ArrayList(); + moduleFunctionProcedureDeclaration = + new ProcedureDeclaration(buildPosition(), new Identifier("moduleFunctionProcedureDeclaration"), + moduleFunctionProcedureBlock, moduleFunctionProcedureParams); + + // module procedure + moduleProcedureBlock = new Block(buildPosition()); + moduleProcedureParamsVariable01 = + new VariableDeclaration(buildPosition(), new Identifier("moduleProcedureParamsVariable01"), + new ResolvableIdentifier("String"), VariableDeclaration.DeclarationType.PARAMETER); + moduleProcedureParamsVariable02 = + new VariableDeclaration(buildPosition(), new Identifier("moduleProcedureParamsVariable02"), + new ResolvableIdentifier("String"), VariableDeclaration.DeclarationType.PARAMETER); + moduleProcedureParams = new ArrayList(); + moduleProcedureDeclaration = + new ProcedureDeclaration(buildPosition(), new Identifier("moduleProcedureDeclaration"), + moduleProcedureBlock, moduleProcedureParams); + moduleProcedureVariableDeclaration = + new VariableDeclaration(buildPosition(), new Identifier("moduleProcedureVariableDeclaration"), + new ResolvableIdentifier("String"), VariableDeclaration.DeclarationType.VARIABLE); + moduleProcedureFunctionBlock = new Block(buildPosition()); + moduleProcedureFunctionParams = new ArrayList(); + moduleProcedureFunctionDeclaration = + new FunctionDeclaration(buildPosition(), new Identifier("moduleProcedureFunctionDeclaration"), + moduleProcedureFunctionBlock, moduleProcedureFunctionParams, new ResolvableIdentifier("String")); + moduleProcedureProcedureBlock = new Block(buildPosition()); + moduleProcedureProcedureParams = new ArrayList(); + moduleProcedureProcedureDeclaration = + new ProcedureDeclaration(buildPosition(), new Identifier("moduleProcedureProcedureDeclaration"), + moduleProcedureProcedureBlock, moduleProcedureProcedureParams); + + // module variable + moduleVariableDeclaration = + new VariableDeclaration(buildPosition(), new Identifier("moduleVariableDeclaration"), + new ResolvableIdentifier("String"), VariableDeclaration.DeclarationType.VARIABLE); + + // module loop + moduleLoopCondition = new BooleanLiteral(buildPosition(), true); + moduleLoopBlock = new Block(buildPosition()); + moduleLoop = new WhileLoop(buildPosition(), moduleLoopCondition, moduleLoopBlock); + moduleLoopContinueStatement = new ContinueStatement(buildPosition()); + moduleLoopBreakStatement = new BreakStatement(buildPosition()); + + // module conditional + moduleConditionalStatementCondition = new BooleanLiteral(buildPosition(), true); + moduleConditionalStatementThenBlock = new Block(buildPosition()); + moduleConditionalStatementElseBlock = new Block(buildPosition()); + moduleConditionalStatement = + new ConditionalStatement(buildPosition(), moduleConditionalStatementCondition, + moduleConditionalStatementThenBlock, moduleConditionalStatementElseBlock); + + // module function return statement + moduleReturnStatementParameter = new StringLiteral(buildPosition(), "42"); + moduleReturnStatement = new ReturnStatement(buildPosition(), moduleReturnStatementParameter); + + // module procedure call + moduleProcedureCallFunctionCallParameter01 = new StringLiteral(buildPosition(), "42"); + moduleProcedureCallFunctionCallParameter02 = new StringLiteral(buildPosition(), "42"); + moduleProcedureCallFunctionCallParameters = new ArrayList(); + + moduleProcedureCall = + new FunctionCall(buildPosition(), new ResolvableIdentifier("moduleProcedureDeclaration"), + moduleProcedureCallFunctionCallParameters); + + // module assignment with function call as left side + moduleAssignmentMemberAccessVariableDeclaration = + new VariableDeclaration(buildPosition(), new Identifier( + "moduleAssignmentMemberAccessVariableDeclaration"), + new ResolvableIdentifier("classDeclaration"), VariableDeclaration.DeclarationType.VARIABLE); + moduleAssignmentMemberAccessVariableAccessClass = + new VariableAccess(buildPosition(), new ResolvableIdentifier( + "moduleAssignmentMemberAccessVariableDeclaration")); + moduleAssignmentMemberAccessVariableAccessVariable = + new VariableAccess(buildPosition(), new ResolvableIdentifier("classVariableDeclaration")); + moduleAssignmentMemberAccess = + new MemberAccess(buildPosition(), moduleAssignmentMemberAccessVariableAccessClass, + moduleAssignmentMemberAccessVariableAccessVariable); + moduleAssignmentFunctionCallParameter01 = new StringLiteral(buildPosition(), "42"); + moduleAssignmentFunctionCallParameter02 = new StringLiteral(buildPosition(), "42"); + moduleAssignmentFunctionCallParameters = new ArrayList(); + moduleAssignmentFunctionCall = + new FunctionCall(buildPosition(), new ResolvableIdentifier("moduleFunctionDeclaration"), + moduleAssignmentFunctionCallParameters); + moduleAssignment = new Assignment(buildPosition(), moduleAssignmentMemberAccess, moduleAssignmentFunctionCall); + + // invalid modul + invalidModuleImport01 = new Import(buildPosition(), new ResolvableIdentifier("Dummy")); + invalidModuleImport02 = new Import(buildPosition(), new ResolvableIdentifier("Dummy")); + invalidModuleImports = new ArrayList(); + invalidModuleBlock = new Block(buildPosition()); + invalidModuleDeclaration = + new ModuleDeclaration(buildPosition(), new Identifier("invalidModuleDeclaration"), invalidModuleBlock, + invalidModuleImports); + + // invalid class + invalidClassBlock = new Block(buildPosition()); + invalidClassSuperClasses = new ArrayList(); + invalidClassDeclaration = + new ClassDeclaration(buildPosition(), new Identifier("invalidClass"), invalidClassSuperClasses, + invalidClassBlock); + + } + + private void fillASTModule() { + moduleImports.add(moduleImport01); + moduleImports.add(moduleImport02); + } + + private void fillASTClass() { + moduleBlock.addDeclaration(classDeclaration); + } + + private void fillASTClassVariable() { + classBlock.addDeclaration(classVariableDeclaration); + } + + private void fillASTClassFunction() { + classBlock.addDeclaration(classFunctionDeclaration); + } + + private void fillASTClassProcedure() { + classBlock.addDeclaration(classProcedureDeclaration); + } + + private void fillASTExtendedClass() { + moduleBlock.addDeclaration(extendedClassDeclaration); + } + + private void fillASTModuleFunction() { + moduleBlock.addDeclaration(moduleFunctionDeclaration); + } + + private void fillASTModuleFunctionVariable() { + moduleFunctionParams.add(moduleFunctionParamsVariable01); + moduleFunctionParams.add(moduleFunctionParamsVariable02); + moduleFunctionBlock.addDeclaration(moduleFunctionVariableDeclaration); + } + + private void fillASTModuleFunctionFunction() { + moduleFunctionBlock.addDeclaration(moduleFunctionFunctionDeclaration); + } + + private void fillASTModuleFunctionProcedure() { + moduleFunctionBlock.addDeclaration(moduleFunctionProcedureDeclaration); + } + + private void fillASTModuleProcedure() { + moduleBlock.addDeclaration(moduleProcedureDeclaration); + } + + private void fillASTModuleProcedureVariable() { + moduleProcedureParams.add(moduleProcedureParamsVariable01); + moduleProcedureParams.add(moduleProcedureParamsVariable02); + moduleProcedureBlock.addDeclaration(moduleProcedureVariableDeclaration); + } + + private void fillASTModuleProcedureFunction() { + moduleProcedureBlock.addDeclaration(moduleProcedureFunctionDeclaration); + } + + private void fillASTModuleProcedureProcedure() { + moduleProcedureBlock.addDeclaration(moduleProcedureProcedureDeclaration); + } + + private void fillASTModuleVariable() { + moduleBlock.addDeclaration(moduleVariableDeclaration); + } + + private void fillASTModuleStatements() { + moduleLoopBlock.addStatement(moduleLoopContinueStatement); + moduleLoopBlock.addStatement(moduleLoopBreakStatement); + + moduleBlock.addDeclaration(moduleAssignmentMemberAccessVariableDeclaration); + moduleBlock.addStatement(moduleLoop); + moduleBlock.addStatement(moduleConditionalStatement); + moduleBlock.addStatement(moduleReturnStatement); + + moduleProcedureCallFunctionCallParameters.add(moduleProcedureCallFunctionCallParameter01); + moduleProcedureCallFunctionCallParameters.add(moduleProcedureCallFunctionCallParameter02); + moduleBlock.addStatement(moduleProcedureCall); + + moduleAssignmentFunctionCallParameters.add(moduleAssignmentFunctionCallParameter01); + moduleAssignmentFunctionCallParameters.add(moduleAssignmentFunctionCallParameter02); + moduleBlock.addStatement(moduleAssignment); + } + + private void fillASTInvalidModule() { + invalidModuleImports.add(invalidModuleImport01); + invalidModuleImports.add(invalidModuleImport02); + } + + @Test + public void setUpASTTest() { + assertNotNull("setParentVisitor is null", setParentVisitor); + assertNotNull("declarationVisitor is null", declarationVisitor); + + assertNotNull("moduleImport01 is null", moduleImport01); + assertNotNull("moduleImport02 is null", moduleImport02); + assertNotNull("moduleImports is null", moduleImports); + assertNotNull("moduleBlock is null", moduleBlock); + assertNotNull("moduleDeclaration is null", moduleDeclaration); + assertNotNull("package is null", aPackage); + + assertNotNull("classDeclarationDeclarations is null", classBlock); + assertNotNull("classDeclaration is null", classDeclaration); + assertNotNull("classVariableDeclaration is null", classVariableDeclaration); + + assertNotNull("classFunctionBlock is null", classFunctionBlock); + assertNotNull("classFunctionParams is null", classFunctionParams); + assertNotNull("classFunctionDeclaration is null", classFunctionDeclaration); + + assertNotNull("classProcedureBlock is null", classProcedureBlock); + assertNotNull("classProcedureParams is null", classProcedureParams); + assertNotNull("classProcedureDeclaration is null", classProcedureDeclaration); + + assertNotNull("extendedClassDeclarationDeclarations is null", extendedClassBlock); + assertNotNull("extendedClassDeclaration is null", extendedClassDeclaration); + + assertNotNull("moduleFunctionBlock is null", moduleFunctionBlock); + assertNotNull("moduleFunctionParamsVariable01 is null", moduleFunctionParamsVariable01); + assertNotNull("moduleFunctionParamsVariable02 is null", moduleFunctionParamsVariable02); + assertNotNull("moduleFunctionParams is null", moduleFunctionParams); + assertNotNull("moduleFunctionDeclaration is null", moduleFunctionDeclaration); + assertNotNull("moduleFunctionVariableDeclaration is null", moduleFunctionVariableDeclaration); + assertNotNull("moduleFunctionFunctionBlock is null", moduleFunctionFunctionBlock); + assertNotNull("moduleFunctionFunctionParams is null", moduleFunctionFunctionParams); + assertNotNull("moduleFunctionFunctionDeclaration is null", moduleFunctionFunctionDeclaration); + assertNotNull("moduleFunctionProcedureBlock is null", moduleFunctionProcedureBlock); + assertNotNull("moduleFunctionProcedureParams is null", moduleFunctionProcedureParams); + assertNotNull("moduleFunctionProcedureDeclaration is null", moduleFunctionProcedureDeclaration); + + assertNotNull("moduleProcedureBlock is null", moduleProcedureBlock); + assertNotNull("moduleProcedureParamsVariable01 is null", moduleProcedureParamsVariable01); + assertNotNull("moduleProcedureParamsVariable02 is null", moduleProcedureParamsVariable02); + assertNotNull("moduleProcedureParams is null", moduleProcedureParams); + assertNotNull("moduleProcedureDeclaration is null", moduleProcedureDeclaration); + assertNotNull("moduleProcedureVariableDeclaration is null", moduleProcedureVariableDeclaration); + assertNotNull("moduleProcedureFunctionBlock is null", moduleProcedureFunctionBlock); + assertNotNull("moduleProcedureFunctionParams is null", moduleProcedureFunctionParams); + assertNotNull("moduleProcedureFunctionDeclaration is null", moduleProcedureFunctionDeclaration); + assertNotNull("moduleProcedureProcedureBlock is null", moduleProcedureProcedureBlock); + assertNotNull("moduleProcedureProcedureParams is null", moduleProcedureProcedureParams); + assertNotNull("moduleProcedureProcedureDeclaration is null", moduleProcedureProcedureDeclaration); + + assertNotNull("moduleVariableDeclaration is null", moduleVariableDeclaration); + + assertNotNull("moduleLoopCondition is null", moduleLoopCondition); + assertNotNull("moduleLoopBlock is null", moduleLoopBlock); + assertNotNull("moduleLoop is null", moduleLoop); + assertNotNull("moduleLoopContinueStatement is null", moduleLoopContinueStatement); + assertNotNull("moduleLoopBreakStatement is null", moduleLoopBreakStatement); + + assertNotNull("moduleConditionalStatementCondition is null", moduleConditionalStatementCondition); + assertNotNull("moduleConditionalStatement is null", moduleConditionalStatement); + assertNotNull("moduleConditionalStatementThenBlock is null", moduleConditionalStatementThenBlock); + assertNotNull("moduleConditionalStatementElseBlock is null", moduleConditionalStatementElseBlock); + + assertNotNull("moduleReturnStatementParameter is null", moduleReturnStatementParameter); + assertNotNull("moduleReturnStatement is null", moduleReturnStatement); + + assertNotNull("moduleProcedureCallFunctionCallParameter01 is null", moduleProcedureCallFunctionCallParameter01); + assertNotNull("moduleProcedureCallFunctionCallParameter02 is null", moduleProcedureCallFunctionCallParameter02); + assertNotNull("moduleProcedureCallFunctionCallParameters is null", moduleProcedureCallFunctionCallParameters); + assertNotNull("moduleProcedureCall is null", moduleProcedureCall); + + assertNotNull( + "moduleAssignmentMemberAccessVariableDeclaration is null", + moduleAssignmentMemberAccessVariableDeclaration); + assertNotNull( + "moduleAssignmentMemberAccessVariableAccessClass is null", + moduleAssignmentMemberAccessVariableAccessClass); + assertNotNull( + "moduleAssignmentMemberAccessVariableAccessVariable is null", + moduleAssignmentMemberAccessVariableAccessVariable); + assertNotNull("moduleAssignmentMemberAccess is null", moduleAssignmentMemberAccess); + assertNotNull("moduleAssignmentFunctionCallParameter01 is null", moduleAssignmentFunctionCallParameter01); + assertNotNull("moduleAssignmentFunctionCallParameter02 is null", moduleAssignmentFunctionCallParameter02); + assertNotNull("moduleAssignmentFunctionCallParameters is null", moduleAssignmentFunctionCallParameters); + assertNotNull("moduleAssignmentFunctionCall is null", moduleAssignmentFunctionCall); + assertNotNull("moduleAssignment is null", moduleAssignment); + + assertNotNull("invalidModuleImport01 is null", invalidModuleImport01); + assertNotNull("invalidModuleImport02 is null", invalidModuleImport02); + assertNotNull("invalidModuleImports is null", invalidModuleImports); + assertNotNull("invalidModuleBlock is null", invalidModuleBlock); + assertNotNull("invalidModuleDeclaration is null", invalidModuleDeclaration); + + assertNotNull("invalidClassSuperClasses is null", invalidClassSuperClasses); + assertNotNull("invalidClassDeclarations is null", invalidClassBlock); + assertNotNull("invalidClassDeclaration is null", invalidClassDeclaration); + } + + // DECLARATION AND SCOPE + + // ONE CASE TO TEST 'EM ALL + + @Test + public void nodeInteractionTest() { + // Es muss einen Test geben, in dem alle AST-Nodes vorkommen. Nach + // Durchlauf des DeclarationVisitors müssen alle AST-Nodes einen Scope + // haben. Jede AST-Node, die mehr als ein Kind haben kann, muss für + // jeden möglichen Kind-Typ mehr als 1 Kind besitzen. (z.B. Modulblock + // mit 2 Statements und 2 Declarations) + + fillASTModule(); + fillASTExtendedClass(); + fillASTClass(); + fillASTClassVariable(); + fillASTClassFunction(); + fillASTClassProcedure(); + fillASTModuleFunction(); + fillASTModuleFunctionVariable(); + fillASTModuleFunctionFunction(); + fillASTModuleFunctionProcedure(); + fillASTModuleProcedure(); + fillASTModuleProcedureVariable(); + fillASTModuleProcedureFunction(); + fillASTModuleProcedureProcedure(); + fillASTModuleVariable(); + fillASTModuleStatements(); + + setParentVisitor.visit(aPackage); + declarationVisitor.visit(aPackage); + + ASTNode[] allASTNodes = + new ASTNode[] { moduleImport01, moduleImport02, moduleBlock, aPackage, classDeclaration, + classVariableDeclaration, classFunctionBlock, classFunctionDeclaration, classProcedureBlock, + classProcedureDeclaration, extendedClassDeclaration, moduleFunctionBlock, + moduleFunctionParamsVariable01, moduleFunctionParamsVariable02, moduleFunctionDeclaration, + moduleFunctionVariableDeclaration, moduleFunctionFunctionBlock, + moduleFunctionFunctionDeclaration, moduleFunctionProcedureBlock, + moduleFunctionProcedureDeclaration, moduleProcedureBlock, moduleProcedureParamsVariable01, + moduleProcedureParamsVariable02, moduleProcedureDeclaration, + moduleProcedureVariableDeclaration, moduleProcedureFunctionBlock, + moduleProcedureFunctionDeclaration, moduleProcedureProcedureBlock, + moduleProcedureProcedureDeclaration, moduleVariableDeclaration, moduleLoopCondition, + moduleLoopBlock, moduleLoop, moduleLoopContinueStatement, moduleLoopBreakStatement, + moduleConditionalStatementCondition, moduleConditionalStatement, + moduleConditionalStatementThenBlock, moduleConditionalStatementElseBlock, + moduleReturnStatementParameter, moduleReturnStatement, + moduleProcedureCallFunctionCallParameter01, moduleProcedureCallFunctionCallParameter02, + moduleProcedureCall, moduleAssignmentMemberAccessVariableDeclaration, + moduleAssignmentMemberAccessVariableAccessClass, + moduleAssignmentMemberAccessVariableAccessVariable, moduleAssignmentMemberAccess, + moduleAssignmentFunctionCallParameter01, moduleAssignmentFunctionCallParameter02, + moduleAssignmentFunctionCall, moduleAssignment, moduleDeclaration }; + + for (ASTNode node : allASTNodes) { + assertNotNull("Scope not set for class: " + node.getClass().getSimpleName(), node.getScope()); + + if (node instanceof ClassDeclaration) { + assertTrue( + "Scope for ClassDeclaration is no ClassScope: " + node.getClass().getSimpleName(), + node.getScope() instanceof ClassScope); + } + + if (!(node instanceof Package)) { + assertNotNull("Parent not set for class: " + node.getClass().getSimpleName(), node.getParentNode()); + } else { + assertNull( + "Parent set for class (but should be null): " + node.getClass().getSimpleName(), + node.getParentNode()); + } + } + } + + // Module Declaration Tests + + @Test + public void moduleTestModuleDeclaration() { + fillASTModule(); + + // there is no way of validating the correct declaration but to fail + // if an exception occurs. + setParentVisitor.visit(aPackage); + declarationVisitor.visit(aPackage); + } + + @Test(expected = InvalidPlaceToDeclareException.class) + public void moduleTestModuleDeclarationInModule() { + fillASTModule(); + fillASTInvalidModule(); + + moduleBlock.addDeclaration(invalidModuleDeclaration); + setParentVisitor.visit(aPackage); + declarationVisitor.visit(aPackage); + } + + @Test(expected = InvalidPlaceToDeclareException.class) + public void moduleTestModuleDeclarationInClass() { + fillASTModule(); + fillASTClass(); + fillASTInvalidModule(); + + classBlock.addDeclaration(invalidModuleDeclaration); + setParentVisitor.visit(aPackage); + declarationVisitor.visit(aPackage); + } + + @Test(expected = InvalidPlaceToDeclareException.class) + public void moduleTestModuleDeclarationInFunction() { + fillASTModule(); + fillASTModuleFunction(); + fillASTInvalidModule(); + + moduleFunctionBlock.addDeclaration(invalidModuleDeclaration); + setParentVisitor.visit(aPackage); + declarationVisitor.visit(aPackage); + } + + @Test(expected = InvalidPlaceToDeclareException.class) + public void moduleTestModuleDeclarationInProcedure() { + fillASTModule(); + fillASTModuleProcedure(); + fillASTInvalidModule(); + + moduleProcedureBlock.addDeclaration(invalidModuleDeclaration); + setParentVisitor.visit(aPackage); + declarationVisitor.visit(aPackage); + } + + // Class Declaration Tests + + @Test + public void classTestClassDeclarationInModule() { + fillASTModule(); + fillASTClass(); + + setParentVisitor.visit(aPackage); + declarationVisitor.visit(aPackage); + assertSame(classDeclaration, moduleDeclaration.getScope().resolve(new ResolvableIdentifier("classDeclaration"))); + } + + @Test(expected = InvalidPlaceToDeclareException.class) + public void classTestClassDeclarationInClass() { + fillASTModule(); + fillASTClass(); + + classBlock.addDeclaration(invalidClassDeclaration); + setParentVisitor.visit(aPackage); + declarationVisitor.visit(aPackage); + } + + @Test(expected = InvalidPlaceToDeclareException.class) + public void classTestClassDeclarationInFunction() { + fillASTModule(); + fillASTModuleFunction(); + + moduleFunctionBlock.addDeclaration(invalidClassDeclaration); + setParentVisitor.visit(aPackage); + declarationVisitor.visit(aPackage); + } + + @Test(expected = InvalidPlaceToDeclareException.class) + public void classTestClassDeclarationInProcedure() { + fillASTModule(); + fillASTModuleProcedure(); + + moduleProcedureBlock.addDeclaration(invalidClassDeclaration); + setParentVisitor.visit(aPackage); + declarationVisitor.visit(aPackage); + } + + // Function Declaration Tests + + @Test + public void functionTestFunctionDeclarationInModule() { + fillASTModule(); + fillASTModuleFunction(); + + setParentVisitor.visit(aPackage); + declarationVisitor.visit(aPackage); + assertTrue(moduleDeclaration.getScope().resolveProcedure(new ResolvableIdentifier("moduleFunctionDeclaration")).contains( + moduleFunctionDeclaration)); + } + + @Test + public void functionTestFunctionDeclarationInClass() { + fillASTModule(); + fillASTClass(); + fillASTClassFunction(); + + setParentVisitor.visit(aPackage); + declarationVisitor.visit(aPackage); + assertTrue(classDeclaration.getScope().resolveProcedure(new ResolvableIdentifier("classFunctionDeclaration")).contains( + classFunctionDeclaration)); + } + + @Test + public void functionTestFunctionDeclarationInFunction() { + fillASTModule(); + fillASTModuleFunction(); + fillASTModuleFunctionFunction(); + + setParentVisitor.visit(aPackage); + declarationVisitor.visit(aPackage); + assertTrue(moduleFunctionDeclaration.getScope().resolveProcedure( + new ResolvableIdentifier("moduleFunctionFunctionDeclaration")).contains( + moduleFunctionFunctionDeclaration)); + } + + @Test + public void functionTestFunctionDeclarationInProcedure() { + fillASTModule(); + fillASTModuleProcedure(); + fillASTModuleProcedureFunction(); + + setParentVisitor.visit(aPackage); + declarationVisitor.visit(aPackage); + assertTrue(moduleProcedureDeclaration.getScope().resolveProcedure( + new ResolvableIdentifier("moduleProcedureFunctionDeclaration")).contains( + moduleProcedureFunctionDeclaration)); + } + + // Procedure Declaration Tests + + @Test + public void procedureTestProcedureDeclarationInModule() { + fillASTModule(); + fillASTModuleProcedure(); + + setParentVisitor.visit(aPackage); + declarationVisitor.visit(aPackage); + assertTrue(moduleDeclaration.getScope().resolveProcedure(new ResolvableIdentifier("moduleProcedureDeclaration")).contains( + moduleProcedureDeclaration)); + } + + @Test + public void procedureTestProcedureDeclarationInClass() { + fillASTModule(); + fillASTClass(); + fillASTClassProcedure(); + + setParentVisitor.visit(aPackage); + declarationVisitor.visit(aPackage); + assertTrue(classDeclaration.getScope().resolveProcedure(new ResolvableIdentifier("classProcedureDeclaration")).contains( + classProcedureDeclaration)); + } + + @Test + public void procedureTestProcedureDeclarationInFunction() { + fillASTModule(); + fillASTModuleFunction(); + fillASTModuleFunctionProcedure(); + + setParentVisitor.visit(aPackage); + declarationVisitor.visit(aPackage); + assertTrue(moduleFunctionDeclaration.getScope().resolveProcedure( + new ResolvableIdentifier("moduleFunctionProcedureDeclaration")).contains( + moduleFunctionProcedureDeclaration)); + } + + @Test + public void procedureTestProcedureDeclarationInProcedure() { + fillASTModule(); + fillASTModuleProcedure(); + fillASTModuleProcedureProcedure(); + + setParentVisitor.visit(aPackage); + declarationVisitor.visit(aPackage); + assertTrue(moduleProcedureDeclaration.getScope().resolveProcedure( + new ResolvableIdentifier("moduleProcedureProcedureDeclaration")).contains( + moduleProcedureProcedureDeclaration)); + } + + // Variable Declaration Tests + + @Test + public void variableTestVariableDeclarationInModule() { + fillASTModule(); + fillASTModuleVariable(); + + setParentVisitor.visit(aPackage); + declarationVisitor.visit(aPackage); + assertSame( + moduleVariableDeclaration, + moduleDeclaration.getScope().resolve(new ResolvableIdentifier("moduleVariableDeclaration"))); + } + + @Test + public void variableTestVariableDeclarationInClass() { + fillASTModule(); + fillASTClass(); + fillASTClassVariable(); + + setParentVisitor.visit(aPackage); + declarationVisitor.visit(aPackage); + assertSame( + classVariableDeclaration, + classDeclaration.getScope().resolve(new ResolvableIdentifier("classVariableDeclaration"))); + } + + @Test + public void variableTestVariableDeclarationInFunction() { + fillASTModule(); + fillASTModuleFunction(); + fillASTModuleFunctionVariable(); + + setParentVisitor.visit(aPackage); + declarationVisitor.visit(aPackage); + Scope scope = moduleFunctionDeclaration.getScope(); + + assertSame( + moduleFunctionParamsVariable01, + scope.resolve(new ResolvableIdentifier("moduleFunctionParamsVariable01"))); + assertSame( + moduleFunctionParamsVariable02, + scope.resolve(new ResolvableIdentifier("moduleFunctionParamsVariable02"))); + assertSame( + moduleFunctionVariableDeclaration, + scope.resolve(new ResolvableIdentifier("moduleFunctionVariableDeclaration"))); + } + + @Test + public void variableTestVariableDeclarationInProcedure() { + fillASTModule(); + fillASTModuleProcedure(); + fillASTModuleProcedureVariable(); + + setParentVisitor.visit(aPackage); + declarationVisitor.visit(aPackage); + Scope scope = moduleProcedureDeclaration.getScope(); + + assertSame( + moduleProcedureParamsVariable01, + scope.resolve(new ResolvableIdentifier("moduleProcedureParamsVariable01"))); + assertSame( + moduleProcedureParamsVariable02, + scope.resolve(new ResolvableIdentifier("moduleProcedureParamsVariable02"))); + assertSame( + moduleProcedureVariableDeclaration, + scope.resolve(new ResolvableIdentifier("moduleProcedureVariableDeclaration"))); + } + + @Test + public void variableTestResolveVariableInNestedScope() { + fillASTModule(); + fillASTModuleVariable(); + fillASTClass(); + fillASTClassVariable(); + fillASTClassFunction(); + + setParentVisitor.visit(aPackage); + declarationVisitor.visit(aPackage); + Scope scope = classFunctionDeclaration.getScope(); + assertSame(classVariableDeclaration, scope.resolve(new ResolvableIdentifier("classVariableDeclaration"))); + assertSame(moduleVariableDeclaration, scope.resolve(new ResolvableIdentifier("moduleVariableDeclaration"))); + } + + // REDECLARATION + + @Test(expected = RedeclarationException.class) + public void redeclarationTestRedeclarationInSameScopeTest() { + fillASTModule(); + fillASTModuleVariable(); + + VariableDeclaration variableDeclaration = + new VariableDeclaration(buildPosition(), new Identifier("moduleVariableDeclaration"), + new ResolvableIdentifier("String"), VariableDeclaration.DeclarationType.VARIABLE); + moduleBlock.addDeclaration(variableDeclaration); + + setParentVisitor.visit(aPackage); + declarationVisitor.visit(aPackage); + } + + @Test(expected = RedeclarationException.class) + public void redeclarationTestRedeclarationInSameClassScopeTest() { + fillASTModule(); + fillASTClass(); + fillASTClassVariable(); + + VariableDeclaration variableDeclaration = + new VariableDeclaration(buildPosition(), new Identifier("classVariableDeclaration"), + new ResolvableIdentifier("String"), VariableDeclaration.DeclarationType.ATTRIBUTE); + classBlock.addDeclaration(variableDeclaration); + + setParentVisitor.visit(aPackage); + declarationVisitor.visit(aPackage); + } + + @Test + public void redeclarationTestRedeclarationInDifferentScopes() { + fillASTModule(); + fillASTModuleVariable(); + fillASTModuleFunction(); + + VariableDeclaration variableDeclaration = + new VariableDeclaration(buildPosition(), new Identifier("moduleVariableDeclaration"), + new ResolvableIdentifier("String"), VariableDeclaration.DeclarationType.VARIABLE); + moduleFunctionBlock.addDeclaration(variableDeclaration); + + setParentVisitor.visit(aPackage); + declarationVisitor.visit(aPackage); + assertSame( + variableDeclaration, + moduleFunctionDeclaration.getScope().resolve(new ResolvableIdentifier("moduleVariableDeclaration"))); + assertNotSame( + variableDeclaration, + moduleDeclaration.getScope().resolve(new ResolvableIdentifier("moduleVariableDeclaration"))); + } + + @Test + public void redeclarationTestRedeclarationInExtendedClassScope() { + fillASTModule(); + fillASTExtendedClass(); + fillASTClass(); + fillASTClassVariable(); + + VariableDeclaration variableDeclaration = + new VariableDeclaration(buildPosition(), new Identifier("classVariableDeclaration"), + new ResolvableIdentifier("String"), VariableDeclaration.DeclarationType.ATTRIBUTE); + extendedClassBlock.addDeclaration(variableDeclaration); + + setParentVisitor.visit(aPackage); + declarationVisitor.visit(aPackage); + assertSame( + variableDeclaration, + extendedClassDeclaration.getScope().resolve(new ResolvableIdentifier("classVariableDeclaration"))); + assertNotSame( + variableDeclaration, + classDeclaration.getScope().resolve(new ResolvableIdentifier("classVariableDeclaration"))); + } +} diff --git a/src/test/java/de/uni/bremen/monty/moco/ast/TypeCheckTest.java b/src/test/java/de/uni/bremen/monty/moco/ast/TypeCheckTest.java new file mode 100644 index 0000000..7d5e24e --- /dev/null +++ b/src/test/java/de/uni/bremen/monty/moco/ast/TypeCheckTest.java @@ -0,0 +1,1611 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.ast; + +import de.uni.bremen.monty.moco.ast.declaration.*; +import de.uni.bremen.monty.moco.ast.declaration.VariableDeclaration.DeclarationType; +import de.uni.bremen.monty.moco.ast.expression.*; +import de.uni.bremen.monty.moco.ast.expression.literal.BooleanLiteral; +import de.uni.bremen.monty.moco.ast.expression.literal.FloatLiteral; +import de.uni.bremen.monty.moco.ast.expression.literal.IntegerLiteral; +import de.uni.bremen.monty.moco.ast.expression.literal.StringLiteral; +import de.uni.bremen.monty.moco.ast.statement.*; +import de.uni.bremen.monty.moco.exception.InvalidExpressionException; +import de.uni.bremen.monty.moco.exception.TypeMismatchException; +import de.uni.bremen.monty.moco.exception.UnknownIdentifierException; +import de.uni.bremen.monty.moco.visitor.DeclarationVisitor; +import de.uni.bremen.monty.moco.visitor.ResolveVisitor; +import de.uni.bremen.monty.moco.visitor.SetParentVisitor; +import de.uni.bremen.monty.moco.visitor.TypeCheckVisitor; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import static org.junit.Assert.*; + +public class TypeCheckTest { + + private SetParentVisitor SPV; + private DeclarationVisitor DV; + private TypeCheckVisitor TCV; + private ResolveVisitor RV; + + private ModuleDeclaration moduleDeclaration; + private Package aPackage; + private Block moduleBlock; + + private ClassDeclaration object; + private ClassDeclaration classDeclaration; + + private VariableDeclaration intVariable; + private VariableDeclaration floatVariable; + private VariableDeclaration strVariable; + private VariableDeclaration booleanVariable; + + private VariableAccess intVariableAccess; + private VariableAccess floatVariableAccess; + private VariableAccess booleanVariableAccess; + private VariableAccess strVariableAccess; + + private IntegerLiteral intLiteral; + private FloatLiteral floatLiteral; + private StringLiteral strLiteral; + private BooleanLiteral booleanLiteral; + + private FunctionDeclaration functionDeclarationIntReturnInt; + private FunctionDeclaration functionDeclarationStringReturnString; + + private ClassDeclaration classPerson; + private ClassDeclaration classStudent; + + private VariableDeclaration classPersonVarDecl; + private VariableDeclaration classStudentVarDecl; + + private ConditionalExpression ConditionStringString; + private ConditionalExpression ConditionIntString; + private ConditionalExpression ConditionIntInt; + + private int lineCounter = 0; + + private Position buildPosition() { + return new Position("TypeCheckTest", lineCounter++, 0); + } + + // helper + private int counter = 0; + + public Position nextPosition() { + return new Position("TestFile", counter++, 1); + } + + @Rule + public ExpectedException exception = ExpectedException.none(); + + @Before + public void setUpAST() { + // reset counter + counter = 0; + + SPV = new SetParentVisitor(); + SPV.setStopOnFirstError(true); + + DV = new DeclarationVisitor(); + DV.setStopOnFirstError(true); + + RV = new ResolveVisitor(); + RV.setStopOnFirstError(true); + + TCV = new TypeCheckVisitor(); + TCV.setStopOnFirstError(true); + + Block classDeclarationBlock = new Block(buildPosition()); + classDeclaration = + new ClassDeclaration(buildPosition(), new Identifier("classDeclaration"), + new ArrayList(), classDeclarationBlock); + classDeclarationBlock.addDeclaration(new VariableDeclaration(buildPosition(), new Identifier( + "classVariableDeclaration"), new ResolvableIdentifier("String"), + VariableDeclaration.DeclarationType.ATTRIBUTE)); + classDeclarationBlock.addDeclaration(new ProcedureDeclaration(buildPosition(), new Identifier( + "classProcedureDeclaration"), new Block(buildPosition()), new ArrayList())); + + intVariable = + new VariableDeclaration(buildPosition(), new Identifier("intVariable"), + new ResolvableIdentifier("Int"), VariableDeclaration.DeclarationType.VARIABLE); + floatVariable = + new VariableDeclaration(buildPosition(), new Identifier("floatVariable"), new ResolvableIdentifier( + "Float"), VariableDeclaration.DeclarationType.VARIABLE); + booleanVariable = + new VariableDeclaration(buildPosition(), new Identifier("booleanVariable"), new ResolvableIdentifier( + "Bool"), VariableDeclaration.DeclarationType.VARIABLE); + strVariable = + new VariableDeclaration(buildPosition(), new Identifier("strVariable"), new ResolvableIdentifier( + "String"), VariableDeclaration.DeclarationType.VARIABLE); + + intVariableAccess = new VariableAccess(buildPosition(), new ResolvableIdentifier("intVariable")); + floatVariableAccess = new VariableAccess(buildPosition(), new ResolvableIdentifier("floatVariable")); + booleanVariableAccess = new VariableAccess(buildPosition(), new ResolvableIdentifier("booleanVariable")); + strVariableAccess = new VariableAccess(buildPosition(), new ResolvableIdentifier("strVariable")); + + intLiteral = new IntegerLiteral(buildPosition(), 1); + floatLiteral = new FloatLiteral(buildPosition(), 0f); + strLiteral = new StringLiteral(buildPosition(), "42"); + booleanLiteral = new BooleanLiteral(buildPosition(), false); + + // set up test AST + moduleBlock = new Block(new Position("TESTFILE", 2, 10)); + moduleDeclaration = + new ModuleDeclaration(new Position("TESTFILE", 1, 10), new Identifier("Main"), moduleBlock, + new ArrayList()); + aPackage = new Package(new Identifier("")); + aPackage.addModule(moduleDeclaration); + Package corePackage = new Package(new Identifier("core")); + Block block = new Block(new Position()); + for (ClassDeclaration classDeclaration : CoreClasses.getAllCoreClasses()) { + block.addDeclaration(classDeclaration); + } + + corePackage.addModule(new ModuleDeclaration(new Position(), new Identifier("CoreClasses"), block, + Collections. emptyList())); + aPackage.addSubPackage(corePackage); + + // Function Block Declaration + Block functionblock = new Block(buildPosition()); + functionblock.addStatement(new ReturnStatement(buildPosition(), new StringLiteral(buildPosition(), + "StringReturnString Result"))); + ArrayList params = new ArrayList(); + params.add(new VariableDeclaration(buildPosition(), new Identifier("a"), new ResolvableIdentifier("String"), + DeclarationType.PARAMETER)); + functionDeclarationStringReturnString = + new FunctionDeclaration(buildPosition(), new Identifier("StringReturnString"), functionblock, params, + new ResolvableIdentifier("String")); + + Block functionblock2 = new Block(buildPosition()); + functionblock2.addStatement(new ReturnStatement(buildPosition(), new IntegerLiteral(buildPosition(), 1337))); + ArrayList params2 = new ArrayList(); + params2.add(new VariableDeclaration(buildPosition(), new Identifier("a"), new ResolvableIdentifier("Int"), + DeclarationType.PARAMETER)); + functionDeclarationIntReturnInt = + new FunctionDeclaration(buildPosition(), new Identifier("IntReturnInt"), functionblock2, params2, + new ResolvableIdentifier("Int")); + + // Class Declaration Person + Block declList = new Block(buildPosition()); + declList.addDeclaration(new VariableDeclaration(buildPosition(), new Identifier("name"), + new ResolvableIdentifier("String"), DeclarationType.ATTRIBUTE)); + declList.addDeclaration(new VariableDeclaration(buildPosition(), new Identifier("age"), + new ResolvableIdentifier("String"), DeclarationType.ATTRIBUTE)); + classPerson = + new ClassDeclaration(buildPosition(), new Identifier("Person"), new ArrayList(), + declList); + + // Class Declaration Person + Block declList2 = new Block(buildPosition()); + declList2.addDeclaration(new VariableDeclaration(buildPosition(), new Identifier("name"), + new ResolvableIdentifier("String"), DeclarationType.ATTRIBUTE)); + declList2.addDeclaration(new VariableDeclaration(buildPosition(), new Identifier("age"), + new ResolvableIdentifier("String"), DeclarationType.ATTRIBUTE)); + classStudent = + new ClassDeclaration(buildPosition(), new Identifier("Student"), new ArrayList(), + declList2); + + classPersonVarDecl = + new VariableDeclaration(buildPosition(), new Identifier("myPerson"), + new ResolvableIdentifier("Person"), DeclarationType.VARIABLE); + classStudentVarDecl = + new VariableDeclaration(buildPosition(), new Identifier("myStudent"), new ResolvableIdentifier( + "Student"), DeclarationType.VARIABLE); + + ConditionStringString = new ConditionalExpression(buildPosition(), booleanLiteral, strLiteral, strLiteral); + + ConditionIntString = new ConditionalExpression(buildPosition(), booleanLiteral, intLiteral, strLiteral); + + ConditionIntInt = new ConditionalExpression(buildPosition(), booleanLiteral, intLiteral, intLiteral); + + } + + @Test + public void setUpASTTest() { + assertNotNull("SPV is null", SPV); + assertNotNull("DV is null", DV); + assertNotNull("RV is null", RV); + assertNotNull("TCV is null", TCV); + + assertNotNull("package is null", aPackage); + assertNotNull("moduleDeclaration is null", moduleDeclaration); + assertNotNull("moduleBlock is null", moduleBlock); + + assertNotNull("intVariable is null", intVariable); + assertNotNull("floatVariable is null", floatVariable); + assertNotNull("strVariable is null", strVariable); + assertNotNull("booleanVariable is null", booleanVariable); + + assertNotNull("intVariableAccess is null", intVariableAccess); + assertNotNull("floatVariableAccess is null", floatVariableAccess); + assertNotNull("booleanVariableAccess is null", booleanVariableAccess); + assertNotNull("strVariableAccess is null", strVariableAccess); + + assertNotNull("intLiteral is null", intLiteral); + assertNotNull("floatLiteral is null", floatLiteral); + assertNotNull("strLiteral is null", strLiteral); + assertNotNull("booleanLiteral is null", booleanLiteral); + } + + // TYPE COMPATIBILITY + + @Test + public void typeEqualityTest() { + for (TypeDeclaration type1 : CoreClasses.getAllCoreClasses()) { + for (TypeDeclaration type2 : CoreClasses.getAllCoreClasses()) { + if (type2 != CoreClasses.objectType()) { + if (type1 == type2 || type2 == CoreClasses.objectType()) { + assertTrue(String.format( + "%s does not match %s", + type1.getIdentifier().getSymbol(), + type2.getIdentifier().getSymbol()), type1.matchesType(type2)); + } else { + assertFalse(String.format( + "%s does match %s", + type1.getIdentifier().getSymbol(), + type2.getIdentifier().getSymbol()), type1.matchesType(type2)); + } + } + } + } + } + + // LITERAL COMPATIBILITY + + @Test + public void literalCompatibilityTest() { + Assignment intAssignment = new Assignment(buildPosition(), intVariableAccess, intLiteral); + Assignment floatAssignment = new Assignment(buildPosition(), floatVariableAccess, floatLiteral); + Assignment booleanAssignment = new Assignment(buildPosition(), booleanVariableAccess, booleanLiteral); + Assignment strAssignment = new Assignment(buildPosition(), strVariableAccess, strLiteral); + + moduleBlock.addDeclaration(intVariable); + moduleBlock.addDeclaration(floatVariable); + moduleBlock.addDeclaration(booleanVariable); + moduleBlock.addDeclaration(strVariable); + moduleBlock.addStatement(intAssignment); + moduleBlock.addStatement(floatAssignment); + moduleBlock.addStatement(booleanAssignment); + moduleBlock.addStatement(strAssignment); + + SPV.visit(aPackage); + DV.visit(aPackage); + RV.visit(aPackage); + TCV.visit(aPackage); // no exception here + } + + // LITERAL INCOMPATIBILITY + + @Test(expected = TypeMismatchException.class) + public void literalIncompatibilityTestIntFloat() { + Assignment intAssignment = new Assignment(buildPosition(), intVariableAccess, floatLiteral); + + moduleBlock.addDeclaration(intVariable); + moduleBlock.addStatement(intAssignment); + + SPV.visit(aPackage); + DV.visit(aPackage); + RV.visit(aPackage); + TCV.visit(aPackage); // TypeMismatchException + } + + @Test(expected = TypeMismatchException.class) + public void literalIncompatibilityTestIntBool() { + Assignment intAssignment = new Assignment(buildPosition(), intVariableAccess, booleanLiteral); + + moduleBlock.addDeclaration(intVariable); + moduleBlock.addStatement(intAssignment); + + SPV.visit(aPackage); + DV.visit(aPackage); + RV.visit(aPackage); + TCV.visit(aPackage); // TypeMismatchException + } + + @Test(expected = TypeMismatchException.class) + public void literalIncompatibilityTestIntStr() { + Assignment intAssignment = new Assignment(buildPosition(), intVariableAccess, strLiteral); + + moduleBlock.addDeclaration(intVariable); + moduleBlock.addStatement(intAssignment); + + SPV.visit(aPackage); + DV.visit(aPackage); + RV.visit(aPackage); + TCV.visit(aPackage); // TypeMismatchException + } + + @Test(expected = TypeMismatchException.class) + public void literalIncompatibilityTestFloatInt() { + Assignment floatAssignment = new Assignment(buildPosition(), floatVariableAccess, intLiteral); + + moduleBlock.addDeclaration(floatVariable); + moduleBlock.addStatement(floatAssignment); + + SPV.visit(aPackage); + DV.visit(aPackage); + RV.visit(aPackage); + TCV.visit(aPackage); // TypeMismatchException + } + + @Test(expected = TypeMismatchException.class) + public void literalIncompatibilityTestFloatBool() { + Assignment floatAssignment = new Assignment(buildPosition(), floatVariableAccess, booleanLiteral); + + moduleBlock.addDeclaration(floatVariable); + moduleBlock.addStatement(floatAssignment); + + SPV.visit(aPackage); + DV.visit(aPackage); + RV.visit(aPackage); + TCV.visit(aPackage); // TypeMismatchException + } + + @Test(expected = TypeMismatchException.class) + public void literalIncompatibilityTestFloatStr() { + Assignment floatAssignment = new Assignment(buildPosition(), floatVariableAccess, strLiteral); + + moduleBlock.addDeclaration(floatVariable); + moduleBlock.addStatement(floatAssignment); + + SPV.visit(aPackage); + DV.visit(aPackage); + RV.visit(aPackage); + TCV.visit(aPackage); // TypeMismatchException + } + + @Test(expected = TypeMismatchException.class) + public void literalIncompatibilityTestBoolInt() { + Assignment booleanAssignment = new Assignment(buildPosition(), booleanVariableAccess, intLiteral); + + moduleBlock.addDeclaration(booleanVariable); + moduleBlock.addStatement(booleanAssignment); + + SPV.visit(aPackage); + DV.visit(aPackage); + RV.visit(aPackage); + TCV.visit(aPackage); // TypeMismatchException + } + + @Test(expected = TypeMismatchException.class) + public void literalIncompatibilityTestBoolFloat() { + Assignment booleanAssignment = new Assignment(buildPosition(), booleanVariableAccess, floatLiteral); + + moduleBlock.addDeclaration(booleanVariable); + moduleBlock.addStatement(booleanAssignment); + + SPV.visit(aPackage); + DV.visit(aPackage); + RV.visit(aPackage); + TCV.visit(aPackage); // TypeMismatchException + } + + @Test(expected = TypeMismatchException.class) + public void literalIncompatibilityTestBoolStr() { + Assignment booleanAssignment = new Assignment(buildPosition(), booleanVariableAccess, strLiteral); + + moduleBlock.addDeclaration(booleanVariable); + moduleBlock.addStatement(booleanAssignment); + + SPV.visit(aPackage); + DV.visit(aPackage); + RV.visit(aPackage); + TCV.visit(aPackage); // TypeMismatchException + } + + @Test(expected = TypeMismatchException.class) + public void literalIncompatibilityTestStrInt() { + Assignment strAssignment = new Assignment(buildPosition(), strVariableAccess, intLiteral); + + moduleBlock.addDeclaration(strVariable); + moduleBlock.addStatement(strAssignment); + + SPV.visit(aPackage); + DV.visit(aPackage); + RV.visit(aPackage); + TCV.visit(aPackage); // TypeMismatchException + } + + @Test(expected = TypeMismatchException.class) + public void literalIncompatibilityTestStrFloat() { + Assignment strAssignment = new Assignment(buildPosition(), strVariableAccess, floatLiteral); + + moduleBlock.addDeclaration(strVariable); + moduleBlock.addStatement(strAssignment); + + SPV.visit(aPackage); + DV.visit(aPackage); + RV.visit(aPackage); + TCV.visit(aPackage); // TypeMismatchException + } + + @Test(expected = TypeMismatchException.class) + public void literalIncompatibilityTestStrBool() { + Assignment strAssignment = new Assignment(buildPosition(), strVariableAccess, booleanLiteral); + + moduleBlock.addDeclaration(strVariable); + moduleBlock.addStatement(strAssignment); + + SPV.visit(aPackage); + DV.visit(aPackage); + RV.visit(aPackage); + TCV.visit(aPackage); // TypeMismatchException + } + + // ASSIGNMENTS + // => Each testcase has to include a well-typed scenario (with a correctly + // typed left and right side), as well as an ill-typed scenario. + + private Object[] makeVarAccessVarAccessAssignment(String LeftResolvableSymbol, String RightResolvableSymbol) { + /* + * Makes a the declarations and VariableAccess objects needed for an variable access = variable access + * AssignmentTest01 and appends it to the Block + */ + VariableDeclaration v1 = + new VariableDeclaration(buildPosition(), new Identifier("var1"), new ResolvableIdentifier( + LeftResolvableSymbol), DeclarationType.VARIABLE); + moduleBlock.addDeclaration(v1); + VariableDeclaration v2 = + new VariableDeclaration(buildPosition(), new Identifier("var2"), new ResolvableIdentifier( + RightResolvableSymbol), DeclarationType.VARIABLE); + moduleBlock.addDeclaration(v2); + VariableAccess val = new VariableAccess(buildPosition(), new ResolvableIdentifier("var1")); + + VariableAccess var = new VariableAccess(buildPosition(), new ResolvableIdentifier("var2")); + + Assignment a = new Assignment(buildPosition(), val, var); + moduleBlock.addStatement(a); + Object[] result = { v1, v2, a }; + return result; + } + + @Test + public void assignmentTest01_1() { + // variable access = variable access + + Object[] generated = makeVarAccessVarAccessAssignment("String", "String"); + SPV.visit(aPackage); + DV.visit(aPackage); + RV.visit(aPackage); + TCV.visit(aPackage); + + Scope bs = moduleBlock.getScope(); + assertNotNull("Scope of module is null, but should be anything else!", moduleDeclaration.getScope()); + assertNotNull("Scope of moduleBlock is null, but should be anything else!", bs); + + assertEquals( + "Declaration doesn't match with the orginal one.", + moduleBlock.getDeclarations().get(0), + (VariableDeclaration) generated[0]); + assertEquals( + "Declaration doesn't match with the orginal one.", + moduleBlock.getDeclarations().get(1), + (VariableDeclaration) generated[1]); + + for (Declaration dc : moduleBlock.getDeclarations()) { + Identifier obj_id = dc.getIdentifier(); + Scope obj_s = dc.getScope(); + assertNotNull("Identifiert shouldn't be null.", obj_id); + assertNotNull("Scope shouldn't be null.", obj_s); + assertEquals("One var declaration is not in the scope of the moduleBlock.", obj_s, bs); + } + + ArrayList statements = (ArrayList) moduleBlock.getStatements(); + + Assignment assignment = null; + if (statements.get(0) instanceof Assignment) { + assignment = (Assignment) statements.get(0); + } else + fail("Statement is not an AssignmentStatement."); + + assertEquals("Statement doesn't match with the orginal one.", statements.get(0), (Assignment) generated[2]); + + if (!(assignment.getLeft() instanceof VariableAccess) && !(assignment.getRight() instanceof VariableAccess)) { + fail("Left or Right of assignment are not from type VariableAccess"); + } + VariableAccess left = (VariableAccess) assignment.getLeft(); + VariableAccess right = (VariableAccess) assignment.getRight(); + + assertEquals("Assignment is not in the moduleBlock scope", assignment.getScope(), bs); + assertNotNull("Type of left Expression is null, but should be string.", left.getType()); + assertNotNull("Type of right Expression is null, but should be string.", right.getType()); + assertEquals("Type of left Expression is not String", left.getType(), CoreClasses.stringType()); + assertEquals("Type of right Expression is not String", right.getType(), CoreClasses.stringType()); + } + + @Test + public void assignmentTest01_2() { + // variable access = variable access + // Ill-Type Test #1 + exception.expect(TypeMismatchException.class); + makeVarAccessVarAccessAssignment("String", "Int"); + SPV.visit(aPackage); + DV.visit(aPackage); + RV.visit(aPackage); + TCV.visit(aPackage); + } + + @Test + public void assignmentTest01_3() { + // variable access = variable access + // Ill-Type Test #2 + exception.expect(TypeMismatchException.class); + makeVarAccessVarAccessAssignment("Float", "String"); + SPV.visit(aPackage); + DV.visit(aPackage); + RV.visit(aPackage); + TCV.visit(aPackage); + } + + @Test + public void assignmentTest01_4() { + // variable access = variable access + // Ill-Type Test #3 + exception.expect(TypeMismatchException.class); + makeVarAccessVarAccessAssignment("Int", "Float"); + SPV.visit(aPackage); + DV.visit(aPackage); + RV.visit(aPackage); + TCV.visit(aPackage); + } + + private void makeVarAccessMemberAccessAssignment(String LeftResolvableSymbol, boolean otherWay) { + /* + * Makes a the declarations and Access objects needed for an variable access = member access AssignmentTest02 + * and appends it to the Blockclass + */ + + // Declaration of a class with a member as attribute. + + moduleBlock.addDeclaration(classPerson); + + // Declaration of a variable + VariableDeclaration v1 = + new VariableDeclaration(buildPosition(), new Identifier("var1"), new ResolvableIdentifier( + LeftResolvableSymbol), DeclarationType.VARIABLE); + moduleBlock.addDeclaration(v1); + + VariableAccess val = new VariableAccess(buildPosition(), new ResolvableIdentifier("var1")); + VariableAccess classvar = new VariableAccess(buildPosition(), new ResolvableIdentifier("Person")); + VariableAccess classaccess = new VariableAccess(buildPosition(), new ResolvableIdentifier("name")); + + MemberAccess mar = new MemberAccess(buildPosition(), classvar, classaccess); + Assignment a; + if (otherWay) + a = new Assignment(buildPosition(), mar, val); + else + a = new Assignment(buildPosition(), val, mar); + moduleBlock.addStatement(a); + } + + @Test + public void assignmentTest02_2() { + // variable access = member access + // Ill-Type Test #1 + exception.expect(TypeMismatchException.class); + makeVarAccessMemberAccessAssignment("Float", false); + SPV.visit(aPackage); + DV.visit(aPackage); + RV.visit(aPackage); + TCV.visit(aPackage); + } + + @Test + public void assignmentTest02_3() { + // variable access = member access + // Ill-Type Test #2 + exception.expect(TypeMismatchException.class); + makeVarAccessMemberAccessAssignment("Int", false); + SPV.visit(aPackage); + DV.visit(aPackage); + RV.visit(aPackage); + TCV.visit(aPackage); + } + + @Test + public void assignmentTest02_4() { + // variable access = member access + // Ill-Type Test #3 + exception.expect(TypeMismatchException.class); + makeVarAccessMemberAccessAssignment("Bool", false); + SPV.visit(aPackage); + DV.visit(aPackage); + RV.visit(aPackage); + TCV.visit(aPackage); + } + + private void variableAccessConditionalExpression_helper(boolean otherway) { + moduleBlock.addDeclaration(strVariable); + Assignment a = + (otherway) ? new Assignment(buildPosition(), strVariableAccess, ConditionStringString) : new Assignment( + buildPosition(), ConditionStringString, strVariableAccess); + moduleBlock.addStatement(a); + + SPV.visit(aPackage); + DV.visit(aPackage); + RV.visit(aPackage); + TCV.visit(aPackage); + + Statement s = moduleBlock.getStatements().get(0); + + assertEquals( + "Statement doesn't match with the orginal one!", + moduleBlock.getStatements().get(0), + (Assignment) s); + + Scope mbs = moduleBlock.getScope(); + assertEquals( + "ConditionalExpression scope doesn't match with block scope!", + mbs, + ConditionStringString.getScope()); + assertEquals("Assignment scope doesn't match with block scope!", mbs, a.getScope()); + assertEquals("booleanLiteral scope doesn't match with block scope!", mbs, booleanLiteral.getScope()); + assertEquals("strLiteral scope doesn't match with block scope!", mbs, strLiteral.getScope()); + assertEquals("strVariableAccess scope doesn't match with block scope!", mbs, strVariableAccess.getScope()); + assertEquals("strVariable scope doesn't match with block scope!", mbs, strVariable.getScope()); + VariableAccess v = (VariableAccess) a.getLeft(); + assertTrue("VariableAccess Left Expression is not marked as L-Value", v.getLValue()); + assertTrue( + "Type of Left Expression from VariableAccess is not string!", + v.getType() == CoreClasses.stringType()); + + } + + @Test + public void assignmentTest03_1() { + // variable access = conditional expression + variableAccessConditionalExpression_helper(true); + } + + @Test + public void assignmentTest03_2() { + // variable access = conditional expression + // Ill-Type Test #1 + exception.expect(TypeMismatchException.class); + moduleBlock.addDeclaration(strVariable); + Assignment a = new Assignment(buildPosition(), strVariableAccess, ConditionIntInt); + moduleBlock.addStatement(a); + + SPV.visit(aPackage); + DV.visit(aPackage); + RV.visit(aPackage); + TCV.visit(aPackage); + } + + @Test + public void assignmentTest03_3() { + // variable access = conditional expression + // Ill-Type Test #2 + exception.expect(TypeMismatchException.class); + ConditionalExpression CE = + new ConditionalExpression(buildPosition(), booleanLiteral, floatLiteral, floatLiteral); + moduleBlock.addDeclaration(strVariable); + Assignment a = new Assignment(buildPosition(), strVariableAccess, CE); + moduleBlock.addStatement(a); + + SPV.visit(aPackage); + DV.visit(aPackage); + RV.visit(aPackage); + TCV.visit(aPackage); + } + + @Test + public void assignmentTest03_4() { + // conditional expression = variable access (is not allowed) + exception.expect(InvalidExpressionException.class); + variableAccessConditionalExpression_helper(false); + } + + private FunctionCall VariableAccessFunctionCallHelper() { + // build function with two parameters ( both int) and return type int: + Block functionblock = new Block(buildPosition()); + functionblock.addStatement(new ReturnStatement(buildPosition(), new IntegerLiteral(buildPosition(), 1337))); + ArrayList params = new ArrayList(); + params.add(new VariableDeclaration(buildPosition(), new Identifier("a"), new ResolvableIdentifier("Int"), + DeclarationType.PARAMETER)); + params.add(new VariableDeclaration(buildPosition(), new Identifier("b"), new ResolvableIdentifier("Int"), + DeclarationType.PARAMETER)); + FunctionDeclaration fd = + new FunctionDeclaration(buildPosition(), new Identifier("testfunction"), functionblock, params, + new ResolvableIdentifier("Int")); + moduleBlock.addDeclaration(fd); + // Make a list with given parameters: + ArrayList values = new ArrayList(); + values.add(intLiteral); + values.add(intLiteral); + return new FunctionCall(buildPosition(), new ResolvableIdentifier("testfunction"), values); + } + + @Test + public void assignmentTest04_1() { + // variable access = function call + moduleBlock.addDeclaration(intVariable); + Assignment a = new Assignment(buildPosition(), intVariableAccess, VariableAccessFunctionCallHelper()); + moduleBlock.addStatement(a); + + SPV.visit(aPackage); + DV.visit(aPackage); + RV.visit(aPackage); + TCV.visit(aPackage); + + } + + @Test + public void assignmentTest04_2() { + // variable access = function call + // Ill-Type Test #1 (Int return on a string variable) + exception.expect(TypeMismatchException.class); + moduleBlock.addDeclaration(strVariable); + Assignment a = new Assignment(buildPosition(), strVariableAccess, VariableAccessFunctionCallHelper()); + moduleBlock.addStatement(a); + + SPV.visit(aPackage); + DV.visit(aPackage); + RV.visit(aPackage); + TCV.visit(aPackage); + + } + + @Test + public void assignmentTest04_3() { + // variable access = function call + // (Int return on a float variable) is not allowed + exception.expect(TypeMismatchException.class); + moduleBlock.addDeclaration(floatVariable); + Assignment a = new Assignment(buildPosition(), floatVariableAccess, VariableAccessFunctionCallHelper()); + moduleBlock.addStatement(a); + + SPV.visit(aPackage); + DV.visit(aPackage); + RV.visit(aPackage); + TCV.visit(aPackage); + + } + + @Test + public void assignmentTest04_4() { + // variable access = function call + // Ill-Type Test #3(Int return on a boolean variable) + exception.expect(TypeMismatchException.class); + moduleBlock.addDeclaration(booleanVariable); + Assignment a = new Assignment(buildPosition(), booleanVariableAccess, VariableAccessFunctionCallHelper()); + moduleBlock.addStatement(a); + + SPV.visit(aPackage); + DV.visit(aPackage); + RV.visit(aPackage); + TCV.visit(aPackage); + + } + + @Test + public void assignmentTest05_2() { + // member access = variable access + // Ill-Type Test #1 + exception.expect(TypeMismatchException.class); + makeVarAccessMemberAccessAssignment("Float", true); + SPV.visit(aPackage); + DV.visit(aPackage); + RV.visit(aPackage); + TCV.visit(aPackage); + } + + @Test + public void assignmentTest05_3() { + // member access = variable access + // Ill-Type Test #2 + exception.expect(TypeMismatchException.class); + makeVarAccessMemberAccessAssignment("Int", true); + SPV.visit(aPackage); + DV.visit(aPackage); + RV.visit(aPackage); + TCV.visit(aPackage); + } + + @Test + public void assignmentTest05_4() { + // member access = variable access + // Ill-Type Test #3 + exception.expect(TypeMismatchException.class); + makeVarAccessMemberAccessAssignment("Bool", true); + SPV.visit(aPackage); + DV.visit(aPackage); + RV.visit(aPackage); + TCV.visit(aPackage); + } + + private void makeMemberAccessMemberAccessAssignment() { + /* + * Makes a the declarations and Access objects needed for an member access = member access AssignmentTest06 and + * appends it to the Block + */ + + moduleBlock.addDeclaration(classStudent); + moduleBlock.addDeclaration(classPerson); + + // Declaration of variables myPerson and myStudent + moduleBlock.addDeclaration(classPersonVarDecl); + moduleBlock.addDeclaration(classStudentVarDecl); + + // Create VariableAccess objects. + VariableAccess classvar = new VariableAccess(buildPosition(), new ResolvableIdentifier("myPerson")); + VariableAccess classvar2 = new VariableAccess(buildPosition(), new ResolvableIdentifier("myStudent")); + + // Make the Assignment with from two MemberAccesses. + MemberAccess ma1 = + new MemberAccess(buildPosition(), classvar, new VariableAccess(buildPosition(), + new ResolvableIdentifier("name"))); + MemberAccess ma2 = + new MemberAccess(buildPosition(), classvar2, new VariableAccess(buildPosition(), + new ResolvableIdentifier("name"))); + Assignment a = new Assignment(buildPosition(), ma1, ma2); + moduleBlock.addStatement(a); + + } + + @Test + public void assignmentTest06() { + // member access = member access + makeMemberAccessMemberAccessAssignment(); + + SPV.visit(aPackage); + DV.visit(aPackage); + RV.visit(aPackage); + TCV.visit(aPackage); + } + + @Test + public void assignmentTest07() { + // member access = conditional expression + moduleBlock.addDeclaration(classStudent); + moduleBlock.addDeclaration(classStudentVarDecl); + + VariableAccess classvar = new VariableAccess(buildPosition(), new ResolvableIdentifier("myStudent")); + + MemberAccess ma = + new MemberAccess(buildPosition(), classvar, new VariableAccess(buildPosition(), + new ResolvableIdentifier("name"))); + Assignment a = new Assignment(buildPosition(), ma, ConditionStringString); + moduleBlock.addStatement(a); + + SPV.visit(aPackage); + DV.visit(aPackage); + RV.visit(aPackage); + TCV.visit(aPackage); + + Scope sc = a.getScope(); + assertNotNull(sc); + assertEquals(sc, moduleBlock.getScope()); + assertTrue(a.getRight() instanceof ConditionalExpression); + assertTrue(a.getLeft() instanceof MemberAccess); + assertTrue(a.getLeft().getType().equals(a.getRight().getType())); + } + + @Test + public void assignmentTest08() { + // member access = function call + + moduleBlock.addDeclaration(classStudent); + moduleBlock.addDeclaration(classStudentVarDecl); + moduleBlock.addDeclaration(functionDeclarationStringReturnString); + + VariableAccess classvar = new VariableAccess(buildPosition(), new ResolvableIdentifier("myStudent")); + + MemberAccess ma = + new MemberAccess(buildPosition(), classvar, new VariableAccess(buildPosition(), + new ResolvableIdentifier("name"))); + + ArrayList values = new ArrayList(); + values.add(strLiteral); + FunctionCall fc = new FunctionCall(buildPosition(), new ResolvableIdentifier("StringReturnString"), values); + + Assignment a = new Assignment(buildPosition(), ma, fc); + moduleBlock.addStatement(a); + + SPV.visit(aPackage); + DV.visit(aPackage); + RV.visit(aPackage); + TCV.visit(aPackage); + + Scope sc = a.getScope(); + assertNotNull(sc); + assertEquals(sc, moduleBlock.getScope()); + assertTrue(a.getLeft() instanceof MemberAccess); + assertTrue(a.getRight() instanceof FunctionCall); + assertTrue(a.getLeft().getType().equals(a.getRight().getType())); + } + + @Test + public void assignmentTest09() { + // function call = variable access + exception.expect(InvalidExpressionException.class); + moduleBlock.addDeclaration(intVariable); + Assignment a = new Assignment(buildPosition(), VariableAccessFunctionCallHelper(), intVariableAccess); + moduleBlock.addStatement(a); + SPV.visit(aPackage); + DV.visit(aPackage); + RV.visit(aPackage); + TCV.visit(aPackage); + } + + // MEMBER ACCESS + + @Test(expected = UnknownIdentifierException.class) + public void memberAccessTest01() { + // x 1: left ist keine classDeclaration + FunctionDeclaration functionDeclaration = + new FunctionDeclaration(buildPosition(), new Identifier("functionDeclaration"), new Block( + buildPosition()), new ArrayList(), new ResolvableIdentifier("String")); + + VariableAccess varAccess = new VariableAccess(buildPosition(), new ResolvableIdentifier("functionDeclaration")); + + MemberAccess memberAccess = new MemberAccess(buildPosition(), varAccess, intVariableAccess); + + WhileLoop loop = new WhileLoop(buildPosition(), memberAccess, new Block(buildPosition())); + + moduleBlock.addDeclaration(intVariable); + moduleBlock.addDeclaration(functionDeclaration); + moduleBlock.addStatement(loop); + + SPV.visit(aPackage); + DV.visit(aPackage); + RV.visit(aPackage); + TCV.visit(aPackage); + } + + @Test(expected = TypeMismatchException.class) + public void memberAccessTest02() { + // x 2: left löst nach classDeclaration auf, right ist conditional + ConditionalExpression conditionalExpression = + new ConditionalExpression(buildPosition(), booleanLiteral, strLiteral, strLiteral); + + VariableAccess varAccess = new VariableAccess(buildPosition(), new ResolvableIdentifier("classDeclaration")); + + MemberAccess memberAccess = new MemberAccess(buildPosition(), varAccess, conditionalExpression); + + WhileLoop loop = new WhileLoop(buildPosition(), memberAccess, new Block(buildPosition())); + + moduleBlock.addDeclaration(classDeclaration); + moduleBlock.addStatement(loop); + + SPV.visit(aPackage); + DV.visit(aPackage); + RV.visit(aPackage); + TCV.visit(aPackage); + } + + @Test(expected = TypeMismatchException.class) + public void memberAccessTest03() { + // x 3: left löst nach classDeclaration auf, right ist boolean + VariableAccess varAccess = new VariableAccess(buildPosition(), new ResolvableIdentifier("classDeclaration")); + + MemberAccess memberAccess = new MemberAccess(buildPosition(), varAccess, booleanLiteral); + + WhileLoop loop = new WhileLoop(buildPosition(), memberAccess, new Block(buildPosition())); + + moduleBlock.addDeclaration(classDeclaration); + moduleBlock.addStatement(loop); + + SPV.visit(aPackage); + DV.visit(aPackage); + RV.visit(aPackage); + TCV.visit(aPackage); + } + + @Test(expected = TypeMismatchException.class) + public void memberAccessTest04() { + // x 4: left löst nach classDeclaration auf, right ist string + VariableAccess varAccess = new VariableAccess(buildPosition(), new ResolvableIdentifier("classDeclaration")); + + MemberAccess memberAccess = new MemberAccess(buildPosition(), varAccess, strLiteral); + + WhileLoop loop = new WhileLoop(buildPosition(), memberAccess, new Block(buildPosition())); + + moduleBlock.addDeclaration(classDeclaration); + moduleBlock.addStatement(loop); + + SPV.visit(aPackage); + DV.visit(aPackage); + RV.visit(aPackage); + TCV.visit(aPackage); + } + + @Test(expected = TypeMismatchException.class) + public void memberAccessTest05() { + // x 5: left löst nach classDeclaration auf, right ist float + VariableAccess varAccess = new VariableAccess(buildPosition(), new ResolvableIdentifier("classDeclaration")); + + MemberAccess memberAccess = new MemberAccess(buildPosition(), varAccess, floatLiteral); + + WhileLoop loop = new WhileLoop(buildPosition(), memberAccess, new Block(buildPosition())); + + moduleBlock.addDeclaration(classDeclaration); + moduleBlock.addStatement(loop); + + SPV.visit(aPackage); + DV.visit(aPackage); + RV.visit(aPackage); + TCV.visit(aPackage); + } + + @Test(expected = TypeMismatchException.class) + public void memberAccessTest06() { + // x 6: left löst nach classDeclaration auf, right ist int + VariableAccess varAccess = new VariableAccess(buildPosition(), new ResolvableIdentifier("classDeclaration")); + + MemberAccess memberAccess = new MemberAccess(buildPosition(), varAccess, intLiteral); + + WhileLoop loop = new WhileLoop(buildPosition(), memberAccess, new Block(buildPosition())); + + moduleBlock.addDeclaration(classDeclaration); + moduleBlock.addStatement(loop); + + SPV.visit(aPackage); + DV.visit(aPackage); + RV.visit(aPackage); + TCV.visit(aPackage); + } + + @Test(expected = UnknownIdentifierException.class) + public void memberAccessTest07() { + // x 7: left löst nach classDeclaration auf, right ist nicht vorhandener + // ProcedureCall + VariableAccess varAccess = new VariableAccess(buildPosition(), new ResolvableIdentifier("classDeclaration")); + FunctionCall functionCall = + new FunctionCall(buildPosition(), new ResolvableIdentifier("invalid"), new ArrayList()); + + MemberAccess memberAccess = new MemberAccess(buildPosition(), varAccess, functionCall); + + WhileLoop loop = new WhileLoop(buildPosition(), memberAccess, new Block(buildPosition())); + + moduleBlock.addDeclaration(classDeclaration); + moduleBlock.addStatement(loop); + + SPV.visit(aPackage); + DV.visit(aPackage); + RV.visit(aPackage); + TCV.visit(aPackage); + } + + @Test(expected = UnknownIdentifierException.class) + public void memberAccessTest08() { + // x 8: left löst nach classDeclaration auf, right ist nicht vorhandener + // variableAccess + VariableAccess varAccess = new VariableAccess(buildPosition(), new ResolvableIdentifier("classDeclaration")); + VariableAccess rightVarAccess = new VariableAccess(buildPosition(), new ResolvableIdentifier("invalid")); + + MemberAccess memberAccess = new MemberAccess(buildPosition(), varAccess, rightVarAccess); + + WhileLoop loop = new WhileLoop(buildPosition(), memberAccess, new Block(buildPosition())); + + moduleBlock.addDeclaration(classDeclaration); + moduleBlock.addStatement(loop); + + SPV.visit(aPackage); + DV.visit(aPackage); + RV.visit(aPackage); + TCV.visit(aPackage); + } + + @Test(expected = TypeMismatchException.class) + public void memberAccessTest09() { + // y 9: left löst nach classDeclaration auf, right ist vorhandener + // ProcedureCall + VariableAccess varAccess = new VariableAccess(buildPosition(), new ResolvableIdentifier("classDeclaration")); + FunctionCall functionCall = + new FunctionCall(buildPosition(), new ResolvableIdentifier("classProcedureDeclaration"), + new ArrayList()); + + MemberAccess memberAccess = new MemberAccess(buildPosition(), varAccess, functionCall); + + WhileLoop loop = new WhileLoop(buildPosition(), memberAccess, new Block(buildPosition())); + + moduleBlock.addDeclaration(classDeclaration); + moduleBlock.addStatement(loop); + + SPV.visit(aPackage); + DV.visit(aPackage); + RV.visit(aPackage); + TCV.visit(aPackage); + } + + @Test(expected = TypeMismatchException.class) + public void memberAccessTest10() { + // y 10: left löst nach classDeclaration auf, right ist vorhandener + // variableAccess + VariableAccess varAccess = new VariableAccess(buildPosition(), new ResolvableIdentifier("classDeclaration")); + VariableAccess rightVarAccess = + new VariableAccess(buildPosition(), new ResolvableIdentifier("classVariableDeclaration")); + + MemberAccess memberAccess = new MemberAccess(buildPosition(), varAccess, rightVarAccess); + + WhileLoop loop = new WhileLoop(buildPosition(), memberAccess, new Block(buildPosition())); + + moduleBlock.addDeclaration(classDeclaration); + moduleBlock.addStatement(loop); + + SPV.visit(aPackage); + DV.visit(aPackage); + RV.visit(aPackage); + TCV.visit(aPackage); + } + + // FUNCTION CALL + @Test + public void functionCallTest() { + // FunctionCall with float returnType + Block functionBlock = new Block(nextPosition()); + functionBlock.addStatement(new ReturnStatement(nextPosition(), floatLiteral)); + FunctionDeclaration functionDeclaration = + new FunctionDeclaration(nextPosition(), new Identifier("functionWithReturn"), functionBlock, + new ArrayList(), new ResolvableIdentifier("Float")); + FunctionCall procedureCall = + new FunctionCall(nextPosition(), new ResolvableIdentifier("functionWithReturn"), + new ArrayList()); + + moduleBlock.addDeclaration(functionDeclaration); + moduleBlock.addStatement(procedureCall); + + SPV.visit(aPackage); + DV.visit(aPackage); + RV.visit(aPackage); + TCV.visit(aPackage); + } + + @Test + public void functionCallWithParamsTest() { + // Functioncall with int Returntype and matching int Paramters + List variables = new ArrayList(); + variables.add(intVariable); + List parameters = new ArrayList(); + parameters.add(intLiteral); + Block functionBlock = new Block(nextPosition()); + functionBlock.addStatement(new ReturnStatement(nextPosition(), intLiteral)); + FunctionDeclaration functionDeclaration = + new FunctionDeclaration(nextPosition(), new Identifier("functionWithParameters"), functionBlock, + variables, new ResolvableIdentifier("Int")); + FunctionCall procedureCall = + new FunctionCall(nextPosition(), new ResolvableIdentifier("functionWithParameters"), parameters); + + moduleBlock.addDeclaration(functionDeclaration); + moduleBlock.addStatement(procedureCall); + + SPV.visit(aPackage); + DV.visit(aPackage); + RV.visit(aPackage); + TCV.visit(aPackage); + } + + @Test(expected = TypeMismatchException.class) + public void functionCallWithParamsTest02() { + // Parameters from Declaration and Call doesn't match + List variables = new ArrayList(); + variables.add(intVariable); + List parameters = new ArrayList(); + parameters.add(strLiteral); + Block functionBlock = new Block(nextPosition()); + functionBlock.addStatement(new ReturnStatement(nextPosition(), intLiteral)); + + FunctionDeclaration functionDeclaration = + new FunctionDeclaration(nextPosition(), new Identifier("functionWithParameters02"), functionBlock, + variables, new ResolvableIdentifier("Int")); + FunctionCall procedureCall = + new FunctionCall(nextPosition(), new ResolvableIdentifier("functionWithParameters02"), parameters); + + moduleBlock.addDeclaration(functionDeclaration); + moduleBlock.addStatement(procedureCall); + + SPV.visit(aPackage); + DV.visit(aPackage); + RV.visit(aPackage); + TCV.visit(aPackage); + } + + @Test(expected = TypeMismatchException.class) + public void functionCallWithParamsTest03() { + // Count of paramters in the FunctionCall does not match the declaration + List variables = new ArrayList(); + variables.add(intVariable); + variables.add(floatVariable); + List parameters = new ArrayList(); + parameters.add(intLiteral); + Block functionBlock = new Block(nextPosition()); + functionBlock.addStatement(new ReturnStatement(nextPosition(), intLiteral)); + + FunctionDeclaration functionDeclaration = + new FunctionDeclaration(nextPosition(), new Identifier("functionWithParameters03"), functionBlock, + variables, new ResolvableIdentifier("Int")); + FunctionCall procedureCall = + new FunctionCall(nextPosition(), new ResolvableIdentifier("functionWithParameters03"), parameters); + + moduleBlock.addDeclaration(functionDeclaration); + moduleBlock.addStatement(procedureCall); + + SPV.visit(aPackage); + DV.visit(aPackage); + RV.visit(aPackage); + TCV.visit(aPackage); + } + + @Test(expected = TypeMismatchException.class) + public void functionCallWithParamsTest04() { + // Count of paramters in the FunctionCall does not match the declaration + List variables = new ArrayList(); + variables.add(floatVariable); + List parameters = new ArrayList(); + parameters.add(floatLiteral); + parameters.add(strLiteral); + Block functionBlock = new Block(nextPosition()); + functionBlock.addStatement(new ReturnStatement(nextPosition(), intLiteral)); + + FunctionDeclaration functionDeclaration = + new FunctionDeclaration(nextPosition(), new Identifier("functionWithParameters04"), functionBlock, + variables, new ResolvableIdentifier("Int")); + FunctionCall procedureCall = + new FunctionCall(nextPosition(), new ResolvableIdentifier("functionWithParameters04"), parameters); + + moduleBlock.addDeclaration(functionDeclaration); + moduleBlock.addStatement(procedureCall); + + SPV.visit(aPackage); + DV.visit(aPackage); + RV.visit(aPackage); + TCV.visit(aPackage); + } + + @Test(expected = TypeMismatchException.class) + public void functionCallWithParamsTest05() { + // Count of paramters in the FunctionCall does not match the declaration + List variables = new ArrayList(); + List parameters = new ArrayList(); + parameters.add(floatLiteral); + parameters.add(strLiteral); + Block functionBlock = new Block(nextPosition()); + functionBlock.addStatement(new ReturnStatement(nextPosition(), floatLiteral)); + + FunctionDeclaration functionDeclaration = + new FunctionDeclaration(nextPosition(), new Identifier("functionWithParameters05"), functionBlock, + variables, new ResolvableIdentifier("Float")); + FunctionCall procedureCall = + new FunctionCall(nextPosition(), new ResolvableIdentifier("functionWithParameters05"), parameters); + + moduleBlock.addDeclaration(functionDeclaration); + moduleBlock.addStatement(procedureCall); + + SPV.visit(aPackage); + DV.visit(aPackage); + RV.visit(aPackage); + TCV.visit(aPackage); + } + + @Test(expected = TypeMismatchException.class) + public void functionCallWithParamsTest06() { + // Count of paramters in the FunctionCall does not match the declaration + List variables = new ArrayList(); + List parameters = new ArrayList(); + parameters.add(floatLiteral); + parameters.add(strLiteral); + Block functionBlock = new Block(nextPosition()); + functionBlock.addStatement(new ReturnStatement(nextPosition(), strLiteral)); + + FunctionDeclaration functionDeclaration = + new FunctionDeclaration(nextPosition(), new Identifier("functionWithParameters06"), functionBlock, + variables, new ResolvableIdentifier("String")); + FunctionCall procedureCall = + new FunctionCall(nextPosition(), new ResolvableIdentifier("functionWithParameters06"), parameters); + + moduleBlock.addDeclaration(functionDeclaration); + moduleBlock.addStatement(procedureCall); + + SPV.visit(aPackage); + DV.visit(aPackage); + RV.visit(aPackage); + TCV.visit(aPackage); + } + + @Test(expected = TypeMismatchException.class) + public void functionCallWithParamsTest07() { + // ReturnStatement type doesn't match Return Type in Declaration + Block functionBlock = new Block(nextPosition()); + functionBlock.addStatement(new ReturnStatement(nextPosition(), strLiteral)); + + FunctionDeclaration functionDeclaration = + new FunctionDeclaration(nextPosition(), new Identifier("functionWithParameters06"), functionBlock, + new ArrayList(), new ResolvableIdentifier("Int")); + FunctionCall procedureCall = + new FunctionCall(nextPosition(), new ResolvableIdentifier("functionWithParameters06"), + new ArrayList()); + + moduleBlock.addDeclaration(functionDeclaration); + moduleBlock.addStatement(procedureCall); + + SPV.visit(aPackage); + DV.visit(aPackage); + RV.visit(aPackage); + TCV.visit(aPackage); + } + + // PROCEDURE CALL + + @Test + public void procedureCallTest() { + // ProcedureCall with matching Declaration + ProcedureDeclaration procedureDeclaration = + new ProcedureDeclaration(nextPosition(), new Identifier("procedure"), new Block(nextPosition()), + new ArrayList()); + FunctionCall procedureCall = + new FunctionCall(nextPosition(), new ResolvableIdentifier("procedure"), new ArrayList()); + + moduleBlock.addDeclaration(procedureDeclaration); + moduleBlock.addStatement(procedureCall); + + SPV.visit(aPackage); + DV.visit(aPackage); + RV.visit(aPackage); + TCV.visit(aPackage); + } + + @Test + public void procedureCallWithParamsTest() { + // ProcedureCall and Declaration with matching types + List variables = new ArrayList(); + variables.add(strVariable); + List parameters = new ArrayList(); + parameters.add(strLiteral); + + ProcedureDeclaration procedureDeclaration = + new ProcedureDeclaration(nextPosition(), new Identifier("procedureWithParams"), new Block( + nextPosition()), variables); + FunctionCall procedureCall = + new FunctionCall(nextPosition(), new ResolvableIdentifier("procedureWithParams"), parameters); + + moduleBlock.addDeclaration(procedureDeclaration); + moduleBlock.addStatement(procedureCall); + + SPV.visit(aPackage); + DV.visit(aPackage); + RV.visit(aPackage); + TCV.visit(aPackage); + } + + @Test(expected = TypeMismatchException.class) + public void procedureCallWithParamsTest02() { + // Parameters from Declaration and Call doesn't match + List variables = new ArrayList(); + variables.add(strVariable); + List parameters = new ArrayList(); + parameters.add(floatLiteral); + + ProcedureDeclaration procedureDeclaration = + new ProcedureDeclaration(nextPosition(), new Identifier("procedureWithParams02"), new Block( + nextPosition()), variables); + FunctionCall procedureCall = + new FunctionCall(nextPosition(), new ResolvableIdentifier("procedureWithParams02"), parameters); + + moduleBlock.addDeclaration(procedureDeclaration); + moduleBlock.addStatement(procedureCall); + + SPV.visit(aPackage); + DV.visit(aPackage); + RV.visit(aPackage); + TCV.visit(aPackage); + } + + @Test(expected = TypeMismatchException.class) + public void procedureCallWithParamsTest03() { + // Count of paramters in the ProcedureCall does not match the + // declaration + List variables = new ArrayList(); + variables.add(strVariable); + variables.add(intVariable); + List parameters = new ArrayList(); + parameters.add(strLiteral); + + ProcedureDeclaration procedureDeclaration = + new ProcedureDeclaration(nextPosition(), new Identifier("procedureWithParams03"), new Block( + nextPosition()), variables); + FunctionCall procedureCall = + new FunctionCall(nextPosition(), new ResolvableIdentifier("procedureWithParams03"), parameters); + + moduleBlock.addDeclaration(procedureDeclaration); + moduleBlock.addStatement(procedureCall); + + SPV.visit(aPackage); + DV.visit(aPackage); + RV.visit(aPackage); + TCV.visit(aPackage); + } + + @Test(expected = TypeMismatchException.class) + public void procedureCallWithParamsTest04() { + // Count of paramters in the ProcedureCall does not match the + // declaration + List variables = new ArrayList(); + variables.add(strVariable); + List parameters = new ArrayList(); + parameters.add(strLiteral); + parameters.add(intLiteral); + + ProcedureDeclaration procedureDeclaration = + new ProcedureDeclaration(nextPosition(), new Identifier("procedureWithParams04"), new Block( + nextPosition()), variables); + FunctionCall procedureCall = + new FunctionCall(nextPosition(), new ResolvableIdentifier("procedureWithParams04"), parameters); + + moduleBlock.addDeclaration(procedureDeclaration); + moduleBlock.addStatement(procedureCall); + + SPV.visit(aPackage); + DV.visit(aPackage); + RV.visit(aPackage); + TCV.visit(aPackage); + } + + @Test(expected = TypeMismatchException.class) + public void procedureCallWithParamsTest05() { + // Count of paramters in the ProcedureCall does not match the + // declaration + List variables = new ArrayList(); + variables.add(strVariable); + List parameters = new ArrayList(); + + ProcedureDeclaration procedureDeclaration = + new ProcedureDeclaration(nextPosition(), new Identifier("procedureWithParams05"), new Block( + nextPosition()), variables); + FunctionCall procedureCall = + new FunctionCall(nextPosition(), new ResolvableIdentifier("procedureWithParams05"), parameters); + + moduleBlock.addDeclaration(procedureDeclaration); + moduleBlock.addStatement(procedureCall); + + SPV.visit(aPackage); + DV.visit(aPackage); + RV.visit(aPackage); + TCV.visit(aPackage); + } + + @Test(expected = TypeMismatchException.class) + public void procedureCallWithParamsTest06() { + // Count of paramters in the ProcedureCall does not match the + // declaration + List variables = new ArrayList(); + List parameters = new ArrayList(); + parameters.add(intLiteral); + + ProcedureDeclaration procedureDeclaration = + new ProcedureDeclaration(nextPosition(), new Identifier("procedureWithParams06"), new Block( + nextPosition()), variables); + FunctionCall procedureCall = + new FunctionCall(nextPosition(), new ResolvableIdentifier("procedureWithParams06"), parameters); + + moduleBlock.addDeclaration(procedureDeclaration); + moduleBlock.addStatement(procedureCall); + + SPV.visit(aPackage); + DV.visit(aPackage); + RV.visit(aPackage); + TCV.visit(aPackage); + } + + // CONDITIONAL STATEMENT + @Test + public void conditionalTestBooleanCondition() { + ConditionalStatement conditionalStatement = + new ConditionalStatement(buildPosition(), booleanLiteral, new Block(buildPosition()), new Block( + buildPosition())); + + moduleBlock.addStatement(conditionalStatement); + + SPV.visit(aPackage); + DV.visit(aPackage); + RV.visit(aPackage); + TCV.visit(aPackage); + } + + @Test(expected = TypeMismatchException.class) + public void conditionalTestNotBooleanCondition() { + ConditionalStatement conditionalStatement = + new ConditionalStatement(buildPosition(), strLiteral, new Block(buildPosition()), new Block( + buildPosition())); + + moduleBlock.addStatement(conditionalStatement); + + SPV.visit(aPackage); + DV.visit(aPackage); + RV.visit(aPackage); + TCV.visit(aPackage); + } + + // CONDITIONAL EXPRESSION + + @Test + public void conditionalExpressionTestCorrectConditionalExpression() { + // thenExpression matches elseExpression + ConditionalExpression conditionalExpression = + new ConditionalExpression(buildPosition(), booleanLiteral, strLiteral, strLiteral); + Assignment conditionalAssignment = new Assignment(buildPosition(), strVariableAccess, conditionalExpression); + + moduleBlock.addDeclaration(strVariable); + moduleBlock.addStatement(conditionalAssignment); + + SPV.visit(aPackage); + DV.visit(aPackage); + RV.visit(aPackage); + TCV.visit(aPackage); + } + + @Test(expected = TypeMismatchException.class) + public void conditionalExpressionTestNotBooleanCondition() { + ConditionalExpression conditionalExpression = + new ConditionalExpression(buildPosition(), intLiteral, strLiteral, strLiteral); + Assignment conditionalAssignment = new Assignment(buildPosition(), strVariableAccess, conditionalExpression); + + moduleBlock.addDeclaration(strVariable); + moduleBlock.addStatement(conditionalAssignment); + + SPV.visit(aPackage); + DV.visit(aPackage); + RV.visit(aPackage); + TCV.visit(aPackage); + } + + @Test(expected = TypeMismatchException.class) + public void conditionalExpressionTestThenElseMismatches() { + // thenExpression mismatches elseExpression + ConditionalExpression conditionalExpression = + new ConditionalExpression(buildPosition(), booleanLiteral, strLiteral, intLiteral); + Assignment conditionalAssignment = new Assignment(buildPosition(), strVariableAccess, conditionalExpression); + + moduleBlock.addDeclaration(strVariable); + moduleBlock.addStatement(conditionalAssignment); + + SPV.visit(aPackage); + DV.visit(aPackage); + RV.visit(aPackage); + TCV.visit(aPackage); + } +} diff --git a/src/test/java/de/uni/bremen/monty/moco/codegeneration/ContextTest.java b/src/test/java/de/uni/bremen/monty/moco/codegeneration/ContextTest.java new file mode 100644 index 0000000..ca91350 --- /dev/null +++ b/src/test/java/de/uni/bremen/monty/moco/codegeneration/ContextTest.java @@ -0,0 +1,113 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.codegeneration; + +import de.uni.bremen.monty.moco.codegeneration.context.CommentAppender; +import de.uni.bremen.monty.moco.codegeneration.context.Context; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.startsWith; +import static org.mockito.AdditionalAnswers.returnsFirstArg; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.when; + +@RunWith(MockitoJUnitRunner.class) +public class ContextTest { + + @Mock + CommentAppender commentAppender; + + @Before + public void setUp() throws Exception { + when(commentAppender.addComment(anyString())).then(returnsFirstArg()); + } + + @Test + public void shouldContainSimpleString() throws Exception { + String testString = "print xxx"; + + Context context = new Context(commentAppender); + context.append(testString); + + assertThat(context.getData(), startsWith(testString)); + } + + @Test + public void shouldContainAnotherContext() throws Exception { + String testString = "call xxx"; + + Context context1 = new Context(commentAppender); + Context context2 = new Context(commentAppender); + context1.append(context2); + context2.append(testString); + + assertThat(context1.getData(), startsWith(testString)); + } + + @Test + public void shouldContainMultpleChildren() throws Exception { + + Context context1 = new Context(commentAppender); + Context context2 = new Context(commentAppender); + Context context3 = new Context(commentAppender); + Context context4 = new Context(commentAppender); + Context context5 = new Context(commentAppender); + + context1.append(context2); + context1.append(context3); + context1.append("World"); + context1.append(context5); + context3.append(context4); + + context2.append("!"); + context4.append("Hello "); + context3.append("pretty "); + + context5.append("!"); + + assertThat(context1.getData(), is("!\nHello \npretty \nWorld\n!\n")); + } + +} diff --git a/src/test/java/de/uni/bremen/monty/moco/util/MultiOutputStream.java b/src/test/java/de/uni/bremen/monty/moco/util/MultiOutputStream.java new file mode 100644 index 0000000..8f4f20f --- /dev/null +++ b/src/test/java/de/uni/bremen/monty/moco/util/MultiOutputStream.java @@ -0,0 +1,57 @@ +/* + * moco, the Monty Compiler + * Copyright (c) 2013-2014, Monty's Coconut, All rights reserved. + * + * This file is part of moco, the Monty Compiler. + * + * moco 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.0 of the License, or (at your option) any later version. + * + * moco 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. + * + * Linking this program and/or its accompanying libraries statically or + * dynamically with other modules is making a combined work based on this + * program. Thus, the terms and conditions of the GNU General Public License + * cover the whole combination. + * + * As a special exception, the copyright holders of moco give + * you permission to link this programm and/or its accompanying libraries + * with independent modules to produce an executable, regardless of the + * license terms of these independent modules, and to copy and distribute the + * resulting executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. + * + * An independent module is a module which is not + * derived from or based on this program and/or its accompanying libraries. + * If you modify this library, you may extend this exception to your version of + * the program or library, but you are not obliged to do so. If you do not wish + * to do so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public + * License along with this library. + */ +package de.uni.bremen.monty.moco.util; + +import java.io.IOException; +import java.io.OutputStream; + +public class MultiOutputStream extends OutputStream { + private OutputStream[] streams; + + public MultiOutputStream(OutputStream... streams) { + this.streams = streams; + } + + @Override + public void write(int b) throws IOException { + for (OutputStream stream : streams) { + stream.write(b); + } + } +} diff --git a/src/test/resources/testAstBuilder/declarationType.monty b/src/test/resources/testAstBuilder/declarationType.monty new file mode 100644 index 0000000..dbb7d14 --- /dev/null +++ b/src/test/resources/testAstBuilder/declarationType.monty @@ -0,0 +1,19 @@ +class Ab: + + String x + + + Float y := 2.4 + + + proc1(Int t): + pass + + + String func1(Bool b): + pass + +Float f +String s := "" + +Int func2(Bool b): + pass + +proc2(Int t): + pass \ No newline at end of file diff --git a/src/test/resources/testAstBuilder/ifElse.monty b/src/test/resources/testAstBuilder/ifElse.monty new file mode 100644 index 0000000..9752784 --- /dev/null +++ b/src/test/resources/testAstBuilder/ifElse.monty @@ -0,0 +1,30 @@ +if a: + p(1) + +if a: + p(1) +else: + p(2) + +if a: + p(1) +elif b: + p(2) +else: + p(3) + +if a: + p(1) +elif b: + p(2) +elif c: + p(3) +else: + p(4) + +if a: + p(1) +elif b: + p(2) +elif c: + p(3) \ No newline at end of file diff --git a/src/test/resources/testAstBuilder/varDecl.monty b/src/test/resources/testAstBuilder/varDecl.monty new file mode 100644 index 0000000..516f262 --- /dev/null +++ b/src/test/resources/testAstBuilder/varDecl.monty @@ -0,0 +1 @@ +String s := "Hallo" \ No newline at end of file diff --git a/src/test/resources/testModuleProgramms/de/dafuq/monty/HelloSayer.monty b/src/test/resources/testModuleProgramms/de/dafuq/monty/HelloSayer.monty new file mode 100644 index 0000000..377820a --- /dev/null +++ b/src/test/resources/testModuleProgramms/de/dafuq/monty/HelloSayer.monty @@ -0,0 +1,11 @@ +// Testing: Functioncall from different Module +// +// The function sayHello is called in Main.monty and it calls +// the function montySays() of module Main.monty +// +// Expected result: see Main.monty + +String sayHello(): + return "Hello" + +print(montySays("says: ")) \ No newline at end of file diff --git a/src/test/resources/testModuleProgramms/de/dafuq/monty/Main.monty b/src/test/resources/testModuleProgramms/de/dafuq/monty/Main.monty new file mode 100644 index 0000000..d912540 --- /dev/null +++ b/src/test/resources/testModuleProgramms/de/dafuq/monty/Main.monty @@ -0,0 +1,13 @@ +// Testing: Functioncall from different Module +// +// The print function calls the function sayHello() in the module +// HelloSayer.monty +// +// Expected result: Monty says: Hello +String montySays(String s): + print("Monty ") + return s + +print(sayHello()) + + diff --git a/src/test/resources/testModuleProgramms/de/dafuq/monty/Main.output b/src/test/resources/testModuleProgramms/de/dafuq/monty/Main.output new file mode 100644 index 0000000..465fed5 --- /dev/null +++ b/src/test/resources/testModuleProgramms/de/dafuq/monty/Main.output @@ -0,0 +1 @@ +Monty says: Hello \ No newline at end of file diff --git a/src/test/resources/testPrograms/CorePackage.monty b/src/test/resources/testPrograms/CorePackage.monty new file mode 100644 index 0000000..adbf383 --- /dev/null +++ b/src/test/resources/testPrograms/CorePackage.monty @@ -0,0 +1,5 @@ +// Testing: Operater Precedence +// +// Expected Output: 2 + +print(1+2*3/4) \ No newline at end of file diff --git a/src/test/resources/testPrograms/CorePackage.output b/src/test/resources/testPrograms/CorePackage.output new file mode 100644 index 0000000..d8263ee --- /dev/null +++ b/src/test/resources/testPrograms/CorePackage.output @@ -0,0 +1 @@ +2 \ No newline at end of file diff --git a/src/test/resources/testPrograms/array/ArrayEmptyInit.monty.ignore b/src/test/resources/testPrograms/array/ArrayEmptyInit.monty.ignore new file mode 100644 index 0000000..d072792 --- /dev/null +++ b/src/test/resources/testPrograms/array/ArrayEmptyInit.monty.ignore @@ -0,0 +1,7 @@ +// Testing: Arrays +// +// An emtpy array must be initializable. +// +// Expected output: + +Array a := [] diff --git a/src/test/resources/testPrograms/array/ArrayEmptyInit.output b/src/test/resources/testPrograms/array/ArrayEmptyInit.output new file mode 100644 index 0000000..e69de29 diff --git a/src/test/resources/testPrograms/array/ArrayEmptyRead.error b/src/test/resources/testPrograms/array/ArrayEmptyRead.error new file mode 100644 index 0000000..e69de29 diff --git a/src/test/resources/testPrograms/array/ArrayEmptyRead.monty.ignore b/src/test/resources/testPrograms/array/ArrayEmptyRead.monty.ignore new file mode 100644 index 0000000..5d4ba1e --- /dev/null +++ b/src/test/resources/testPrograms/array/ArrayEmptyRead.monty.ignore @@ -0,0 +1,8 @@ +// Testing: Arrays +// +// A read of an empty array must yield an error. +// +// Expected error + +Array a := [] +print(a[0]) diff --git a/src/test/resources/testPrograms/array/ArrayEmptyWrite.error b/src/test/resources/testPrograms/array/ArrayEmptyWrite.error new file mode 100644 index 0000000..e69de29 diff --git a/src/test/resources/testPrograms/array/ArrayEmptyWrite.monty.ignore b/src/test/resources/testPrograms/array/ArrayEmptyWrite.monty.ignore new file mode 100644 index 0000000..fb39fec --- /dev/null +++ b/src/test/resources/testPrograms/array/ArrayEmptyWrite.monty.ignore @@ -0,0 +1,8 @@ +// Testing: Arrays +// +// A write into an empty array must yield an error. +// +// Expected error + +Array a := [] +a[0] := 0 diff --git a/src/test/resources/testPrograms/array/ArrayMany.monty.ignore b/src/test/resources/testPrograms/array/ArrayMany.monty.ignore new file mode 100644 index 0000000..7e38839 --- /dev/null +++ b/src/test/resources/testPrograms/array/ArrayMany.monty.ignore @@ -0,0 +1,25 @@ +// Testing: Arrays +// +// Read/Write with an array of some big size must work. +// +// Expected output: 101112131415202122232425 + +Array a := [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] +print(a[10]) +print(a[11]) +print(a[12]) +print(a[13]) +print(a[14]) +print(a[15]) +a[10] := 20 +a[11] := 21 +a[12] := 22 +a[13] := 23 +a[14] := 24 +a[15] := 25 +print(a[10]) +print(a[11]) +print(a[12]) +print(a[13]) +print(a[14]) +print(a[15]) diff --git a/src/test/resources/testPrograms/array/ArrayMany.output b/src/test/resources/testPrograms/array/ArrayMany.output new file mode 100644 index 0000000..b1634b2 --- /dev/null +++ b/src/test/resources/testPrograms/array/ArrayMany.output @@ -0,0 +1 @@ +101112131415202122232425 \ No newline at end of file diff --git a/src/test/resources/testPrograms/array/ArrayOne.monty.ignore b/src/test/resources/testPrograms/array/ArrayOne.monty.ignore new file mode 100644 index 0000000..28bf70a --- /dev/null +++ b/src/test/resources/testPrograms/array/ArrayOne.monty.ignore @@ -0,0 +1,10 @@ +// Testing: Arrays +// +// Read/Write with an array of size 1 must work. +// +// Expected output: 010 + +Array a := [0] +print(a[0]) +a[0] := 10 +print(a[0]) diff --git a/src/test/resources/testPrograms/array/ArrayOne.output b/src/test/resources/testPrograms/array/ArrayOne.output new file mode 100644 index 0000000..fc06c8b --- /dev/null +++ b/src/test/resources/testPrograms/array/ArrayOne.output @@ -0,0 +1 @@ +010 \ No newline at end of file diff --git a/src/test/resources/testPrograms/array/ArrayOutOfBounds1.error b/src/test/resources/testPrograms/array/ArrayOutOfBounds1.error new file mode 100644 index 0000000..e69de29 diff --git a/src/test/resources/testPrograms/array/ArrayOutOfBounds1.monty.ignore b/src/test/resources/testPrograms/array/ArrayOutOfBounds1.monty.ignore new file mode 100644 index 0000000..3b4e8e6 --- /dev/null +++ b/src/test/resources/testPrograms/array/ArrayOutOfBounds1.monty.ignore @@ -0,0 +1,8 @@ +// Testing: Arrays +// +// A write into an empty array must yield an error. +// +// Expected error + +Array a := [0, 1] +print(a[-1]) diff --git a/src/test/resources/testPrograms/array/ArrayOutOfBounds2.error b/src/test/resources/testPrograms/array/ArrayOutOfBounds2.error new file mode 100644 index 0000000..e69de29 diff --git a/src/test/resources/testPrograms/array/ArrayOutOfBounds2.monty.ignore b/src/test/resources/testPrograms/array/ArrayOutOfBounds2.monty.ignore new file mode 100644 index 0000000..6743263 --- /dev/null +++ b/src/test/resources/testPrograms/array/ArrayOutOfBounds2.monty.ignore @@ -0,0 +1,8 @@ +// Testing: Arrays +// +// A write out of bounds must yield an error. +// +// Expected error + +Array a := [0, 1] +a[-1] := 42 diff --git a/src/test/resources/testPrograms/array/ArrayOutOfBounds3.error b/src/test/resources/testPrograms/array/ArrayOutOfBounds3.error new file mode 100644 index 0000000..e69de29 diff --git a/src/test/resources/testPrograms/array/ArrayOutOfBounds3.monty.ignore b/src/test/resources/testPrograms/array/ArrayOutOfBounds3.monty.ignore new file mode 100644 index 0000000..f8c5bcb --- /dev/null +++ b/src/test/resources/testPrograms/array/ArrayOutOfBounds3.monty.ignore @@ -0,0 +1,8 @@ +// Testing: Arrays +// +// A read out of bounds must yield an error. +// +// Expected error + +Array a := [0, 1] +print(a[42]) diff --git a/src/test/resources/testPrograms/array/ArrayOutOfBounds4.error b/src/test/resources/testPrograms/array/ArrayOutOfBounds4.error new file mode 100644 index 0000000..e69de29 diff --git a/src/test/resources/testPrograms/array/ArrayOutOfBounds4.monty.ignore b/src/test/resources/testPrograms/array/ArrayOutOfBounds4.monty.ignore new file mode 100644 index 0000000..4b533b9 --- /dev/null +++ b/src/test/resources/testPrograms/array/ArrayOutOfBounds4.monty.ignore @@ -0,0 +1,8 @@ +// Testing: Arrays +// +// A write out of bounds must yield an error. +// +// Expected error + +Array a := [0, 1] +a[42] := 42 diff --git a/src/test/resources/testPrograms/array/ArrayTwo.monty.ignore b/src/test/resources/testPrograms/array/ArrayTwo.monty.ignore new file mode 100644 index 0000000..c0bc1a1 --- /dev/null +++ b/src/test/resources/testPrograms/array/ArrayTwo.monty.ignore @@ -0,0 +1,13 @@ +// Testing: Arrays +// +// Read/Write with an array of size 2 must work. +// +// Expected output: 011011 + +Array a := [0, 1] +print(a[0]) +print(a[1]) +a[0] := 10 +a[1] := 11 +print(a[0]) +print(a[1]) diff --git a/src/test/resources/testPrograms/array/ArrayTwo.output b/src/test/resources/testPrograms/array/ArrayTwo.output new file mode 100644 index 0000000..0969ac7 --- /dev/null +++ b/src/test/resources/testPrograms/array/ArrayTwo.output @@ -0,0 +1 @@ +011011 \ No newline at end of file diff --git a/src/test/resources/testPrograms/callable/Function.monty b/src/test/resources/testPrograms/callable/Function.monty new file mode 100644 index 0000000..1d8997f --- /dev/null +++ b/src/test/resources/testPrograms/callable/Function.monty @@ -0,0 +1,11 @@ +// Testing: FunctionDeclaration and FunctionCall +// +// The function must be called correctly and return the evaluated return +// expression. +// +// Expected output: 4 + +Int square(Int value): + return value * value + +print(square(2)) diff --git a/src/test/resources/testPrograms/callable/Function.output b/src/test/resources/testPrograms/callable/Function.output new file mode 100644 index 0000000..bf0d87a --- /dev/null +++ b/src/test/resources/testPrograms/callable/Function.output @@ -0,0 +1 @@ +4 \ No newline at end of file diff --git a/src/test/resources/testPrograms/callable/Function1.monty b/src/test/resources/testPrograms/callable/Function1.monty new file mode 100644 index 0000000..1d8997f --- /dev/null +++ b/src/test/resources/testPrograms/callable/Function1.monty @@ -0,0 +1,11 @@ +// Testing: FunctionDeclaration and FunctionCall +// +// The function must be called correctly and return the evaluated return +// expression. +// +// Expected output: 4 + +Int square(Int value): + return value * value + +print(square(2)) diff --git a/src/test/resources/testPrograms/callable/Function1.output b/src/test/resources/testPrograms/callable/Function1.output new file mode 100644 index 0000000..bf0d87a --- /dev/null +++ b/src/test/resources/testPrograms/callable/Function1.output @@ -0,0 +1 @@ +4 \ No newline at end of file diff --git a/src/test/resources/testPrograms/callable/Function2.monty b/src/test/resources/testPrograms/callable/Function2.monty new file mode 100644 index 0000000..2198971 --- /dev/null +++ b/src/test/resources/testPrograms/callable/Function2.monty @@ -0,0 +1,21 @@ +// Testing: Nested FunctionDeclaration, FunctionCall, multiplication +// +// The function must be called correctly and return the evaluated return +// expression. +// +// Expected output: 16 + +Int calc(Int value1, Int value2): + + Int identity(Int x): + return x + + Int two(): + return 2 + + Int square(Int x): + return 2 * x + + return identity(value1) * two() * square(value2) + +print(calc(2,2)) \ No newline at end of file diff --git a/src/test/resources/testPrograms/callable/Function2.output b/src/test/resources/testPrograms/callable/Function2.output new file mode 100644 index 0000000..19c7bdb --- /dev/null +++ b/src/test/resources/testPrograms/callable/Function2.output @@ -0,0 +1 @@ +16 \ No newline at end of file diff --git a/src/test/resources/testPrograms/callable/Function3.monty b/src/test/resources/testPrograms/callable/Function3.monty new file mode 100644 index 0000000..20d3003 --- /dev/null +++ b/src/test/resources/testPrograms/callable/Function3.monty @@ -0,0 +1,20 @@ +// Testing: Nested FunctionDeclaration, FunctionCall, multiplication, addition +// +// The function must be called correctly and return the evaluated return +// expression. +// +// Expected output: 16 + +Int calc(Int value1, Int value2): + + Int identity(Int x): + return x + + Int two(): + return 2 + + Int square(Int x): + return 2 * x + return identity(value1) + two() + square(value2) + 8 + +print(calc(2,2)) \ No newline at end of file diff --git a/src/test/resources/testPrograms/callable/Function3.output b/src/test/resources/testPrograms/callable/Function3.output new file mode 100644 index 0000000..19c7bdb --- /dev/null +++ b/src/test/resources/testPrograms/callable/Function3.output @@ -0,0 +1 @@ +16 \ No newline at end of file diff --git a/src/test/resources/testPrograms/callable/Function4.monty b/src/test/resources/testPrograms/callable/Function4.monty new file mode 100644 index 0000000..9b2cf7e --- /dev/null +++ b/src/test/resources/testPrograms/callable/Function4.monty @@ -0,0 +1,19 @@ +// Testing: Nested FunctionDeclaration, FunctionCall, ConditionalStatement +// +// The function must be called correctly and return the evaluated return +// expression. +// +// Expected output: 42 + +Int identity(Int x): + return x + +Int square(Int x): + if x < 3: + return identity(4) + else: + return identity(2) + return 9000 // this is needed at the moment, should be fixed + +print(square(2)) +print(square(100)) \ No newline at end of file diff --git a/src/test/resources/testPrograms/callable/Function4.output b/src/test/resources/testPrograms/callable/Function4.output new file mode 100644 index 0000000..f70d7bb --- /dev/null +++ b/src/test/resources/testPrograms/callable/Function4.output @@ -0,0 +1 @@ +42 \ No newline at end of file diff --git a/src/test/resources/testPrograms/callable/FunctionGlobalLocalBoolean.monty b/src/test/resources/testPrograms/callable/FunctionGlobalLocalBoolean.monty new file mode 100644 index 0000000..77183b3 --- /dev/null +++ b/src/test/resources/testPrograms/callable/FunctionGlobalLocalBoolean.monty @@ -0,0 +1,12 @@ +// Testing: VariableDeclaration, VariableAccess, FunctionCall +// +// A global boolean variable as parameter and local copy as return value. +// +// Expected output: 1 + +Bool function(Bool var): + Bool copy := var + return copy + +Bool var := true +print(function(var)) diff --git a/src/test/resources/testPrograms/callable/FunctionGlobalLocalBoolean.output b/src/test/resources/testPrograms/callable/FunctionGlobalLocalBoolean.output new file mode 100644 index 0000000..56a6051 --- /dev/null +++ b/src/test/resources/testPrograms/callable/FunctionGlobalLocalBoolean.output @@ -0,0 +1 @@ +1 \ No newline at end of file diff --git a/src/test/resources/testPrograms/callable/FunctionGlobalLocalFloat.monty b/src/test/resources/testPrograms/callable/FunctionGlobalLocalFloat.monty new file mode 100644 index 0000000..80a19a0 --- /dev/null +++ b/src/test/resources/testPrograms/callable/FunctionGlobalLocalFloat.monty @@ -0,0 +1,12 @@ +// Testing: VariableDeclaration, VariableAccess, FunctionCall +// +// A global float variable as parameter and local copy as return value. +// +// Expected output: 1.3 + +Float function(Float var): + Float copy := var + return copy + +Float var := 1.3 +print(function(var)) diff --git a/src/test/resources/testPrograms/callable/FunctionGlobalLocalFloat.output b/src/test/resources/testPrograms/callable/FunctionGlobalLocalFloat.output new file mode 100644 index 0000000..a58941b --- /dev/null +++ b/src/test/resources/testPrograms/callable/FunctionGlobalLocalFloat.output @@ -0,0 +1 @@ +1.3 \ No newline at end of file diff --git a/src/test/resources/testPrograms/callable/FunctionGlobalLocalInt.monty b/src/test/resources/testPrograms/callable/FunctionGlobalLocalInt.monty new file mode 100644 index 0000000..1145ce4 --- /dev/null +++ b/src/test/resources/testPrograms/callable/FunctionGlobalLocalInt.monty @@ -0,0 +1,12 @@ +// Testing: VariableDeclaration, VariableAccess, FunctionCall +// +// A global int variable as parameter and local copy as return value. +// +// Expected output: 42 + +Int function(Int var): + Int copy := var + return copy + +Int var := 42 +print(function(var)) diff --git a/src/test/resources/testPrograms/callable/FunctionGlobalLocalInt.output b/src/test/resources/testPrograms/callable/FunctionGlobalLocalInt.output new file mode 100644 index 0000000..f70d7bb --- /dev/null +++ b/src/test/resources/testPrograms/callable/FunctionGlobalLocalInt.output @@ -0,0 +1 @@ +42 \ No newline at end of file diff --git a/src/test/resources/testPrograms/callable/FunctionGlobalLocalString.monty b/src/test/resources/testPrograms/callable/FunctionGlobalLocalString.monty new file mode 100644 index 0000000..076b37d --- /dev/null +++ b/src/test/resources/testPrograms/callable/FunctionGlobalLocalString.monty @@ -0,0 +1,12 @@ +// Testing: VariableDeclaration, VariableAccess, FunctionCall +// +// A global string variable as parameter and local copy as return value. +// +// Expected output: Hallo + +String function(String var): + String copy := var + return copy + +String var := "Hallo" +print(function(var)) diff --git a/src/test/resources/testPrograms/callable/FunctionGlobalLocalString.output b/src/test/resources/testPrograms/callable/FunctionGlobalLocalString.output new file mode 100644 index 0000000..53f5007 --- /dev/null +++ b/src/test/resources/testPrograms/callable/FunctionGlobalLocalString.output @@ -0,0 +1 @@ +Hallo \ No newline at end of file diff --git a/src/test/resources/testPrograms/callable/Procedure.monty b/src/test/resources/testPrograms/callable/Procedure.monty new file mode 100644 index 0000000..8e302da --- /dev/null +++ b/src/test/resources/testPrograms/callable/Procedure.monty @@ -0,0 +1,17 @@ +// Testing: ProcedureDeclaration and FunctionCall +// +// The procedures must be called correctly and execute the body. +// +// Expected output: Hello World + +output1(): + print("Hello ") + +output2(): + print("World") + if true: + return + print("Nope") + +output1() +output2() diff --git a/src/test/resources/testPrograms/callable/Procedure.output b/src/test/resources/testPrograms/callable/Procedure.output new file mode 100644 index 0000000..5e1c309 --- /dev/null +++ b/src/test/resources/testPrograms/callable/Procedure.output @@ -0,0 +1 @@ +Hello World \ No newline at end of file diff --git a/src/test/resources/testPrograms/callable/defaultParameter/DefaultFunction1.monty b/src/test/resources/testPrograms/callable/defaultParameter/DefaultFunction1.monty new file mode 100644 index 0000000..e7dfe58 --- /dev/null +++ b/src/test/resources/testPrograms/callable/defaultParameter/DefaultFunction1.monty @@ -0,0 +1,11 @@ +// Testing: FunctionDeclaration and FunctionCall +// +// The function must be called correctly and return the evaluated return +// expression. +// +// Expected output: 4 + +Int square(Int value := 2): + return value * value + +print(square()) diff --git a/src/test/resources/testPrograms/callable/defaultParameter/DefaultFunction1.output b/src/test/resources/testPrograms/callable/defaultParameter/DefaultFunction1.output new file mode 100644 index 0000000..bf0d87a --- /dev/null +++ b/src/test/resources/testPrograms/callable/defaultParameter/DefaultFunction1.output @@ -0,0 +1 @@ +4 \ No newline at end of file diff --git a/src/test/resources/testPrograms/callable/defaultParameter/DefaultFunction2.monty b/src/test/resources/testPrograms/callable/defaultParameter/DefaultFunction2.monty new file mode 100644 index 0000000..dc93800 --- /dev/null +++ b/src/test/resources/testPrograms/callable/defaultParameter/DefaultFunction2.monty @@ -0,0 +1,11 @@ +// Testing: FunctionDeclaration and FunctionCall +// +// The function must be called correctly and return the evaluated return +// expression. +// +// Expected output: 4 + +Int square(Int dummy1, Int dummy2, Int value := 2): + return value * value + +print(square(1,2)) diff --git a/src/test/resources/testPrograms/callable/defaultParameter/DefaultFunction2.output b/src/test/resources/testPrograms/callable/defaultParameter/DefaultFunction2.output new file mode 100644 index 0000000..bf0d87a --- /dev/null +++ b/src/test/resources/testPrograms/callable/defaultParameter/DefaultFunction2.output @@ -0,0 +1 @@ +4 \ No newline at end of file diff --git a/src/test/resources/testPrograms/callable/defaultParameter/DefaultFunction3.monty b/src/test/resources/testPrograms/callable/defaultParameter/DefaultFunction3.monty new file mode 100644 index 0000000..377d51a --- /dev/null +++ b/src/test/resources/testPrograms/callable/defaultParameter/DefaultFunction3.monty @@ -0,0 +1,13 @@ +// Testing: FunctionDeclaration and FunctionCall +// +// The function must be called correctly and return the evaluated return +// expression. +// +// Expected output: 261 + +Int func(Int dummy1, Int dummy2, Int value1 := 2, Int value2 := 6): + print(value1) + print (value2) + return dummy1 + +print(func(1,2)) diff --git a/src/test/resources/testPrograms/callable/defaultParameter/DefaultFunction3.output b/src/test/resources/testPrograms/callable/defaultParameter/DefaultFunction3.output new file mode 100644 index 0000000..c390b4c --- /dev/null +++ b/src/test/resources/testPrograms/callable/defaultParameter/DefaultFunction3.output @@ -0,0 +1 @@ +261 \ No newline at end of file diff --git a/src/test/resources/testPrograms/callable/defaultParameter/DefaultFunction4.monty b/src/test/resources/testPrograms/callable/defaultParameter/DefaultFunction4.monty new file mode 100644 index 0000000..0a96da7 --- /dev/null +++ b/src/test/resources/testPrograms/callable/defaultParameter/DefaultFunction4.monty @@ -0,0 +1,21 @@ +// Testing: FunctionDeclaration and FunctionCall +// +// The function must be called correctly and return the evaluated return +// expression. +// +// Expected output: 3611230 + +Int func1(Int dummy1, Int dummy2, Int value1 := 2, Int value2 := 6): + print(value1) + print (value2) + return dummy1 + +print(func1(1,2,3)) + +Int func2(Int dummy1, Int value3 := 3, Int value1 := 1, Int value2 := 2): + print(value1) + print (value2) + print(value3) + return dummy1 + +print(func2(0)) \ No newline at end of file diff --git a/src/test/resources/testPrograms/callable/defaultParameter/DefaultFunction4.output b/src/test/resources/testPrograms/callable/defaultParameter/DefaultFunction4.output new file mode 100644 index 0000000..325ab32 --- /dev/null +++ b/src/test/resources/testPrograms/callable/defaultParameter/DefaultFunction4.output @@ -0,0 +1 @@ +3611230 \ No newline at end of file diff --git a/src/test/resources/testPrograms/callable/defaultParameter/DefaultFunction5.monty b/src/test/resources/testPrograms/callable/defaultParameter/DefaultFunction5.monty new file mode 100644 index 0000000..5a51ee6 --- /dev/null +++ b/src/test/resources/testPrograms/callable/defaultParameter/DefaultFunction5.monty @@ -0,0 +1,32 @@ +// Testing: ProcedureDeclaration and FunctionCall +// +// The procedure must be called correctly and return the evaluated return +// expression. +// +// Expected output: 400100200000001000012000123 + +square(Int value := 2): + print(value * value) + +square() + + +proc1(Int dummy1, Int dummy2, Int value1 := 1): + print(dummy1) + print(dummy2) + print(value1) + +proc1(0,0) +proc1(0,0,2) + +proc2(Int dummy1, Int dummy2, Int value1 := 0, Int value2 := 0, Int value3 := 0): + print(dummy1) + print(dummy2) + print(value1) + print(value2) + print(value3) + +proc2(0,0) +proc2(0,0,1) +proc2(0,0,1,2) +proc2(0,0,1,2,3) diff --git a/src/test/resources/testPrograms/callable/defaultParameter/DefaultFunction5.output b/src/test/resources/testPrograms/callable/defaultParameter/DefaultFunction5.output new file mode 100644 index 0000000..9493c05 --- /dev/null +++ b/src/test/resources/testPrograms/callable/defaultParameter/DefaultFunction5.output @@ -0,0 +1 @@ +400100200000001000012000123 \ No newline at end of file diff --git a/src/test/resources/testPrograms/callable/defaultParameter/DefaultFunction6.monty b/src/test/resources/testPrograms/callable/defaultParameter/DefaultFunction6.monty new file mode 100644 index 0000000..98886db --- /dev/null +++ b/src/test/resources/testPrograms/callable/defaultParameter/DefaultFunction6.monty @@ -0,0 +1,33 @@ +// Testing: Default-Parameter for methods +// +// The methods (functions and procedures) of a class with parameters must be +// called correctly. +// +// Expected output: + +class Person: + + constructor(): + pass + + + saySomething1(String text := "Hello"): + print(text) + + + saySomething2(Person person := Person()): + person.saySomething1() + + + Int stupidMethod(Int dummy1, Int value1 := 3, Int value2 := 1, Int value3 := 2): + print(value1) + print (value2) + print(value3) + return dummy1 + + + Float liftWeight(Float weight := 100.0): + return weight + +Person person := Person() +person.saySomething1() +person.saySomething1("World") +person.saySomething2() +person.saySomething2(person) +print(person.stupidMethod(12)) +print(person.liftWeight()) \ No newline at end of file diff --git a/src/test/resources/testPrograms/callable/defaultParameter/DefaultFunction6.output b/src/test/resources/testPrograms/callable/defaultParameter/DefaultFunction6.output new file mode 100644 index 0000000..6994950 --- /dev/null +++ b/src/test/resources/testPrograms/callable/defaultParameter/DefaultFunction6.output @@ -0,0 +1 @@ +HelloWorldHelloHello31212100 \ No newline at end of file diff --git a/src/test/resources/testPrograms/classes/ClassMemberBool1.monty b/src/test/resources/testPrograms/classes/ClassMemberBool1.monty new file mode 100644 index 0000000..87fc3cf --- /dev/null +++ b/src/test/resources/testPrograms/classes/ClassMemberBool1.monty @@ -0,0 +1,15 @@ +// Testing: VariableDeclaration in ClassDeclaration. +// +// The boolean attribute is written and printed. The access via self must +// work. +// +// Expected output: 1 + +class Ab: + + initializer(): + self.attr := true + print(self.attr) + + + Bool attr + +Ab b := Ab() diff --git a/src/test/resources/testPrograms/classes/ClassMemberBool1.output b/src/test/resources/testPrograms/classes/ClassMemberBool1.output new file mode 100644 index 0000000..56a6051 --- /dev/null +++ b/src/test/resources/testPrograms/classes/ClassMemberBool1.output @@ -0,0 +1 @@ +1 \ No newline at end of file diff --git a/src/test/resources/testPrograms/classes/ClassMemberBool2.monty b/src/test/resources/testPrograms/classes/ClassMemberBool2.monty new file mode 100644 index 0000000..617280f --- /dev/null +++ b/src/test/resources/testPrograms/classes/ClassMemberBool2.monty @@ -0,0 +1,15 @@ +// Testing: VariableDeclaration in ClassDeclaration. +// +// The boolean attribute is written and printed from outside the class. The +// access via self and the member access must work. +// +// Expected output: 1 + +class Ab: + + initializer(): + self.attr := true + + + Bool attr + +Ab b := Ab() +print(b.attr) diff --git a/src/test/resources/testPrograms/classes/ClassMemberBool2.output b/src/test/resources/testPrograms/classes/ClassMemberBool2.output new file mode 100644 index 0000000..56a6051 --- /dev/null +++ b/src/test/resources/testPrograms/classes/ClassMemberBool2.output @@ -0,0 +1 @@ +1 \ No newline at end of file diff --git a/src/test/resources/testPrograms/classes/ClassMemberBool3.monty b/src/test/resources/testPrograms/classes/ClassMemberBool3.monty new file mode 100644 index 0000000..1ec2cff --- /dev/null +++ b/src/test/resources/testPrograms/classes/ClassMemberBool3.monty @@ -0,0 +1,17 @@ +// Testing: VariableDeclaration in ClassDeclaration. +// +// A boolean attribute and a local variable exist with the same name. Both +// must be writable and readable. +// +// Expected output: 10 + +class Ab: + + initializer(): + self.attr := true + Bool attr := false + print(self.attr) + print(attr) + + + Bool attr + +Ab b := Ab() diff --git a/src/test/resources/testPrograms/classes/ClassMemberBool3.output b/src/test/resources/testPrograms/classes/ClassMemberBool3.output new file mode 100644 index 0000000..9a03714 --- /dev/null +++ b/src/test/resources/testPrograms/classes/ClassMemberBool3.output @@ -0,0 +1 @@ +10 \ No newline at end of file diff --git a/src/test/resources/testPrograms/classes/ClassMemberBool4.monty b/src/test/resources/testPrograms/classes/ClassMemberBool4.monty new file mode 100644 index 0000000..036c305 --- /dev/null +++ b/src/test/resources/testPrograms/classes/ClassMemberBool4.monty @@ -0,0 +1,16 @@ +// Testing: VariableDeclaration in ClassDeclaration. +// +// The boolean attribute is written and a copy printed. The access via self +// must work. +// +// Expected output: 1 + +class Ab: + + initializer(): + self.attr := true + Bool copy := self.attr + print(copy) + + + Bool attr + +Ab b := Ab() diff --git a/src/test/resources/testPrograms/classes/ClassMemberBool4.output b/src/test/resources/testPrograms/classes/ClassMemberBool4.output new file mode 100644 index 0000000..56a6051 --- /dev/null +++ b/src/test/resources/testPrograms/classes/ClassMemberBool4.output @@ -0,0 +1 @@ +1 \ No newline at end of file diff --git a/src/test/resources/testPrograms/classes/ClassMemberChar1.monty b/src/test/resources/testPrograms/classes/ClassMemberChar1.monty new file mode 100644 index 0000000..5ba9d00 --- /dev/null +++ b/src/test/resources/testPrograms/classes/ClassMemberChar1.monty @@ -0,0 +1,15 @@ +// Testing: VariableDeclaration in ClassDeclaration. +// +// The char attribute is written and printed. The access via self must +// work. +// +// Expected output: 'M' + +class Ab: + + initializer(): + self.attr := 'M' + print(self.attr) + + + Char attr + +Ab b := Ab() diff --git a/src/test/resources/testPrograms/classes/ClassMemberChar1.output b/src/test/resources/testPrograms/classes/ClassMemberChar1.output new file mode 100644 index 0000000..ef6bce1 --- /dev/null +++ b/src/test/resources/testPrograms/classes/ClassMemberChar1.output @@ -0,0 +1 @@ +M \ No newline at end of file diff --git a/src/test/resources/testPrograms/classes/ClassMemberChar2.monty b/src/test/resources/testPrograms/classes/ClassMemberChar2.monty new file mode 100644 index 0000000..04650dc --- /dev/null +++ b/src/test/resources/testPrograms/classes/ClassMemberChar2.monty @@ -0,0 +1,15 @@ +// Testing: VariableDeclaration in ClassDeclaration. +// +// The char attribute is written and printed from outside the class. The +// access via self and the member access must work. +// +// Expected output: M + +class Ab: + + initializer(): + self.attr := 'M' + + + Char attr + +Ab b := Ab() +print(b.attr) diff --git a/src/test/resources/testPrograms/classes/ClassMemberChar2.output b/src/test/resources/testPrograms/classes/ClassMemberChar2.output new file mode 100644 index 0000000..ef6bce1 --- /dev/null +++ b/src/test/resources/testPrograms/classes/ClassMemberChar2.output @@ -0,0 +1 @@ +M \ No newline at end of file diff --git a/src/test/resources/testPrograms/classes/ClassMemberChar3.monty b/src/test/resources/testPrograms/classes/ClassMemberChar3.monty new file mode 100644 index 0000000..59d55e0 --- /dev/null +++ b/src/test/resources/testPrograms/classes/ClassMemberChar3.monty @@ -0,0 +1,17 @@ +// Testing: VariableDeclaration in ClassDeclaration. +// +// An char attribute and a local variable exist with the same name. Both +// must be writable and readable. +// +// Expected output: JO + +class Ab: + + initializer(): + self.attr := 'J' + Char attr := 'O' + print(self.attr) + print(attr) + + + Char attr + +Ab b := Ab() diff --git a/src/test/resources/testPrograms/classes/ClassMemberChar3.output b/src/test/resources/testPrograms/classes/ClassMemberChar3.output new file mode 100644 index 0000000..444a896 --- /dev/null +++ b/src/test/resources/testPrograms/classes/ClassMemberChar3.output @@ -0,0 +1 @@ +JO \ No newline at end of file diff --git a/src/test/resources/testPrograms/classes/ClassMemberChar4.monty b/src/test/resources/testPrograms/classes/ClassMemberChar4.monty new file mode 100644 index 0000000..7d63975 --- /dev/null +++ b/src/test/resources/testPrograms/classes/ClassMemberChar4.monty @@ -0,0 +1,16 @@ +// Testing: VariableDeclaration in ClassDeclaration. +// +// The char attribute is written and a copy printed. The access via self +// must work. +// +// Expected output: M + +class Ab: + + initializer(): + self.attr := 'M' + Char copy := self.attr + print(copy) + + + Char attr + +Ab b := Ab() diff --git a/src/test/resources/testPrograms/classes/ClassMemberChar4.output b/src/test/resources/testPrograms/classes/ClassMemberChar4.output new file mode 100644 index 0000000..ef6bce1 --- /dev/null +++ b/src/test/resources/testPrograms/classes/ClassMemberChar4.output @@ -0,0 +1 @@ +M \ No newline at end of file diff --git a/src/test/resources/testPrograms/classes/ClassMemberComplex1.monty b/src/test/resources/testPrograms/classes/ClassMemberComplex1.monty new file mode 100644 index 0000000..1fc7ea3 --- /dev/null +++ b/src/test/resources/testPrograms/classes/ClassMemberComplex1.monty @@ -0,0 +1,33 @@ +// Testing: VariableDeclaration in ClassDeclaration. +// +// The attributes of a class with multiple attributes of different types are +// written and read from within the initializer and outside the class. +// +// Expected output: 18Paul119Paula0 + +class Person: + + initializer(): + self.isMale := false + self.age := 0 + self.name := "" + + + Bool isMale + + Int age + + String name + +Person person := Person() +person.age := 18 +person.name := "Paul" +person.isMale := true + +print(person.age) +print(person.name) +print(person.isMale) + +person.age := 19 +person.name := "Paula" +person.isMale := false + +print(person.age) +print(person.name) +print(person.isMale) diff --git a/src/test/resources/testPrograms/classes/ClassMemberComplex1.output b/src/test/resources/testPrograms/classes/ClassMemberComplex1.output new file mode 100644 index 0000000..bacc5d5 --- /dev/null +++ b/src/test/resources/testPrograms/classes/ClassMemberComplex1.output @@ -0,0 +1 @@ +18Paul119Paula0 \ No newline at end of file diff --git a/src/test/resources/testPrograms/classes/ClassMemberComplex2.monty b/src/test/resources/testPrograms/classes/ClassMemberComplex2.monty new file mode 100644 index 0000000..b59d4da --- /dev/null +++ b/src/test/resources/testPrograms/classes/ClassMemberComplex2.monty @@ -0,0 +1,20 @@ +// Testing: VariableDeclaration in ClassDeclaration. +// +// A complex expression of chained attributes must be accessible and readable. +// +// Expected output: Hallo Welt + +class Ab: + + String attr + + + initializer(): + self.attr := "Hallo Welt" + +class Ba: + + Ab attr + + + initializer(): + self.attr := Ab() + +Ba inst := Ba() +print(inst.attr.attr) diff --git a/src/test/resources/testPrograms/classes/ClassMemberComplex2.output b/src/test/resources/testPrograms/classes/ClassMemberComplex2.output new file mode 100644 index 0000000..a92550c --- /dev/null +++ b/src/test/resources/testPrograms/classes/ClassMemberComplex2.output @@ -0,0 +1 @@ +Hallo Welt \ No newline at end of file diff --git a/src/test/resources/testPrograms/classes/ClassMemberComplex3.monty b/src/test/resources/testPrograms/classes/ClassMemberComplex3.monty new file mode 100644 index 0000000..6cd2cc4 --- /dev/null +++ b/src/test/resources/testPrograms/classes/ClassMemberComplex3.monty @@ -0,0 +1,22 @@ +// Testing: VariableDeclaration in ClassDeclaration. +// +// A complex expression of chained attributes must be accessible, writable and +// readable. +// +// Expected output: Hallo Welt + +class Ab: + + String attr + + + initializer(): + self.attr := "Nope" + +class Ba: + + Ab attr + + + initializer(): + self.attr := Ab() + +Ba inst := Ba() +inst.attr.attr := "Hallo Welt" +print(inst.attr.attr) diff --git a/src/test/resources/testPrograms/classes/ClassMemberComplex3.output b/src/test/resources/testPrograms/classes/ClassMemberComplex3.output new file mode 100644 index 0000000..a92550c --- /dev/null +++ b/src/test/resources/testPrograms/classes/ClassMemberComplex3.output @@ -0,0 +1 @@ +Hallo Welt \ No newline at end of file diff --git a/src/test/resources/testPrograms/classes/ClassMemberFloat1.monty b/src/test/resources/testPrograms/classes/ClassMemberFloat1.monty new file mode 100644 index 0000000..fd2f01e --- /dev/null +++ b/src/test/resources/testPrograms/classes/ClassMemberFloat1.monty @@ -0,0 +1,15 @@ +// Testing: VariableDeclaration in ClassDeclaration. +// +// The float attribute is written and printed. The access via self must +// work. +// +// Expected output: 1.3 + +class Ab: + + initializer(): + self.attr := 1.3 + print(self.attr) + + + Float attr + +Ab b := Ab() diff --git a/src/test/resources/testPrograms/classes/ClassMemberFloat1.output b/src/test/resources/testPrograms/classes/ClassMemberFloat1.output new file mode 100644 index 0000000..a58941b --- /dev/null +++ b/src/test/resources/testPrograms/classes/ClassMemberFloat1.output @@ -0,0 +1 @@ +1.3 \ No newline at end of file diff --git a/src/test/resources/testPrograms/classes/ClassMemberFloat2.monty b/src/test/resources/testPrograms/classes/ClassMemberFloat2.monty new file mode 100644 index 0000000..2c95c59 --- /dev/null +++ b/src/test/resources/testPrograms/classes/ClassMemberFloat2.monty @@ -0,0 +1,15 @@ +// Testing: VariableDeclaration in ClassDeclaration. +// +// The float attribute is written and printed from outside the class. The +// access via self and the member access must work. +// +// Expected output: 1.3 + +class Ab: + + initializer(): + self.attr := 1.3 + + + Float attr + +Ab b := Ab() +print(b.attr) diff --git a/src/test/resources/testPrograms/classes/ClassMemberFloat2.output b/src/test/resources/testPrograms/classes/ClassMemberFloat2.output new file mode 100644 index 0000000..a58941b --- /dev/null +++ b/src/test/resources/testPrograms/classes/ClassMemberFloat2.output @@ -0,0 +1 @@ +1.3 \ No newline at end of file diff --git a/src/test/resources/testPrograms/classes/ClassMemberFloat3.monty b/src/test/resources/testPrograms/classes/ClassMemberFloat3.monty new file mode 100644 index 0000000..01547ab --- /dev/null +++ b/src/test/resources/testPrograms/classes/ClassMemberFloat3.monty @@ -0,0 +1,17 @@ +// Testing: VariableDeclaration in ClassDeclaration. +// +// A float attribute and a local variable exist with the same name. Both +// must be writable and readable. +// +// Expected output: 1.33.1 + +class Ab: + + initializer(): + self.attr := 1.3 + Float attr := 3.1 + print(self.attr) + print(attr) + + + Float attr + +Ab b := Ab() diff --git a/src/test/resources/testPrograms/classes/ClassMemberFloat3.output b/src/test/resources/testPrograms/classes/ClassMemberFloat3.output new file mode 100644 index 0000000..9e9fac3 --- /dev/null +++ b/src/test/resources/testPrograms/classes/ClassMemberFloat3.output @@ -0,0 +1 @@ +1.33.1 \ No newline at end of file diff --git a/src/test/resources/testPrograms/classes/ClassMemberFloat4.monty b/src/test/resources/testPrograms/classes/ClassMemberFloat4.monty new file mode 100644 index 0000000..348c267 --- /dev/null +++ b/src/test/resources/testPrograms/classes/ClassMemberFloat4.monty @@ -0,0 +1,16 @@ +// Testing: VariableDeclaration in ClassDeclaration. +// +// The float attribute is written and a copy printed. The access via self +// must work. +// +// Expected output: 1.3 + +class Ab: + + initializer(): + self.attr := 1.3 + Float copy := self.attr + print(copy) + + + Float attr + +Ab b := Ab() diff --git a/src/test/resources/testPrograms/classes/ClassMemberFloat4.output b/src/test/resources/testPrograms/classes/ClassMemberFloat4.output new file mode 100644 index 0000000..a58941b --- /dev/null +++ b/src/test/resources/testPrograms/classes/ClassMemberFloat4.output @@ -0,0 +1 @@ +1.3 \ No newline at end of file diff --git a/src/test/resources/testPrograms/classes/ClassMemberInt1.monty b/src/test/resources/testPrograms/classes/ClassMemberInt1.monty new file mode 100644 index 0000000..5d47486 --- /dev/null +++ b/src/test/resources/testPrograms/classes/ClassMemberInt1.monty @@ -0,0 +1,15 @@ +// Testing: VariableDeclaration in ClassDeclaration. +// +// The int attribute is written and printed. The access via self must +// work. +// +// Expected output: 1 + +class Ab: + + initializer(): + self.attr := 1 + print(self.attr) + + + Int attr + +Ab b := Ab() diff --git a/src/test/resources/testPrograms/classes/ClassMemberInt1.output b/src/test/resources/testPrograms/classes/ClassMemberInt1.output new file mode 100644 index 0000000..56a6051 --- /dev/null +++ b/src/test/resources/testPrograms/classes/ClassMemberInt1.output @@ -0,0 +1 @@ +1 \ No newline at end of file diff --git a/src/test/resources/testPrograms/classes/ClassMemberInt2.monty b/src/test/resources/testPrograms/classes/ClassMemberInt2.monty new file mode 100644 index 0000000..52e4dae --- /dev/null +++ b/src/test/resources/testPrograms/classes/ClassMemberInt2.monty @@ -0,0 +1,15 @@ +// Testing: VariableDeclaration in ClassDeclaration. +// +// The int attribute is written and printed from outside the class. The +// access via self and the member access must work. +// +// Expected output: 1 + +class Ab: + + initializer(): + self.attr := 1 + + + Int attr + +Ab b := Ab() +print(b.attr) diff --git a/src/test/resources/testPrograms/classes/ClassMemberInt2.output b/src/test/resources/testPrograms/classes/ClassMemberInt2.output new file mode 100644 index 0000000..56a6051 --- /dev/null +++ b/src/test/resources/testPrograms/classes/ClassMemberInt2.output @@ -0,0 +1 @@ +1 \ No newline at end of file diff --git a/src/test/resources/testPrograms/classes/ClassMemberInt3.monty b/src/test/resources/testPrograms/classes/ClassMemberInt3.monty new file mode 100644 index 0000000..5b44911 --- /dev/null +++ b/src/test/resources/testPrograms/classes/ClassMemberInt3.monty @@ -0,0 +1,17 @@ +// Testing: VariableDeclaration in ClassDeclaration. +// +// An int attribute and a local variable exist with the same name. Both +// must be writable and readable. +// +// Expected output: 10 + +class Ab: + + initializer(): + self.attr := 1 + Int attr := 0 + print(self.attr) + print(attr) + + + Int attr + +Ab b := Ab() diff --git a/src/test/resources/testPrograms/classes/ClassMemberInt3.output b/src/test/resources/testPrograms/classes/ClassMemberInt3.output new file mode 100644 index 0000000..9a03714 --- /dev/null +++ b/src/test/resources/testPrograms/classes/ClassMemberInt3.output @@ -0,0 +1 @@ +10 \ No newline at end of file diff --git a/src/test/resources/testPrograms/classes/ClassMemberInt4.monty b/src/test/resources/testPrograms/classes/ClassMemberInt4.monty new file mode 100644 index 0000000..4462ca3 --- /dev/null +++ b/src/test/resources/testPrograms/classes/ClassMemberInt4.monty @@ -0,0 +1,16 @@ +// Testing: VariableDeclaration in ClassDeclaration. +// +// The int attribute is written and a copy printed. The access via self +// must work. +// +// Expected output: 1 + +class Ab: + + initializer(): + self.attr := 1 + Int copy := self.attr + print(copy) + + + Int attr + +Ab b := Ab() diff --git a/src/test/resources/testPrograms/classes/ClassMemberInt4.output b/src/test/resources/testPrograms/classes/ClassMemberInt4.output new file mode 100644 index 0000000..56a6051 --- /dev/null +++ b/src/test/resources/testPrograms/classes/ClassMemberInt4.output @@ -0,0 +1 @@ +1 \ No newline at end of file diff --git a/src/test/resources/testPrograms/classes/ClassMemberString1.monty b/src/test/resources/testPrograms/classes/ClassMemberString1.monty new file mode 100644 index 0000000..b836a7b --- /dev/null +++ b/src/test/resources/testPrograms/classes/ClassMemberString1.monty @@ -0,0 +1,15 @@ +// Testing: VariableDeclaration in ClassDeclaration. +// +// The string attribute is written and printed. The access via self must +// work. +// +// Expected output: Hallo + +class Ab: + + initializer(): + self.attr := "Hallo" + print(self.attr) + + + String attr + +Ab b := Ab() diff --git a/src/test/resources/testPrograms/classes/ClassMemberString1.output b/src/test/resources/testPrograms/classes/ClassMemberString1.output new file mode 100644 index 0000000..53f5007 --- /dev/null +++ b/src/test/resources/testPrograms/classes/ClassMemberString1.output @@ -0,0 +1 @@ +Hallo \ No newline at end of file diff --git a/src/test/resources/testPrograms/classes/ClassMemberString2.monty b/src/test/resources/testPrograms/classes/ClassMemberString2.monty new file mode 100644 index 0000000..c3f6125 --- /dev/null +++ b/src/test/resources/testPrograms/classes/ClassMemberString2.monty @@ -0,0 +1,15 @@ +// Testing: VariableDeclaration in ClassDeclaration. +// +// The string attribute is written and printed from outside the class. The +// access via self and the member access must work. +// +// Expected output: Hallo + +class Ab: + + initializer(): + self.attr := "Hallo" + + + String attr + +Ab b := Ab() +print(b.attr) diff --git a/src/test/resources/testPrograms/classes/ClassMemberString2.output b/src/test/resources/testPrograms/classes/ClassMemberString2.output new file mode 100644 index 0000000..53f5007 --- /dev/null +++ b/src/test/resources/testPrograms/classes/ClassMemberString2.output @@ -0,0 +1 @@ +Hallo \ No newline at end of file diff --git a/src/test/resources/testPrograms/classes/ClassMemberString3.monty b/src/test/resources/testPrograms/classes/ClassMemberString3.monty new file mode 100644 index 0000000..3f1bb48 --- /dev/null +++ b/src/test/resources/testPrograms/classes/ClassMemberString3.monty @@ -0,0 +1,17 @@ +// Testing: VariableDeclaration in ClassDeclaration. +// +// A string attribute and a local variable exist with the same name. Both +// must be writable and readable. +// +// Expected output: HalloWelt + +class Ab: + + initializer(): + self.attr := "Hallo" + String attr := "Welt" + print(self.attr) + print(attr) + + + String attr + +Ab b := Ab() diff --git a/src/test/resources/testPrograms/classes/ClassMemberString3.output b/src/test/resources/testPrograms/classes/ClassMemberString3.output new file mode 100644 index 0000000..b7b7804 --- /dev/null +++ b/src/test/resources/testPrograms/classes/ClassMemberString3.output @@ -0,0 +1 @@ +HalloWelt \ No newline at end of file diff --git a/src/test/resources/testPrograms/classes/ClassMemberString4.monty b/src/test/resources/testPrograms/classes/ClassMemberString4.monty new file mode 100644 index 0000000..bb1c138 --- /dev/null +++ b/src/test/resources/testPrograms/classes/ClassMemberString4.monty @@ -0,0 +1,16 @@ +// Testing: VariableDeclaration in ClassDeclaration. +// +// The string attribute is written and a copy printed. The access via self +// must work. +// +// Expected output: Hallo + +class Ab: + + initializer(): + self.attr := "Hallo" + String copy := self.attr + print(copy) + + + String attr + +Ab b := Ab() diff --git a/src/test/resources/testPrograms/classes/ClassMemberString4.output b/src/test/resources/testPrograms/classes/ClassMemberString4.output new file mode 100644 index 0000000..53f5007 --- /dev/null +++ b/src/test/resources/testPrograms/classes/ClassMemberString4.output @@ -0,0 +1 @@ +Hallo \ No newline at end of file diff --git a/src/test/resources/testPrograms/classes/ClassPointer1.monty b/src/test/resources/testPrograms/classes/ClassPointer1.monty new file mode 100644 index 0000000..47ee295 --- /dev/null +++ b/src/test/resources/testPrograms/classes/ClassPointer1.monty @@ -0,0 +1,31 @@ +// Testing: VariableDeclaration of type ClassDeclaration. +// +// The variable 'person' is a reference to an instance of Person. Passing this +// reference arround must work. Storing it under alternative names and +// altering the attribute must be visible under all references. +// +// Expected output: PeterPaulPetraPetraPaulaPaula + +class Person: + + initializer(String name): + self.name := name + + + String name + +Person alterPerson(Person per): + per.name := "Petra" + return per + +Person person := Person("Peter") +print(person.name) + +person.name := "Paul" +print(person.name) + +Person new := alterPerson(person) +print(person.name) +print(new.name) + +person.name := "Paula" +print(person.name) +print(new.name) diff --git a/src/test/resources/testPrograms/classes/ClassPointer1.output b/src/test/resources/testPrograms/classes/ClassPointer1.output new file mode 100644 index 0000000..25dcdef --- /dev/null +++ b/src/test/resources/testPrograms/classes/ClassPointer1.output @@ -0,0 +1 @@ +PeterPaulPetraPetraPaulaPaula \ No newline at end of file diff --git a/src/test/resources/testPrograms/classes/ClassPointer2.monty b/src/test/resources/testPrograms/classes/ClassPointer2.monty new file mode 100644 index 0000000..c26121d --- /dev/null +++ b/src/test/resources/testPrograms/classes/ClassPointer2.monty @@ -0,0 +1,26 @@ +// Testing: VariableDeclaration of type ClassDeclaration. +// +// The function buildPerson() returns a reference to a heap allocated Person. +// The procedure stackDestroyer() would override the stack memory if objects +// are allocated on the stack. +// +// Expected output: Peter + +class Person: + + initializer(String name): + self.name := name + + + String name + +Person buildPerson(): + Person person := Person("Peter") + return person + +stackDestroyer(): + Person person1 := Person("Stack") + Person person2 := Person("Des") + Person person3 := Person("Troyer") + +Person person := buildPerson() +stackDestroyer() +print(person.name) diff --git a/src/test/resources/testPrograms/classes/ClassPointer2.output b/src/test/resources/testPrograms/classes/ClassPointer2.output new file mode 100644 index 0000000..9cd89b6 --- /dev/null +++ b/src/test/resources/testPrograms/classes/ClassPointer2.output @@ -0,0 +1 @@ +Peter \ No newline at end of file diff --git a/src/test/resources/testPrograms/classes/constructor/Constructor1.monty b/src/test/resources/testPrograms/classes/constructor/Constructor1.monty new file mode 100644 index 0000000..4b1eb73 --- /dev/null +++ b/src/test/resources/testPrograms/classes/constructor/Constructor1.monty @@ -0,0 +1,13 @@ +// Testing: ClassDeclaration +// +// The simple initializer call must work. +// +// Expected output: Hi + +class Ab: + + String someAttr + + + initializer(): + print("Hi") + +Ab x := Ab() diff --git a/src/test/resources/testPrograms/classes/constructor/Constructor1.output b/src/test/resources/testPrograms/classes/constructor/Constructor1.output new file mode 100644 index 0000000..40816a2 --- /dev/null +++ b/src/test/resources/testPrograms/classes/constructor/Constructor1.output @@ -0,0 +1 @@ +Hi \ No newline at end of file diff --git a/src/test/resources/testPrograms/classes/constructor/Constructor2.monty b/src/test/resources/testPrograms/classes/constructor/Constructor2.monty new file mode 100644 index 0000000..f0105b3 --- /dev/null +++ b/src/test/resources/testPrograms/classes/constructor/Constructor2.monty @@ -0,0 +1,11 @@ +// Testing: ClassDeclaration +// +// The simple initializer call with a parameter must work. +// +// Expected output: HALLO + +class Ab: + + initializer(String a): + print(a) + +Ab x := Ab("HALLO") diff --git a/src/test/resources/testPrograms/classes/constructor/Constructor2.output b/src/test/resources/testPrograms/classes/constructor/Constructor2.output new file mode 100644 index 0000000..d3327f7 --- /dev/null +++ b/src/test/resources/testPrograms/classes/constructor/Constructor2.output @@ -0,0 +1 @@ +HALLO \ No newline at end of file diff --git a/src/test/resources/testPrograms/classes/constructor/Constructor3.monty b/src/test/resources/testPrograms/classes/constructor/Constructor3.monty new file mode 100644 index 0000000..84b7c79 --- /dev/null +++ b/src/test/resources/testPrograms/classes/constructor/Constructor3.monty @@ -0,0 +1,12 @@ +// Testing: ClassDeclaration +// +// The simple initializer call with a variable as parameter must work. +// +// Expected output: HALLO + +class Ab: + + initializer(String a): + print(a) + +String hallo := "HALLO" +Ab x := Ab(hallo) diff --git a/src/test/resources/testPrograms/classes/constructor/Constructor3.output b/src/test/resources/testPrograms/classes/constructor/Constructor3.output new file mode 100644 index 0000000..d3327f7 --- /dev/null +++ b/src/test/resources/testPrograms/classes/constructor/Constructor3.output @@ -0,0 +1 @@ +HALLO \ No newline at end of file diff --git a/src/test/resources/testPrograms/classes/constructor/Constructor4.monty b/src/test/resources/testPrograms/classes/constructor/Constructor4.monty new file mode 100644 index 0000000..4f2d452 --- /dev/null +++ b/src/test/resources/testPrograms/classes/constructor/Constructor4.monty @@ -0,0 +1,15 @@ +// Testing: ClassDeclaration +// +// The simple initializer call with a variable as parameter and an assignment +// to an attribute must work. +// +// Expected output: HALLO + +class Ab: + + String someAttr + + + initializer(String a): + self.someAttr := a + +Ab x := Ab("HALLO") +print(x.someAttr) diff --git a/src/test/resources/testPrograms/classes/constructor/Constructor4.output b/src/test/resources/testPrograms/classes/constructor/Constructor4.output new file mode 100644 index 0000000..d3327f7 --- /dev/null +++ b/src/test/resources/testPrograms/classes/constructor/Constructor4.output @@ -0,0 +1 @@ +HALLO \ No newline at end of file diff --git a/src/test/resources/testPrograms/classes/constructor/Constructor5.monty b/src/test/resources/testPrograms/classes/constructor/Constructor5.monty new file mode 100644 index 0000000..ee3176a --- /dev/null +++ b/src/test/resources/testPrograms/classes/constructor/Constructor5.monty @@ -0,0 +1,15 @@ +// Testing: ClassDeclaration, default initializer +// +// The default initializer must be created when no initializer is given and do +// all class attribute assignments. +// +// Expected output: reifenschubser + +class MyClass: + + String baum := "schubser" + + String auto := "reifen" + +MyClass clazz := MyClass() + +print(clazz.auto) +print(clazz.baum) diff --git a/src/test/resources/testPrograms/classes/constructor/Constructor5.output b/src/test/resources/testPrograms/classes/constructor/Constructor5.output new file mode 100644 index 0000000..91ba2ac --- /dev/null +++ b/src/test/resources/testPrograms/classes/constructor/Constructor5.output @@ -0,0 +1 @@ +reifenschubser \ No newline at end of file diff --git a/src/test/resources/testPrograms/classes/constructor/Constructor6.monty b/src/test/resources/testPrograms/classes/constructor/Constructor6.monty new file mode 100644 index 0000000..c6e052f --- /dev/null +++ b/src/test/resources/testPrograms/classes/constructor/Constructor6.monty @@ -0,0 +1,16 @@ +// Testing: ClassDeclaration, default initializer / attr assignments +// +// The initializer must first execute the class attribute assignments and then +// execute its own body. +// +// Expected output: HalloBernd + +class Ab: + + initializer(): + print(self.attr) + self.attr := "Bernd" + + + String attr := "Hallo" + +Ab b := Ab() +print(b.attr) \ No newline at end of file diff --git a/src/test/resources/testPrograms/classes/constructor/Constructor6.output b/src/test/resources/testPrograms/classes/constructor/Constructor6.output new file mode 100644 index 0000000..2d4c760 --- /dev/null +++ b/src/test/resources/testPrograms/classes/constructor/Constructor6.output @@ -0,0 +1 @@ +HalloBernd \ No newline at end of file diff --git a/src/test/resources/testPrograms/classes/constructor/Constructor7.monty b/src/test/resources/testPrograms/classes/constructor/Constructor7.monty new file mode 100644 index 0000000..f6cb58b --- /dev/null +++ b/src/test/resources/testPrograms/classes/constructor/Constructor7.monty @@ -0,0 +1,24 @@ +// Testing: ClassDeclaration, default initializer / attr assignments +// +// The assignments of member attributes of the class must be executed in all +// given initializers. +// +// Expected output: null!eins!zwei! + +class MyClass: + + String null := "null!" + + String eins := "eins!" + + String zwei := "zwei!" + + + initializer(): + print(self.null) + + + initializer(String egal): + print(self.eins) + + + initializer(String egal, String auchunwichtig): + print(self.zwei) + +MyClass clazz0 := MyClass() +MyClass clazz1 := MyClass("1") +MyClass clazz2 := MyClass("1", "2") \ No newline at end of file diff --git a/src/test/resources/testPrograms/classes/constructor/Constructor7.output b/src/test/resources/testPrograms/classes/constructor/Constructor7.output new file mode 100644 index 0000000..bba4b81 --- /dev/null +++ b/src/test/resources/testPrograms/classes/constructor/Constructor7.output @@ -0,0 +1 @@ +null!eins!zwei! \ No newline at end of file diff --git a/src/test/resources/testPrograms/classes/methods/Methods1.monty b/src/test/resources/testPrograms/classes/methods/Methods1.monty new file mode 100644 index 0000000..d547a6e --- /dev/null +++ b/src/test/resources/testPrograms/classes/methods/Methods1.monty @@ -0,0 +1,29 @@ +// Testing: Methods of classes +// +// The methods (functions and procedures) of a class must be called correctly. +// +// Expected output: Stoehn Aechz Keuch + +class Laute: + + initializer(): + pass + + + printSpace(): + print(" ") + + + String stoehn(): + return "Stoehn" + + + String aechz(): + return "Aechz" + + + String keuch(): + return "Keuch" + +Laute laut := Laute() + +print(laut.stoehn()) +laut.printSpace() +print(laut.aechz()) +laut.printSpace() +print(laut.keuch()) diff --git a/src/test/resources/testPrograms/classes/methods/Methods1.output b/src/test/resources/testPrograms/classes/methods/Methods1.output new file mode 100644 index 0000000..bc757d7 --- /dev/null +++ b/src/test/resources/testPrograms/classes/methods/Methods1.output @@ -0,0 +1 @@ +Stoehn Aechz Keuch \ No newline at end of file diff --git a/src/test/resources/testPrograms/classes/methods/Methods2.monty b/src/test/resources/testPrograms/classes/methods/Methods2.monty new file mode 100644 index 0000000..693f845 --- /dev/null +++ b/src/test/resources/testPrograms/classes/methods/Methods2.monty @@ -0,0 +1,20 @@ +// Testing: Methods of classes +// +// The methods (functions and procedures) of a class with parameters must be +// called correctly. +// +// Expected output: BAUM FAELLT!uiuiui + +class Laute: + + initializer(): + pass + + + String gibLaut(String ausruf): + return ausruf + + + printLaut(String ausruf): + print(ausruf) + +Laute laut := Laute() +print(laut.gibLaut("BAUM FAELLT!")) +laut.printLaut("uiuiui") diff --git a/src/test/resources/testPrograms/classes/methods/Methods2.output b/src/test/resources/testPrograms/classes/methods/Methods2.output new file mode 100644 index 0000000..a297a72 --- /dev/null +++ b/src/test/resources/testPrograms/classes/methods/Methods2.output @@ -0,0 +1 @@ +BAUM FAELLT!uiuiui \ No newline at end of file diff --git a/src/test/resources/testPrograms/classes/methods/Methods3.monty b/src/test/resources/testPrograms/classes/methods/Methods3.monty new file mode 100644 index 0000000..52001c1 --- /dev/null +++ b/src/test/resources/testPrograms/classes/methods/Methods3.monty @@ -0,0 +1,23 @@ +// Testing: Methods of classes +// +// The methods (functions and procedures) of a class must be called correctly +// with the class as a reference to an instance. +// +// Expected output: Wuff + +class Dog: + + initializer(): + pass + + + bark(): + print("Wuff") + +Dog buildDog(): + Dog dog := Dog() + return dog + +bark(Dog dogy): + dogy.bark() + +Dog dog := Dog() +bark(dog) diff --git a/src/test/resources/testPrograms/classes/methods/Methods3.output b/src/test/resources/testPrograms/classes/methods/Methods3.output new file mode 100644 index 0000000..4aa6ca2 --- /dev/null +++ b/src/test/resources/testPrograms/classes/methods/Methods3.output @@ -0,0 +1 @@ +Wuff \ No newline at end of file diff --git a/src/test/resources/testPrograms/classes/methods/Methods4.monty b/src/test/resources/testPrograms/classes/methods/Methods4.monty new file mode 100644 index 0000000..93d5510 --- /dev/null +++ b/src/test/resources/testPrograms/classes/methods/Methods4.monty @@ -0,0 +1,22 @@ +// Testing: Methods of classes +// +// The methods (functions and procedures) of multiple classes must work +// together. +// +// Expected output: 123 + +class Node: + + initializer(String id): + self.id := id + + - String id + + String getId(): + return self.id + + setId(String value): + self.id := value + +Node node := Node("") +Node node2 := Node("123") + +node.setId(node2.getId()) +print(node.getId()) diff --git a/src/test/resources/testPrograms/classes/methods/Methods4.output b/src/test/resources/testPrograms/classes/methods/Methods4.output new file mode 100644 index 0000000..d800886 --- /dev/null +++ b/src/test/resources/testPrograms/classes/methods/Methods4.output @@ -0,0 +1 @@ +123 \ No newline at end of file diff --git a/src/test/resources/testPrograms/classes/methods/Methods5.monty b/src/test/resources/testPrograms/classes/methods/Methods5.monty new file mode 100644 index 0000000..a1689b4 --- /dev/null +++ b/src/test/resources/testPrograms/classes/methods/Methods5.monty @@ -0,0 +1,36 @@ +// Testing: Methods of classes +// +// The methods (functions and procedures) of multiple classes must work +// together if classes are passed as arguments and return values. +// +// Expected output: 12 + +class Edge: + + Node start + + Node end + + + initializer(Node start, Node end): + self.start := start + self.end := end + + + Node getStart(): + return self.start + + + Node getEnd(): + return self.end + +class Node: + + Int id + + + initializer(Int id): + self.id := id + + + Int getId(): + return self.id + +Node s := Node(1) +Node e := Node(2) +Edge edge := Edge(s,e) + +print(edge.getStart().getId()) +print(edge.getEnd().getId()) diff --git a/src/test/resources/testPrograms/classes/methods/Methods5.output b/src/test/resources/testPrograms/classes/methods/Methods5.output new file mode 100644 index 0000000..3cacc0b --- /dev/null +++ b/src/test/resources/testPrograms/classes/methods/Methods5.output @@ -0,0 +1 @@ +12 \ No newline at end of file diff --git a/src/test/resources/testPrograms/compoundAssignments/Div.monty b/src/test/resources/testPrograms/compoundAssignments/Div.monty new file mode 100644 index 0000000..2d9664a --- /dev/null +++ b/src/test/resources/testPrograms/compoundAssignments/Div.monty @@ -0,0 +1,9 @@ +// Testing: CompoundAssignment +// +// Using the CompoundAssignment Div +// +// Expected output: 4 + +Int a := 8 +a /= 2 +print(a) diff --git a/src/test/resources/testPrograms/compoundAssignments/Div.output b/src/test/resources/testPrograms/compoundAssignments/Div.output new file mode 100644 index 0000000..bf0d87a --- /dev/null +++ b/src/test/resources/testPrograms/compoundAssignments/Div.output @@ -0,0 +1 @@ +4 \ No newline at end of file diff --git a/src/test/resources/testPrograms/compoundAssignments/Div1.monty b/src/test/resources/testPrograms/compoundAssignments/Div1.monty new file mode 100644 index 0000000..3bf4b19 --- /dev/null +++ b/src/test/resources/testPrograms/compoundAssignments/Div1.monty @@ -0,0 +1,10 @@ +// Testing: CompoundAssignment +// +// Using the CompoundAssignment Div with a slightly +// more complicated right hand expression +// +// Expected output: 13 + +Int a := 452 +a /= 3 + 2 * 15 +print(a) diff --git a/src/test/resources/testPrograms/compoundAssignments/Div1.output b/src/test/resources/testPrograms/compoundAssignments/Div1.output new file mode 100644 index 0000000..ca7bf83 --- /dev/null +++ b/src/test/resources/testPrograms/compoundAssignments/Div1.output @@ -0,0 +1 @@ +13 \ No newline at end of file diff --git a/src/test/resources/testPrograms/compoundAssignments/Minus.monty b/src/test/resources/testPrograms/compoundAssignments/Minus.monty new file mode 100644 index 0000000..3c477bb --- /dev/null +++ b/src/test/resources/testPrograms/compoundAssignments/Minus.monty @@ -0,0 +1,9 @@ +// Testing: CompoundAssignment +// +// Using the CompoundAssignment Minus +// +// Expected output: 3 + +Int a := 5 +a -= 2 +print(a) diff --git a/src/test/resources/testPrograms/compoundAssignments/Minus.output b/src/test/resources/testPrograms/compoundAssignments/Minus.output new file mode 100644 index 0000000..e440e5c --- /dev/null +++ b/src/test/resources/testPrograms/compoundAssignments/Minus.output @@ -0,0 +1 @@ +3 \ No newline at end of file diff --git a/src/test/resources/testPrograms/compoundAssignments/Minus1.monty b/src/test/resources/testPrograms/compoundAssignments/Minus1.monty new file mode 100644 index 0000000..95de524 --- /dev/null +++ b/src/test/resources/testPrograms/compoundAssignments/Minus1.monty @@ -0,0 +1,9 @@ +// Testing: CompoundAssignment +// +// Using the CompoundAssignment Minus +// +// Expected output: -19 + +Int a := 5 * 3 + 5 +a -= 13 * (4 - 1) +print(a) diff --git a/src/test/resources/testPrograms/compoundAssignments/Minus1.output b/src/test/resources/testPrograms/compoundAssignments/Minus1.output new file mode 100644 index 0000000..940cd43 --- /dev/null +++ b/src/test/resources/testPrograms/compoundAssignments/Minus1.output @@ -0,0 +1 @@ +-19 \ No newline at end of file diff --git a/src/test/resources/testPrograms/compoundAssignments/Mod.monty b/src/test/resources/testPrograms/compoundAssignments/Mod.monty new file mode 100644 index 0000000..d865bd5 --- /dev/null +++ b/src/test/resources/testPrograms/compoundAssignments/Mod.monty @@ -0,0 +1,9 @@ +// Testing: CompoundAssignment +// +// Using the CompoundAssignment Mod +// +// Expected output: 1 + +Int a := 5 +a %= 2 +print(a) diff --git a/src/test/resources/testPrograms/compoundAssignments/Mod.output b/src/test/resources/testPrograms/compoundAssignments/Mod.output new file mode 100644 index 0000000..56a6051 --- /dev/null +++ b/src/test/resources/testPrograms/compoundAssignments/Mod.output @@ -0,0 +1 @@ +1 \ No newline at end of file diff --git a/src/test/resources/testPrograms/compoundAssignments/Mod1.monty b/src/test/resources/testPrograms/compoundAssignments/Mod1.monty new file mode 100644 index 0000000..e9f0933 --- /dev/null +++ b/src/test/resources/testPrograms/compoundAssignments/Mod1.monty @@ -0,0 +1,10 @@ +// Testing: CompoundAssignment +// +// Using the CompoundAssignment Mod with a slightly +// more complicated right hand expression +// +// Expected output: 2 + +Int a := 11 +a %= 2 * 4 - 5 +print(a) diff --git a/src/test/resources/testPrograms/compoundAssignments/Mod1.output b/src/test/resources/testPrograms/compoundAssignments/Mod1.output new file mode 100644 index 0000000..d8263ee --- /dev/null +++ b/src/test/resources/testPrograms/compoundAssignments/Mod1.output @@ -0,0 +1 @@ +2 \ No newline at end of file diff --git a/src/test/resources/testPrograms/compoundAssignments/Mult.monty b/src/test/resources/testPrograms/compoundAssignments/Mult.monty new file mode 100644 index 0000000..a144b81 --- /dev/null +++ b/src/test/resources/testPrograms/compoundAssignments/Mult.monty @@ -0,0 +1,9 @@ +// Testing: CompoundAssignment +// +// Using the CompoundAssignment Mult +// +// Expected output: 10 + +Int a := 5 +a *= 2 +print(a) diff --git a/src/test/resources/testPrograms/compoundAssignments/Mult.output b/src/test/resources/testPrograms/compoundAssignments/Mult.output new file mode 100644 index 0000000..9a03714 --- /dev/null +++ b/src/test/resources/testPrograms/compoundAssignments/Mult.output @@ -0,0 +1 @@ +10 \ No newline at end of file diff --git a/src/test/resources/testPrograms/compoundAssignments/Mult1.monty b/src/test/resources/testPrograms/compoundAssignments/Mult1.monty new file mode 100644 index 0000000..ff703d3 --- /dev/null +++ b/src/test/resources/testPrograms/compoundAssignments/Mult1.monty @@ -0,0 +1,10 @@ +// Testing: CompoundAssignment +// +// Using the CompoundAssignment Mult with a slightly +// more complicated right hand expression +// +// Expected output: 33 + +Int a := 5 + 2 * 3 +a *= 3 +print(a) diff --git a/src/test/resources/testPrograms/compoundAssignments/Mult1.output b/src/test/resources/testPrograms/compoundAssignments/Mult1.output new file mode 100644 index 0000000..dc7b54a --- /dev/null +++ b/src/test/resources/testPrograms/compoundAssignments/Mult1.output @@ -0,0 +1 @@ +33 \ No newline at end of file diff --git a/src/test/resources/testPrograms/compoundAssignments/Plus.monty b/src/test/resources/testPrograms/compoundAssignments/Plus.monty new file mode 100644 index 0000000..403d502 --- /dev/null +++ b/src/test/resources/testPrograms/compoundAssignments/Plus.monty @@ -0,0 +1,9 @@ +// Testing: CompoundAssignment +// +// Using the CompoundAssignment Plus +// +// Expected output: 7 + +Int a := 5 +a += 2 +print(a) diff --git a/src/test/resources/testPrograms/compoundAssignments/Plus.output b/src/test/resources/testPrograms/compoundAssignments/Plus.output new file mode 100644 index 0000000..c793025 --- /dev/null +++ b/src/test/resources/testPrograms/compoundAssignments/Plus.output @@ -0,0 +1 @@ +7 \ No newline at end of file diff --git a/src/test/resources/testPrograms/compoundAssignments/Plus1.monty b/src/test/resources/testPrograms/compoundAssignments/Plus1.monty new file mode 100644 index 0000000..d45cc96 --- /dev/null +++ b/src/test/resources/testPrograms/compoundAssignments/Plus1.monty @@ -0,0 +1,10 @@ +// Testing: CompoundAssignment +// +// Using the CompoundAssignment Plus with a slightly +// more complicated right hand expression +// +// Expected output: 42 + +Int a := 12 +a += 7 * 4 + (1 * 2) +print(a) diff --git a/src/test/resources/testPrograms/compoundAssignments/Plus1.output b/src/test/resources/testPrograms/compoundAssignments/Plus1.output new file mode 100644 index 0000000..f70d7bb --- /dev/null +++ b/src/test/resources/testPrograms/compoundAssignments/Plus1.output @@ -0,0 +1 @@ +42 \ No newline at end of file diff --git a/src/test/resources/testPrograms/compoundAssignments/Power.monty.ignore b/src/test/resources/testPrograms/compoundAssignments/Power.monty.ignore new file mode 100644 index 0000000..15c16bd --- /dev/null +++ b/src/test/resources/testPrograms/compoundAssignments/Power.monty.ignore @@ -0,0 +1,9 @@ +// Testing: CompoundAssignment +// +// Using the CompoundAssignment Power +// +// Expected output: 64 + +Int a := 8 +a ^= 2 +print(a) diff --git a/src/test/resources/testPrograms/compoundAssignments/Power.output b/src/test/resources/testPrograms/compoundAssignments/Power.output new file mode 100644 index 0000000..4b6f9c3 --- /dev/null +++ b/src/test/resources/testPrograms/compoundAssignments/Power.output @@ -0,0 +1 @@ +64 \ No newline at end of file diff --git a/src/test/resources/testPrograms/compoundAssignments/Power1.monty.ignore b/src/test/resources/testPrograms/compoundAssignments/Power1.monty.ignore new file mode 100644 index 0000000..d774b6e --- /dev/null +++ b/src/test/resources/testPrograms/compoundAssignments/Power1.monty.ignore @@ -0,0 +1,10 @@ +// Testing: CompoundAssignment +// +// Using the CompoundAssignment Power with a slightly +// more complicated right hand expression +// +// Expected output: 243 + +Int a := 3 +a ^= 2 + 1 * 3 +print(a) diff --git a/src/test/resources/testPrograms/compoundAssignments/Power1.output b/src/test/resources/testPrograms/compoundAssignments/Power1.output new file mode 100644 index 0000000..104fcf5 --- /dev/null +++ b/src/test/resources/testPrograms/compoundAssignments/Power1.output @@ -0,0 +1 @@ +243 \ No newline at end of file diff --git a/src/test/resources/testPrograms/controlflow/ConditionalStatementComplex.monty b/src/test/resources/testPrograms/controlflow/ConditionalStatementComplex.monty new file mode 100644 index 0000000..3dbd60c --- /dev/null +++ b/src/test/resources/testPrograms/controlflow/ConditionalStatementComplex.monty @@ -0,0 +1,13 @@ +// Testing: ConditionalStatement +// +// The if-elif-else nesting should be converted into simple if-else +// statements. +// +// Expected output: 1 + +if false: + print(3) +elif false: + print(2) +else: + print(1) diff --git a/src/test/resources/testPrograms/controlflow/ConditionalStatementComplex.output b/src/test/resources/testPrograms/controlflow/ConditionalStatementComplex.output new file mode 100644 index 0000000..56a6051 --- /dev/null +++ b/src/test/resources/testPrograms/controlflow/ConditionalStatementComplex.output @@ -0,0 +1 @@ +1 \ No newline at end of file diff --git a/src/test/resources/testPrograms/controlflow/ConditionalStatementFalse.monty b/src/test/resources/testPrograms/controlflow/ConditionalStatementFalse.monty new file mode 100644 index 0000000..f9b5777 --- /dev/null +++ b/src/test/resources/testPrograms/controlflow/ConditionalStatementFalse.monty @@ -0,0 +1,10 @@ +// Testing: ConditionalStatement +// +// The condition is false, so the print() shall never be called. +// +// Expected output: + +Bool value2 := false + +if value2: + print(0) diff --git a/src/test/resources/testPrograms/controlflow/ConditionalStatementFalse.output b/src/test/resources/testPrograms/controlflow/ConditionalStatementFalse.output new file mode 100644 index 0000000..e69de29 diff --git a/src/test/resources/testPrograms/controlflow/ConditionalStatementTrue.monty b/src/test/resources/testPrograms/controlflow/ConditionalStatementTrue.monty new file mode 100644 index 0000000..1457fbb --- /dev/null +++ b/src/test/resources/testPrograms/controlflow/ConditionalStatementTrue.monty @@ -0,0 +1,10 @@ +// Testing: ConditionalStatement +// +// The condition is true, so the print() must be called. +// +// Expected output: 1 + +Bool value := true + +if value: + print(1) diff --git a/src/test/resources/testPrograms/controlflow/ConditionalStatementTrue.output b/src/test/resources/testPrograms/controlflow/ConditionalStatementTrue.output new file mode 100644 index 0000000..56a6051 --- /dev/null +++ b/src/test/resources/testPrograms/controlflow/ConditionalStatementTrue.output @@ -0,0 +1 @@ +1 \ No newline at end of file diff --git a/src/test/resources/testPrograms/controlflow/Ifelse1.monty b/src/test/resources/testPrograms/controlflow/Ifelse1.monty new file mode 100644 index 0000000..739aa45 --- /dev/null +++ b/src/test/resources/testPrograms/controlflow/Ifelse1.monty @@ -0,0 +1,19 @@ +// Testing: ConditionalStatement +// +// The if-elif-else nesting should be converted into simple if-else +// statements. +// +// Expected output: 2020 + +Int a := 20 + +if a = 10: + print(10) +else: + print(a) + +if a = 10: + print(10) +else: + if a = 20: + print(a) \ No newline at end of file diff --git a/src/test/resources/testPrograms/controlflow/Ifelse1.output b/src/test/resources/testPrograms/controlflow/Ifelse1.output new file mode 100644 index 0000000..145262f --- /dev/null +++ b/src/test/resources/testPrograms/controlflow/Ifelse1.output @@ -0,0 +1 @@ +2020 \ No newline at end of file diff --git a/src/test/resources/testPrograms/controlflow/Ifelse2.monty b/src/test/resources/testPrograms/controlflow/Ifelse2.monty new file mode 100644 index 0000000..af06176 --- /dev/null +++ b/src/test/resources/testPrograms/controlflow/Ifelse2.monty @@ -0,0 +1,33 @@ +// Testing: ConditionalStatement +// +// The if-elif-else nesting should be converted into simple if-else +// statements. +// +// Expected output: 2020 + +Int a := 20 + +if a = 10: + print(10) +else: + if a = 5: + print("no") + elif a = 20: + print(a) + else: + print("no") + +if a = 10: + print(10) +else: + if a = 5: + print("no") + elif a = 20: + if a = 5: + print("no") + elif a = 10: + print("no") + else: + print(a) + else: + print("no") \ No newline at end of file diff --git a/src/test/resources/testPrograms/controlflow/Ifelse2.output b/src/test/resources/testPrograms/controlflow/Ifelse2.output new file mode 100644 index 0000000..145262f --- /dev/null +++ b/src/test/resources/testPrograms/controlflow/Ifelse2.output @@ -0,0 +1 @@ +2020 \ No newline at end of file diff --git a/src/test/resources/testPrograms/controlflow/WhileLoopBreak1.monty b/src/test/resources/testPrograms/controlflow/WhileLoopBreak1.monty new file mode 100644 index 0000000..0070355 --- /dev/null +++ b/src/test/resources/testPrograms/controlflow/WhileLoopBreak1.monty @@ -0,0 +1,12 @@ +// Testing: WhileLoop with BreakStatement. +// +// The control-flow enters the loop-body, the break leaves it immediately so +// the print("Should not print") never gets called. +// +// Expected output: Ok + +while true: + break + print("Should not print") + +print("Ok") diff --git a/src/test/resources/testPrograms/controlflow/WhileLoopBreak1.output b/src/test/resources/testPrograms/controlflow/WhileLoopBreak1.output new file mode 100644 index 0000000..077fd65 --- /dev/null +++ b/src/test/resources/testPrograms/controlflow/WhileLoopBreak1.output @@ -0,0 +1 @@ +Ok \ No newline at end of file diff --git a/src/test/resources/testPrograms/controlflow/WhileLoopFalse.monty b/src/test/resources/testPrograms/controlflow/WhileLoopFalse.monty new file mode 100644 index 0000000..4b53c6e --- /dev/null +++ b/src/test/resources/testPrograms/controlflow/WhileLoopFalse.monty @@ -0,0 +1,11 @@ +// Testing: WhileLoop +// +// The control-flow never enters the loop-body so the print("Should not +// print") never gets called. +// +// Expected output: Ok + +while false: + print("Should not print") + +print("Ok") diff --git a/src/test/resources/testPrograms/controlflow/WhileLoopFalse.output b/src/test/resources/testPrograms/controlflow/WhileLoopFalse.output new file mode 100644 index 0000000..077fd65 --- /dev/null +++ b/src/test/resources/testPrograms/controlflow/WhileLoopFalse.output @@ -0,0 +1 @@ +Ok \ No newline at end of file diff --git a/src/test/resources/testPrograms/controlflow/WhileLoopSimple.monty b/src/test/resources/testPrograms/controlflow/WhileLoopSimple.monty new file mode 100644 index 0000000..d75f538 --- /dev/null +++ b/src/test/resources/testPrograms/controlflow/WhileLoopSimple.monty @@ -0,0 +1,13 @@ +// Testing: WhileLoop with simple expression. +// +// The loop-body gets executed while the condition is true. The condition +// should always load the variable for the evaluation of the expression. +// +// Expected output: 16 + +Int counter := 1 + +while counter < 15: + counter := counter * 2 + +print(counter) diff --git a/src/test/resources/testPrograms/controlflow/WhileLoopSimple.output b/src/test/resources/testPrograms/controlflow/WhileLoopSimple.output new file mode 100644 index 0000000..19c7bdb --- /dev/null +++ b/src/test/resources/testPrograms/controlflow/WhileLoopSimple.output @@ -0,0 +1 @@ +16 \ No newline at end of file diff --git a/src/test/resources/testPrograms/controlflow/WhileLoopSkip1.monty b/src/test/resources/testPrograms/controlflow/WhileLoopSkip1.monty new file mode 100644 index 0000000..57927a0 --- /dev/null +++ b/src/test/resources/testPrograms/controlflow/WhileLoopSkip1.monty @@ -0,0 +1,17 @@ +// Testing: WhileLoop with SkipStatement. +// +// The control-flow enters the loop-body, the skip jumpes back to the +// evaluation of the condition so the print("Should not print") never gets +// called. +// +// Expected output: Ok16 + +Int counter := 1 + +while counter < 15: + counter := counter * 2 + skip + print("Should not print") + +print("Ok") +print(counter) diff --git a/src/test/resources/testPrograms/controlflow/WhileLoopSkip1.output b/src/test/resources/testPrograms/controlflow/WhileLoopSkip1.output new file mode 100644 index 0000000..d0c9add --- /dev/null +++ b/src/test/resources/testPrograms/controlflow/WhileLoopSkip1.output @@ -0,0 +1 @@ +Ok16 \ No newline at end of file diff --git a/src/test/resources/testPrograms/expressions/BinaryOperatorAdd1.monty b/src/test/resources/testPrograms/expressions/BinaryOperatorAdd1.monty new file mode 100644 index 0000000..7534486 --- /dev/null +++ b/src/test/resources/testPrograms/expressions/BinaryOperatorAdd1.monty @@ -0,0 +1,11 @@ +// Testing: The operator + on int. +// +// The result of an addition should be an int. +// +// Expected output: 54 + +Int b := 2+3 +print(b) +Int a := 3 +print(a+1) + diff --git a/src/test/resources/testPrograms/expressions/BinaryOperatorAdd1.output b/src/test/resources/testPrograms/expressions/BinaryOperatorAdd1.output new file mode 100644 index 0000000..43c451e --- /dev/null +++ b/src/test/resources/testPrograms/expressions/BinaryOperatorAdd1.output @@ -0,0 +1 @@ +54 \ No newline at end of file diff --git a/src/test/resources/testPrograms/expressions/BinaryOperatorAdd2.monty b/src/test/resources/testPrograms/expressions/BinaryOperatorAdd2.monty new file mode 100644 index 0000000..ec1a322 --- /dev/null +++ b/src/test/resources/testPrograms/expressions/BinaryOperatorAdd2.monty @@ -0,0 +1,10 @@ +// Testing: The operator + on float. +// +// The result of an addition should be an float. +// +// Expected output: 3.15 + +Float b := 2.3+0.8 +print(b) +Float a := 4.25 +print(a+0.75) diff --git a/src/test/resources/testPrograms/expressions/BinaryOperatorAdd2.output b/src/test/resources/testPrograms/expressions/BinaryOperatorAdd2.output new file mode 100644 index 0000000..230693c --- /dev/null +++ b/src/test/resources/testPrograms/expressions/BinaryOperatorAdd2.output @@ -0,0 +1 @@ +3.15 \ No newline at end of file diff --git a/src/test/resources/testPrograms/expressions/BinaryOperatorAnd1.monty b/src/test/resources/testPrograms/expressions/BinaryOperatorAnd1.monty new file mode 100644 index 0000000..5413746 --- /dev/null +++ b/src/test/resources/testPrograms/expressions/BinaryOperatorAnd1.monty @@ -0,0 +1,11 @@ +// Testing: The operator 'and' on bool. +// +// The result of an 'and' should be an bool. +// +// Expected output: 1000 + +Bool b := true and true +print(b) +print(true and false) +print(false and true) +print(false and false) diff --git a/src/test/resources/testPrograms/expressions/BinaryOperatorAnd1.output b/src/test/resources/testPrograms/expressions/BinaryOperatorAnd1.output new file mode 100644 index 0000000..e37d32a --- /dev/null +++ b/src/test/resources/testPrograms/expressions/BinaryOperatorAnd1.output @@ -0,0 +1 @@ +1000 \ No newline at end of file diff --git a/src/test/resources/testPrograms/expressions/BinaryOperatorDiv1.monty b/src/test/resources/testPrograms/expressions/BinaryOperatorDiv1.monty new file mode 100644 index 0000000..d665582 --- /dev/null +++ b/src/test/resources/testPrograms/expressions/BinaryOperatorDiv1.monty @@ -0,0 +1,10 @@ +// Testing: The operator / on int. +// +// The result of a division should be an int. +// +// Expected output: 17 + +Int b := 3/2 +print(b) +Int a := 35 +print(a/5) diff --git a/src/test/resources/testPrograms/expressions/BinaryOperatorDiv1.output b/src/test/resources/testPrograms/expressions/BinaryOperatorDiv1.output new file mode 100644 index 0000000..8e2afd3 --- /dev/null +++ b/src/test/resources/testPrograms/expressions/BinaryOperatorDiv1.output @@ -0,0 +1 @@ +17 \ No newline at end of file diff --git a/src/test/resources/testPrograms/expressions/BinaryOperatorDiv2.monty b/src/test/resources/testPrograms/expressions/BinaryOperatorDiv2.monty new file mode 100644 index 0000000..8f9d645 --- /dev/null +++ b/src/test/resources/testPrograms/expressions/BinaryOperatorDiv2.monty @@ -0,0 +1,10 @@ +// Testing: The operator / on float. +// +// The result of a division should be an float. +// +// Expected output: 1.57 + +Float b := 3.0/2.0 +print(b) +Float a := 35.0 +print(a/5.0) diff --git a/src/test/resources/testPrograms/expressions/BinaryOperatorDiv2.output b/src/test/resources/testPrograms/expressions/BinaryOperatorDiv2.output new file mode 100644 index 0000000..aa6cc3f --- /dev/null +++ b/src/test/resources/testPrograms/expressions/BinaryOperatorDiv2.output @@ -0,0 +1 @@ +1.57 \ No newline at end of file diff --git a/src/test/resources/testPrograms/expressions/BinaryOperatorEquals1.monty b/src/test/resources/testPrograms/expressions/BinaryOperatorEquals1.monty new file mode 100644 index 0000000..a12030a --- /dev/null +++ b/src/test/resources/testPrograms/expressions/BinaryOperatorEquals1.monty @@ -0,0 +1,11 @@ +// Testing: The operator '=' on bool. +// +// The result of an '=' should be an bool. +// +// Expected output: 1001 + +Bool b := true = true +print(b) +print(true = false) +print(false = true) +print(false = false) diff --git a/src/test/resources/testPrograms/expressions/BinaryOperatorEquals1.output b/src/test/resources/testPrograms/expressions/BinaryOperatorEquals1.output new file mode 100644 index 0000000..7cebf7d --- /dev/null +++ b/src/test/resources/testPrograms/expressions/BinaryOperatorEquals1.output @@ -0,0 +1 @@ +1001 \ No newline at end of file diff --git a/src/test/resources/testPrograms/expressions/BinaryOperatorEquals2.monty b/src/test/resources/testPrograms/expressions/BinaryOperatorEquals2.monty new file mode 100644 index 0000000..0a2ec17 --- /dev/null +++ b/src/test/resources/testPrograms/expressions/BinaryOperatorEquals2.monty @@ -0,0 +1,12 @@ +// Testing: The operator '=' on int. +// +// The result of an '=' should be an bool. +// +// Expected output: 101 + +Bool b := 20 = 20 +print(b) +print(3 = 4) +Int x := 5 +Int y := 5 +print(x=y) diff --git a/src/test/resources/testPrograms/expressions/BinaryOperatorEquals2.output b/src/test/resources/testPrograms/expressions/BinaryOperatorEquals2.output new file mode 100644 index 0000000..97a55e1 --- /dev/null +++ b/src/test/resources/testPrograms/expressions/BinaryOperatorEquals2.output @@ -0,0 +1 @@ +101 \ No newline at end of file diff --git a/src/test/resources/testPrograms/expressions/BinaryOperatorEquals3.monty b/src/test/resources/testPrograms/expressions/BinaryOperatorEquals3.monty new file mode 100644 index 0000000..00c7eb5 --- /dev/null +++ b/src/test/resources/testPrograms/expressions/BinaryOperatorEquals3.monty @@ -0,0 +1,13 @@ +// Testing: The operator '=' on float. +// +// The result of an '=' should be an bool. +// +// Expected output: 1110 + +Bool b := 20.0 = 20.0 +print(b) +print(3.3 = 3.3) +Float x := 8.125 +Float y := 8.125 +print(x=y) +print(x=8.124) diff --git a/src/test/resources/testPrograms/expressions/BinaryOperatorEquals3.output b/src/test/resources/testPrograms/expressions/BinaryOperatorEquals3.output new file mode 100644 index 0000000..96e38be --- /dev/null +++ b/src/test/resources/testPrograms/expressions/BinaryOperatorEquals3.output @@ -0,0 +1 @@ +1110 \ No newline at end of file diff --git a/src/test/resources/testPrograms/expressions/BinaryOperatorEqualsNot1.monty b/src/test/resources/testPrograms/expressions/BinaryOperatorEqualsNot1.monty new file mode 100644 index 0000000..8db72bd --- /dev/null +++ b/src/test/resources/testPrograms/expressions/BinaryOperatorEqualsNot1.monty @@ -0,0 +1,11 @@ +// Testing: The operator '!=' on bool. +// +// The result of an '!=' should be an bool. +// +// Expected output: 0110 + +Bool b := true != true +print(b) +print(true != false) +print(false != true) +print(false != false) diff --git a/src/test/resources/testPrograms/expressions/BinaryOperatorEqualsNot1.output b/src/test/resources/testPrograms/expressions/BinaryOperatorEqualsNot1.output new file mode 100644 index 0000000..f4396d0 --- /dev/null +++ b/src/test/resources/testPrograms/expressions/BinaryOperatorEqualsNot1.output @@ -0,0 +1 @@ +0110 \ No newline at end of file diff --git a/src/test/resources/testPrograms/expressions/BinaryOperatorEqualsNot2.monty b/src/test/resources/testPrograms/expressions/BinaryOperatorEqualsNot2.monty new file mode 100644 index 0000000..6f4f111 --- /dev/null +++ b/src/test/resources/testPrograms/expressions/BinaryOperatorEqualsNot2.monty @@ -0,0 +1,11 @@ +// Testing: The operator '!=' on int. +// +// The result of an '!=' should be an bool. +// +// Expected output: 1010 + +Bool b := 51 != 21 +print(b) +print(10 != 10) +print(-10 != 30) +print(-18 != -18) diff --git a/src/test/resources/testPrograms/expressions/BinaryOperatorEqualsNot2.output b/src/test/resources/testPrograms/expressions/BinaryOperatorEqualsNot2.output new file mode 100644 index 0000000..028ead5 --- /dev/null +++ b/src/test/resources/testPrograms/expressions/BinaryOperatorEqualsNot2.output @@ -0,0 +1 @@ +1010 \ No newline at end of file diff --git a/src/test/resources/testPrograms/expressions/BinaryOperatorEqualsNot3.monty b/src/test/resources/testPrograms/expressions/BinaryOperatorEqualsNot3.monty new file mode 100644 index 0000000..091dbf6 --- /dev/null +++ b/src/test/resources/testPrograms/expressions/BinaryOperatorEqualsNot3.monty @@ -0,0 +1,13 @@ +// Testing: The operator '!=' on float. +// +// The result of an '!=' should be an bool. +// +// Expected output: 0001 + +Bool b := 20.0 != 20.0 +print(b) +print(3.3 != 3.3) +Float x := 8.125 +Float y := 8.125 +print(x != y) +print(x != 8.124) diff --git a/src/test/resources/testPrograms/expressions/BinaryOperatorEqualsNot3.output b/src/test/resources/testPrograms/expressions/BinaryOperatorEqualsNot3.output new file mode 100644 index 0000000..741d32c --- /dev/null +++ b/src/test/resources/testPrograms/expressions/BinaryOperatorEqualsNot3.output @@ -0,0 +1 @@ +0001 \ No newline at end of file diff --git a/src/test/resources/testPrograms/expressions/BinaryOperatorGreater1.monty b/src/test/resources/testPrograms/expressions/BinaryOperatorGreater1.monty new file mode 100644 index 0000000..bf4e238 --- /dev/null +++ b/src/test/resources/testPrograms/expressions/BinaryOperatorGreater1.monty @@ -0,0 +1,9 @@ +// Testing: The operator > on int. +// +// The result of a comparison should be a bool. +// +// Expected output: 01 + +print(2>3) +Int a := 3 +print(a>1) diff --git a/src/test/resources/testPrograms/expressions/BinaryOperatorGreater1.output b/src/test/resources/testPrograms/expressions/BinaryOperatorGreater1.output new file mode 100644 index 0000000..a616ad4 --- /dev/null +++ b/src/test/resources/testPrograms/expressions/BinaryOperatorGreater1.output @@ -0,0 +1 @@ +01 \ No newline at end of file diff --git a/src/test/resources/testPrograms/expressions/BinaryOperatorGreater2.monty b/src/test/resources/testPrograms/expressions/BinaryOperatorGreater2.monty new file mode 100644 index 0000000..fdf8e4f --- /dev/null +++ b/src/test/resources/testPrograms/expressions/BinaryOperatorGreater2.monty @@ -0,0 +1,10 @@ +// Testing: The operator > on float. +// +// The result of a comparison should be a bool. +// +// Expected output: 001 + +print(2.0>3.0) +Float a := 4.9 +print(a>5.0) +print(3.0 > -2.3) diff --git a/src/test/resources/testPrograms/expressions/BinaryOperatorGreater2.output b/src/test/resources/testPrograms/expressions/BinaryOperatorGreater2.output new file mode 100644 index 0000000..0f30166 --- /dev/null +++ b/src/test/resources/testPrograms/expressions/BinaryOperatorGreater2.output @@ -0,0 +1 @@ +001 \ No newline at end of file diff --git a/src/test/resources/testPrograms/expressions/BinaryOperatorGreaterEqual1.monty b/src/test/resources/testPrograms/expressions/BinaryOperatorGreaterEqual1.monty new file mode 100644 index 0000000..9c938f6 --- /dev/null +++ b/src/test/resources/testPrograms/expressions/BinaryOperatorGreaterEqual1.monty @@ -0,0 +1,9 @@ +// Testing: The operator >= on int. +// +// The result of a comparison should be a bool. +// +// Expected output: 11 + +print(3>=2) +Int a := 3 +print(a>=3) diff --git a/src/test/resources/testPrograms/expressions/BinaryOperatorGreaterEqual1.output b/src/test/resources/testPrograms/expressions/BinaryOperatorGreaterEqual1.output new file mode 100644 index 0000000..9d60796 --- /dev/null +++ b/src/test/resources/testPrograms/expressions/BinaryOperatorGreaterEqual1.output @@ -0,0 +1 @@ +11 \ No newline at end of file diff --git a/src/test/resources/testPrograms/expressions/BinaryOperatorGreaterEqual2.monty b/src/test/resources/testPrograms/expressions/BinaryOperatorGreaterEqual2.monty new file mode 100644 index 0000000..34e1099 --- /dev/null +++ b/src/test/resources/testPrograms/expressions/BinaryOperatorGreaterEqual2.monty @@ -0,0 +1,9 @@ +// Testing: The operator >= on float. +// +// The result of a comparison should be a bool. +// +// Expected output: 11 + +print(3.3>=1.0) +Float a := 3.789 +print(a>=3.789) diff --git a/src/test/resources/testPrograms/expressions/BinaryOperatorGreaterEqual2.output b/src/test/resources/testPrograms/expressions/BinaryOperatorGreaterEqual2.output new file mode 100644 index 0000000..9d60796 --- /dev/null +++ b/src/test/resources/testPrograms/expressions/BinaryOperatorGreaterEqual2.output @@ -0,0 +1 @@ +11 \ No newline at end of file diff --git a/src/test/resources/testPrograms/expressions/BinaryOperatorLess1.monty b/src/test/resources/testPrograms/expressions/BinaryOperatorLess1.monty new file mode 100644 index 0000000..33132d4 --- /dev/null +++ b/src/test/resources/testPrograms/expressions/BinaryOperatorLess1.monty @@ -0,0 +1,9 @@ +// Testing: The operator < on int. +// +// The result of a comparison should be a bool. +// +// Expected output: 10 + +print(2<3) +Int a := 3 +print(a<1) diff --git a/src/test/resources/testPrograms/expressions/BinaryOperatorLess1.output b/src/test/resources/testPrograms/expressions/BinaryOperatorLess1.output new file mode 100644 index 0000000..9a03714 --- /dev/null +++ b/src/test/resources/testPrograms/expressions/BinaryOperatorLess1.output @@ -0,0 +1 @@ +10 \ No newline at end of file diff --git a/src/test/resources/testPrograms/expressions/BinaryOperatorLess2.monty b/src/test/resources/testPrograms/expressions/BinaryOperatorLess2.monty new file mode 100644 index 0000000..aa7e194 --- /dev/null +++ b/src/test/resources/testPrograms/expressions/BinaryOperatorLess2.monty @@ -0,0 +1,10 @@ +// Testing: The operator < on float. +// +// The result of a comparison should be a bool. +// +// Expected output: 110 + +print(2.0<3.0) +Float a := 4.9 +print(a<5.0) +print(3.0 < -2.3) diff --git a/src/test/resources/testPrograms/expressions/BinaryOperatorLess2.output b/src/test/resources/testPrograms/expressions/BinaryOperatorLess2.output new file mode 100644 index 0000000..97e3504 --- /dev/null +++ b/src/test/resources/testPrograms/expressions/BinaryOperatorLess2.output @@ -0,0 +1 @@ +110 \ No newline at end of file diff --git a/src/test/resources/testPrograms/expressions/BinaryOperatorLessEqual1.monty b/src/test/resources/testPrograms/expressions/BinaryOperatorLessEqual1.monty new file mode 100644 index 0000000..5f44c5e --- /dev/null +++ b/src/test/resources/testPrograms/expressions/BinaryOperatorLessEqual1.monty @@ -0,0 +1,9 @@ +// Testing: The operator <= on int. +// +// The result of a comparison should be a bool. +// +// Expected output: 11 + +print(2<=3) +Int a := 3 +print(a<=3) diff --git a/src/test/resources/testPrograms/expressions/BinaryOperatorLessEqual1.output b/src/test/resources/testPrograms/expressions/BinaryOperatorLessEqual1.output new file mode 100644 index 0000000..9d60796 --- /dev/null +++ b/src/test/resources/testPrograms/expressions/BinaryOperatorLessEqual1.output @@ -0,0 +1 @@ +11 \ No newline at end of file diff --git a/src/test/resources/testPrograms/expressions/BinaryOperatorLessEqual2.monty b/src/test/resources/testPrograms/expressions/BinaryOperatorLessEqual2.monty new file mode 100644 index 0000000..af4ef28 --- /dev/null +++ b/src/test/resources/testPrograms/expressions/BinaryOperatorLessEqual2.monty @@ -0,0 +1,9 @@ +// Testing: The operator <= on float. +// +// The result of a comparison should be a bool. +// +// Expected output: 11 + +print(2.0<=3.3) +Float a := 3.789 +print(a<=3.789) diff --git a/src/test/resources/testPrograms/expressions/BinaryOperatorLessEqual2.output b/src/test/resources/testPrograms/expressions/BinaryOperatorLessEqual2.output new file mode 100644 index 0000000..9d60796 --- /dev/null +++ b/src/test/resources/testPrograms/expressions/BinaryOperatorLessEqual2.output @@ -0,0 +1 @@ +11 \ No newline at end of file diff --git a/src/test/resources/testPrograms/expressions/BinaryOperatorModulo1.monty b/src/test/resources/testPrograms/expressions/BinaryOperatorModulo1.monty new file mode 100644 index 0000000..1c0b61a --- /dev/null +++ b/src/test/resources/testPrograms/expressions/BinaryOperatorModulo1.monty @@ -0,0 +1,11 @@ +// Testing: The operator '%' on int. +// +// The result of an '%' should be an int. +// +// Expected output: 1038 + +Int b := 10 % 3 +print(b) +print(9000 % 5) +print(47 % 4) +print(8 % 10) diff --git a/src/test/resources/testPrograms/expressions/BinaryOperatorModulo1.output b/src/test/resources/testPrograms/expressions/BinaryOperatorModulo1.output new file mode 100644 index 0000000..0f746c7 --- /dev/null +++ b/src/test/resources/testPrograms/expressions/BinaryOperatorModulo1.output @@ -0,0 +1 @@ +1038 \ No newline at end of file diff --git a/src/test/resources/testPrograms/expressions/BinaryOperatorMul1.monty b/src/test/resources/testPrograms/expressions/BinaryOperatorMul1.monty new file mode 100644 index 0000000..2500cbf --- /dev/null +++ b/src/test/resources/testPrograms/expressions/BinaryOperatorMul1.monty @@ -0,0 +1,11 @@ +// Testing: The operator * on int. +// +// The result of an multiplication should be an int. +// +// Expected output: 63 + +Int b := 2*3 +print(b) + +Int a := 3 +print(a*1) diff --git a/src/test/resources/testPrograms/expressions/BinaryOperatorMul1.output b/src/test/resources/testPrograms/expressions/BinaryOperatorMul1.output new file mode 100644 index 0000000..4e9e288 --- /dev/null +++ b/src/test/resources/testPrograms/expressions/BinaryOperatorMul1.output @@ -0,0 +1 @@ +63 \ No newline at end of file diff --git a/src/test/resources/testPrograms/expressions/BinaryOperatorMul2.monty b/src/test/resources/testPrograms/expressions/BinaryOperatorMul2.monty new file mode 100644 index 0000000..126608b --- /dev/null +++ b/src/test/resources/testPrograms/expressions/BinaryOperatorMul2.monty @@ -0,0 +1,11 @@ +// Testing: The operator * on float. +// +// The result of an multiplication should be an int. +// +// Expected output: 53.75 + +Float b := 2.5*2.0 +print(b) + +Float a := 1.25 +print(a*3.0) diff --git a/src/test/resources/testPrograms/expressions/BinaryOperatorMul2.output b/src/test/resources/testPrograms/expressions/BinaryOperatorMul2.output new file mode 100644 index 0000000..975e6b8 --- /dev/null +++ b/src/test/resources/testPrograms/expressions/BinaryOperatorMul2.output @@ -0,0 +1 @@ +53.75 \ No newline at end of file diff --git a/src/test/resources/testPrograms/expressions/BinaryOperatorOr1.monty b/src/test/resources/testPrograms/expressions/BinaryOperatorOr1.monty new file mode 100644 index 0000000..ab271e8 --- /dev/null +++ b/src/test/resources/testPrograms/expressions/BinaryOperatorOr1.monty @@ -0,0 +1,11 @@ +// Testing: The operator 'or' on bool. +// +// The result of an 'or' should be an bool. +// +// Expected output: 1101 + +Bool b := true or false +print(b) +print(false or true) +print(false or false) +print(true or true) diff --git a/src/test/resources/testPrograms/expressions/BinaryOperatorOr1.output b/src/test/resources/testPrograms/expressions/BinaryOperatorOr1.output new file mode 100644 index 0000000..1ea87ef --- /dev/null +++ b/src/test/resources/testPrograms/expressions/BinaryOperatorOr1.output @@ -0,0 +1 @@ +1101 \ No newline at end of file diff --git a/src/test/resources/testPrograms/expressions/BinaryOperatorSub1.monty b/src/test/resources/testPrograms/expressions/BinaryOperatorSub1.monty new file mode 100644 index 0000000..3fdcd76 --- /dev/null +++ b/src/test/resources/testPrograms/expressions/BinaryOperatorSub1.monty @@ -0,0 +1,10 @@ +// Testing: The operator - on int. +// +// The result of an subtraction should be an int. +// +// Expected output: -51 + +Int b := 3-8 +print(b) +Int a := -1 +print(a+2) \ No newline at end of file diff --git a/src/test/resources/testPrograms/expressions/BinaryOperatorSub1.output b/src/test/resources/testPrograms/expressions/BinaryOperatorSub1.output new file mode 100644 index 0000000..f33fb37 --- /dev/null +++ b/src/test/resources/testPrograms/expressions/BinaryOperatorSub1.output @@ -0,0 +1 @@ +-51 \ No newline at end of file diff --git a/src/test/resources/testPrograms/expressions/BinaryOperatorSub2.monty b/src/test/resources/testPrograms/expressions/BinaryOperatorSub2.monty new file mode 100644 index 0000000..edbb805 --- /dev/null +++ b/src/test/resources/testPrograms/expressions/BinaryOperatorSub2.monty @@ -0,0 +1,10 @@ +// Testing: The operator - on float. +// +// The result of an subtraction should be an float. +// +// Expected output: 3-7.275 + +Float b := 3.5-0.5 +print(b) +Float a := 2.725 +print(a-10.0) \ No newline at end of file diff --git a/src/test/resources/testPrograms/expressions/BinaryOperatorSub2.output b/src/test/resources/testPrograms/expressions/BinaryOperatorSub2.output new file mode 100644 index 0000000..f52d3b2 --- /dev/null +++ b/src/test/resources/testPrograms/expressions/BinaryOperatorSub2.output @@ -0,0 +1 @@ +3-7.275 \ No newline at end of file diff --git a/src/test/resources/testPrograms/expressions/BinaryOperatorXor1.monty b/src/test/resources/testPrograms/expressions/BinaryOperatorXor1.monty new file mode 100644 index 0000000..31e3418 --- /dev/null +++ b/src/test/resources/testPrograms/expressions/BinaryOperatorXor1.monty @@ -0,0 +1,11 @@ +// Testing: The operator 'xor' on bool. +// +// The result of an 'xor' should be an bool. +// +// Expected output: 0110 + +Bool b := false xor false +print(b) +print(false xor true) +print(true xor false) +print(true xor true) diff --git a/src/test/resources/testPrograms/expressions/BinaryOperatorXor1.output b/src/test/resources/testPrograms/expressions/BinaryOperatorXor1.output new file mode 100644 index 0000000..f4396d0 --- /dev/null +++ b/src/test/resources/testPrograms/expressions/BinaryOperatorXor1.output @@ -0,0 +1 @@ +0110 \ No newline at end of file diff --git a/src/test/resources/testPrograms/expressions/ConditionalExpressionComplex.monty b/src/test/resources/testPrograms/expressions/ConditionalExpressionComplex.monty new file mode 100644 index 0000000..99c4aa9 --- /dev/null +++ b/src/test/resources/testPrograms/expressions/ConditionalExpressionComplex.monty @@ -0,0 +1,27 @@ +// Testing: ConditionalExpression with functions with side effects. +// +// The function dontPrint() should never be called, function doPrint() two +// times. +// +// Expected output: OkOkOk + +Bool functionTrue(): + return true + +Bool functionFalse(): + return false + +String dontPrint(): + print("Nope") + return "Nope" + +String doPrint(): + print("Ok") + return "Ok" + +output(): + String var1 := doPrint() if functionTrue() else dontPrint() + String var2 := dontPrint() if functionFalse() else doPrint() + print(var1 if true else var2) + +output() diff --git a/src/test/resources/testPrograms/expressions/ConditionalExpressionComplex.output b/src/test/resources/testPrograms/expressions/ConditionalExpressionComplex.output new file mode 100644 index 0000000..9d604ae --- /dev/null +++ b/src/test/resources/testPrograms/expressions/ConditionalExpressionComplex.output @@ -0,0 +1 @@ +OkOkOk \ No newline at end of file diff --git a/src/test/resources/testPrograms/expressions/ConditionalExpressionFalse1.monty b/src/test/resources/testPrograms/expressions/ConditionalExpressionFalse1.monty new file mode 100644 index 0000000..ba74504 --- /dev/null +++ b/src/test/resources/testPrograms/expressions/ConditionalExpressionFalse1.monty @@ -0,0 +1,7 @@ +// Testing: ConditionalExpression with simple expressions. +// +// The condition is false, so the else part should be returned. +// +// Expected output: 24 + +print(42 if false else 24) diff --git a/src/test/resources/testPrograms/expressions/ConditionalExpressionFalse1.output b/src/test/resources/testPrograms/expressions/ConditionalExpressionFalse1.output new file mode 100644 index 0000000..cabf43b --- /dev/null +++ b/src/test/resources/testPrograms/expressions/ConditionalExpressionFalse1.output @@ -0,0 +1 @@ +24 \ No newline at end of file diff --git a/src/test/resources/testPrograms/expressions/ConditionalExpressionFalse2.monty b/src/test/resources/testPrograms/expressions/ConditionalExpressionFalse2.monty new file mode 100644 index 0000000..9acd37e --- /dev/null +++ b/src/test/resources/testPrograms/expressions/ConditionalExpressionFalse2.monty @@ -0,0 +1,9 @@ +// Testing: ConditionalExpression with variable accesses as expressions. +// +// The condition is false, so the else part should be returned. +// +// Expected output: Welt + +String hallo := "Hallo" +String welt := "Welt" +print(hallo if 5 < 4 else welt) diff --git a/src/test/resources/testPrograms/expressions/ConditionalExpressionFalse2.output b/src/test/resources/testPrograms/expressions/ConditionalExpressionFalse2.output new file mode 100644 index 0000000..934937a --- /dev/null +++ b/src/test/resources/testPrograms/expressions/ConditionalExpressionFalse2.output @@ -0,0 +1 @@ +Welt \ No newline at end of file diff --git a/src/test/resources/testPrograms/expressions/ConditionalExpressionFalse3.monty b/src/test/resources/testPrograms/expressions/ConditionalExpressionFalse3.monty new file mode 100644 index 0000000..a5d1860 --- /dev/null +++ b/src/test/resources/testPrograms/expressions/ConditionalExpressionFalse3.monty @@ -0,0 +1,9 @@ +// Testing: ConditionalExpression with complex expressions. +// +// The condition is false, so the else part should be returned. +// +// Expected output: 42 + +Int a := 12 +Int b := 21 +print((a * 2) if false else (b * 2)) diff --git a/src/test/resources/testPrograms/expressions/ConditionalExpressionFalse3.output b/src/test/resources/testPrograms/expressions/ConditionalExpressionFalse3.output new file mode 100644 index 0000000..f70d7bb --- /dev/null +++ b/src/test/resources/testPrograms/expressions/ConditionalExpressionFalse3.output @@ -0,0 +1 @@ +42 \ No newline at end of file diff --git a/src/test/resources/testPrograms/expressions/ConditionalExpressionTrue1.monty b/src/test/resources/testPrograms/expressions/ConditionalExpressionTrue1.monty new file mode 100644 index 0000000..0b8dac1 --- /dev/null +++ b/src/test/resources/testPrograms/expressions/ConditionalExpressionTrue1.monty @@ -0,0 +1,7 @@ +// Testing: ConditionalExpression with simple expressions. +// +// The condition is true, so the first part should be returned. +// +// Expected output: 42 + +print(42 if true else 24) diff --git a/src/test/resources/testPrograms/expressions/ConditionalExpressionTrue1.output b/src/test/resources/testPrograms/expressions/ConditionalExpressionTrue1.output new file mode 100644 index 0000000..f70d7bb --- /dev/null +++ b/src/test/resources/testPrograms/expressions/ConditionalExpressionTrue1.output @@ -0,0 +1 @@ +42 \ No newline at end of file diff --git a/src/test/resources/testPrograms/expressions/ConditionalExpressionTrue2.monty b/src/test/resources/testPrograms/expressions/ConditionalExpressionTrue2.monty new file mode 100644 index 0000000..7fca568 --- /dev/null +++ b/src/test/resources/testPrograms/expressions/ConditionalExpressionTrue2.monty @@ -0,0 +1,9 @@ +// Testing: ConditionalExpression with variable accesses as expressions. +// +// The condition is true, so the first part should be returned. +// +// Expected output: Hallo + +String hallo := "Hallo" +String welt := "Welt" +print(hallo if 3 < 4 else welt) diff --git a/src/test/resources/testPrograms/expressions/ConditionalExpressionTrue2.output b/src/test/resources/testPrograms/expressions/ConditionalExpressionTrue2.output new file mode 100644 index 0000000..53f5007 --- /dev/null +++ b/src/test/resources/testPrograms/expressions/ConditionalExpressionTrue2.output @@ -0,0 +1 @@ +Hallo \ No newline at end of file diff --git a/src/test/resources/testPrograms/expressions/ConditionalExpressionTrue3.monty b/src/test/resources/testPrograms/expressions/ConditionalExpressionTrue3.monty new file mode 100644 index 0000000..93ee8ca --- /dev/null +++ b/src/test/resources/testPrograms/expressions/ConditionalExpressionTrue3.monty @@ -0,0 +1,9 @@ +// Testing: ConditionalExpression with complex expressions. +// +// The condition is true, so the first part should be returned. +// +// Expected output: 24 + +Int a := 12 +Int b := 21 +print((a * 2) if true else (b * 2)) diff --git a/src/test/resources/testPrograms/expressions/ConditionalExpressionTrue3.output b/src/test/resources/testPrograms/expressions/ConditionalExpressionTrue3.output new file mode 100644 index 0000000..cabf43b --- /dev/null +++ b/src/test/resources/testPrograms/expressions/ConditionalExpressionTrue3.output @@ -0,0 +1 @@ +24 \ No newline at end of file diff --git a/src/test/resources/testPrograms/expressions/SelfDefinedOperators.monty b/src/test/resources/testPrograms/expressions/SelfDefinedOperators.monty new file mode 100644 index 0000000..15e4a4c --- /dev/null +++ b/src/test/resources/testPrograms/expressions/SelfDefinedOperators.monty @@ -0,0 +1,93 @@ +// Testing: User defined operators. +// +// The user must be able to define operators on some class. +// +// Expected output: operator_unary-operator+operator-operator*operator/ +// operator%operatoroperator<=operator>=operator= +// operator!=operator_notoperator_xoroperator_andoperator_or + +class SomeClass: + + SomeClass operator-(): + print("operator_unary-") + return self + + + SomeClass operator+(SomeClass other): + print("operator+") + return self + + + SomeClass operator-(SomeClass other): + print("operator-") + return self + + + SomeClass operator*(SomeClass other): + print("operator*") + return self + + + SomeClass operator/(SomeClass other): + print("operator/") + return self + + + SomeClass operator%(SomeClass other): + print("operator%") + return self + + + SomeClass operator<(SomeClass other): + print("operator<") + return self + + + SomeClass operator>(SomeClass other): + print("operator>") + return self + + + SomeClass operator<=(SomeClass other): + print("operator<=") + return self + + + SomeClass operator>=(SomeClass other): + print("operator>=") + return self + + + SomeClass operator=(SomeClass other): + print("operator=") + return self + + + SomeClass operator!=(SomeClass other): + print("operator!=") + return self + + + SomeClass operator_not(): + print("operator_not") + return self + + + SomeClass operator_xor(SomeClass other): + print("operator_xor") + return self + + + SomeClass operator_and(SomeClass other): + print("operator_and") + return self + + + SomeClass operator_or(SomeClass other): + print("operator_or") + return self + +SomeClass foo := SomeClass() +SomeClass bar := SomeClass() +SomeClass result := SomeClass() + +result := -bar +result := foo + bar +result := foo - bar +result := foo * bar +result := foo / bar +result := foo % bar +result := foo < bar +result := foo > bar +result := foo <= bar +result := foo >= bar +result := foo = bar +result := foo != bar +result := not bar +result := foo xor bar +result := foo and bar +result := foo or bar diff --git a/src/test/resources/testPrograms/expressions/SelfDefinedOperators.output b/src/test/resources/testPrograms/expressions/SelfDefinedOperators.output new file mode 100644 index 0000000..eb7d66a --- /dev/null +++ b/src/test/resources/testPrograms/expressions/SelfDefinedOperators.output @@ -0,0 +1 @@ +operator_unary-operator+operator-operator*operator/operator%operatoroperator<=operator>=operator=operator!=operator_notoperator_xoroperator_andoperator_or \ No newline at end of file diff --git a/src/test/resources/testPrograms/expressions/UnaryOperatorMinus1.monty b/src/test/resources/testPrograms/expressions/UnaryOperatorMinus1.monty new file mode 100644 index 0000000..be21bcf --- /dev/null +++ b/src/test/resources/testPrograms/expressions/UnaryOperatorMinus1.monty @@ -0,0 +1,11 @@ +// Testing: The unary operator '-" on Int. +// +// The expression should be negated. +// +// Expected output: -5510 + +Int a := -5 +print(a) +print(-a) +Int b := -(-10) +print(b) \ No newline at end of file diff --git a/src/test/resources/testPrograms/expressions/UnaryOperatorMinus1.output b/src/test/resources/testPrograms/expressions/UnaryOperatorMinus1.output new file mode 100644 index 0000000..86fb0c4 --- /dev/null +++ b/src/test/resources/testPrograms/expressions/UnaryOperatorMinus1.output @@ -0,0 +1 @@ +-5510 \ No newline at end of file diff --git a/src/test/resources/testPrograms/expressions/UnaryOperatorMinus2.monty b/src/test/resources/testPrograms/expressions/UnaryOperatorMinus2.monty new file mode 100644 index 0000000..dd99d9a --- /dev/null +++ b/src/test/resources/testPrograms/expressions/UnaryOperatorMinus2.monty @@ -0,0 +1,11 @@ +// Testing: The unary operator '-" on Float. +// +// The expression should be negated. +// +// Expected output: -1.751.7512.34 + +Float a := -1.75 +print(a) +print(-a) +Float b := -(-12.34) +print(b) \ No newline at end of file diff --git a/src/test/resources/testPrograms/expressions/UnaryOperatorMinus2.output b/src/test/resources/testPrograms/expressions/UnaryOperatorMinus2.output new file mode 100644 index 0000000..2dca2c9 --- /dev/null +++ b/src/test/resources/testPrograms/expressions/UnaryOperatorMinus2.output @@ -0,0 +1 @@ +-1.751.7512.34 \ No newline at end of file diff --git a/src/test/resources/testPrograms/expressions/UnaryOperatorNot1.monty b/src/test/resources/testPrograms/expressions/UnaryOperatorNot1.monty new file mode 100644 index 0000000..1dfa210 --- /dev/null +++ b/src/test/resources/testPrograms/expressions/UnaryOperatorNot1.monty @@ -0,0 +1,8 @@ +// Testing: UnaryExpression. +// +// The expression should be negated. +// +// Expected output: 10 + +print(not false) +print(not true) diff --git a/src/test/resources/testPrograms/expressions/UnaryOperatorNot1.output b/src/test/resources/testPrograms/expressions/UnaryOperatorNot1.output new file mode 100644 index 0000000..9a03714 --- /dev/null +++ b/src/test/resources/testPrograms/expressions/UnaryOperatorNot1.output @@ -0,0 +1 @@ +10 \ No newline at end of file diff --git a/src/test/resources/testPrograms/inheritance/casting/ClassInheritedCast1.monty b/src/test/resources/testPrograms/inheritance/casting/ClassInheritedCast1.monty new file mode 100644 index 0000000..b808c7f --- /dev/null +++ b/src/test/resources/testPrograms/inheritance/casting/ClassInheritedCast1.monty @@ -0,0 +1,20 @@ +// Testing: ClassDeclaration with single inheritance and casting. +// +// The compiler must cast the expression and call the right method. +// +// Expected output: Ok + +class Ab: + + initializer(): + pass + +class Ba inherits Ab: + + initializer(): + pass + + + methodB(): + print("Ok") + +Ab a := Ba() +Ba b := a as Ba +b.methodB() diff --git a/src/test/resources/testPrograms/inheritance/casting/ClassInheritedCast1.output b/src/test/resources/testPrograms/inheritance/casting/ClassInheritedCast1.output new file mode 100644 index 0000000..077fd65 --- /dev/null +++ b/src/test/resources/testPrograms/inheritance/casting/ClassInheritedCast1.output @@ -0,0 +1 @@ +Ok \ No newline at end of file diff --git a/src/test/resources/testPrograms/inheritance/casting/ClassInheritedCast2.error b/src/test/resources/testPrograms/inheritance/casting/ClassInheritedCast2.error new file mode 100644 index 0000000..e69de29 diff --git a/src/test/resources/testPrograms/inheritance/casting/ClassInheritedCast2.monty b/src/test/resources/testPrograms/inheritance/casting/ClassInheritedCast2.monty new file mode 100644 index 0000000..e0a4b10 --- /dev/null +++ b/src/test/resources/testPrograms/inheritance/casting/ClassInheritedCast2.monty @@ -0,0 +1,21 @@ +// Testing: ClassDeclaration with single inheritance and casting. +// +// The program must fail casting the expression as the expression was never an +// instance of B. The program fails before printing. +// +// Expected output: + +class Ab: + + initializer(): + pass + +class Ba inherits Ab: + + initializer(): + pass + + + methodB(): + print("Nope") + +Ab a := Ab() +Ba b := a as Ba +b.methodB() diff --git a/src/test/resources/testPrograms/inheritance/casting/ClassInheritedUpcast1.monty b/src/test/resources/testPrograms/inheritance/casting/ClassInheritedUpcast1.monty new file mode 100644 index 0000000..c265ebb --- /dev/null +++ b/src/test/resources/testPrograms/inheritance/casting/ClassInheritedUpcast1.monty @@ -0,0 +1,21 @@ +// Testing: ClassDeclaration with single inheritance and upcasting. +// +// The compiler must upcast automatically at an assignment. +// +// Expected output: 1 + +class Ab: + + initializer(Bool value): + self.attr := value + + + Bool attr + + + printIt(): + print(self.attr) + +class Ba inherits Ab: + + initializer(): + parent(Ab).initializer(true) + +Ab b := Ba() +b.printIt() diff --git a/src/test/resources/testPrograms/inheritance/casting/ClassInheritedUpcast1.output b/src/test/resources/testPrograms/inheritance/casting/ClassInheritedUpcast1.output new file mode 100644 index 0000000..56a6051 --- /dev/null +++ b/src/test/resources/testPrograms/inheritance/casting/ClassInheritedUpcast1.output @@ -0,0 +1 @@ +1 \ No newline at end of file diff --git a/src/test/resources/testPrograms/inheritance/casting/ClassInheritedUpcast2.monty b/src/test/resources/testPrograms/inheritance/casting/ClassInheritedUpcast2.monty new file mode 100644 index 0000000..ac133e0 --- /dev/null +++ b/src/test/resources/testPrograms/inheritance/casting/ClassInheritedUpcast2.monty @@ -0,0 +1,24 @@ +// Testing: ClassDeclaration with single inheritance and upcasting. +// +// The compiler must upcast automatically at a function call. +// +// Expected output: 1 + +class Ab: + + initializer(Bool value): + self.attr := value + + + Bool attr + + + printIt(): + print(self.attr) + +class Ba inherits Ab: + + initializer(): + parent(Ab).initializer(true) + +printIt(Ab a): + a.printIt() + +Ba b := Ba() +printIt(b) diff --git a/src/test/resources/testPrograms/inheritance/casting/ClassInheritedUpcast2.output b/src/test/resources/testPrograms/inheritance/casting/ClassInheritedUpcast2.output new file mode 100644 index 0000000..56a6051 --- /dev/null +++ b/src/test/resources/testPrograms/inheritance/casting/ClassInheritedUpcast2.output @@ -0,0 +1 @@ +1 \ No newline at end of file diff --git a/src/test/resources/testPrograms/inheritance/casting/ClassInheritedUpcast3.monty b/src/test/resources/testPrograms/inheritance/casting/ClassInheritedUpcast3.monty new file mode 100644 index 0000000..840bf4e --- /dev/null +++ b/src/test/resources/testPrograms/inheritance/casting/ClassInheritedUpcast3.monty @@ -0,0 +1,25 @@ +// Testing: ClassDeclaration with single inheritance and upcasting. +// +// The compiler must upcast automatically at a return statement. +// +// Expected output: 1 + +class Ab: + + initializer(Bool value): + self.attr := value + + + Bool attr + + + printIt(): + print(self.attr) + +class Ba inherits Ab: + + initializer(): + parent(Ab).initializer(true) + +Ab createIt(): + Ba b := Ba() + return b + +Ab b := createIt() +b.printIt() diff --git a/src/test/resources/testPrograms/inheritance/casting/ClassInheritedUpcast3.output b/src/test/resources/testPrograms/inheritance/casting/ClassInheritedUpcast3.output new file mode 100644 index 0000000..56a6051 --- /dev/null +++ b/src/test/resources/testPrograms/inheritance/casting/ClassInheritedUpcast3.output @@ -0,0 +1 @@ +1 \ No newline at end of file diff --git a/src/test/resources/testPrograms/inheritance/constructor/ConstructorInheritance1.monty b/src/test/resources/testPrograms/inheritance/constructor/ConstructorInheritance1.monty new file mode 100644 index 0000000..6a2b87a --- /dev/null +++ b/src/test/resources/testPrograms/inheritance/constructor/ConstructorInheritance1.monty @@ -0,0 +1,17 @@ +// Testing: ClassDeclaration +// +// The simple initializer call of an inherited class must work. +// +// Expected output: Hi + +class Ab: + + String someAttr + + + initializer(): + print("Hi") + +class Ba inherits Ab: + + initializer(): + parent(Ab).initializer() + +Ba x := Ba() diff --git a/src/test/resources/testPrograms/inheritance/constructor/ConstructorInheritance1.output b/src/test/resources/testPrograms/inheritance/constructor/ConstructorInheritance1.output new file mode 100644 index 0000000..40816a2 --- /dev/null +++ b/src/test/resources/testPrograms/inheritance/constructor/ConstructorInheritance1.output @@ -0,0 +1 @@ +Hi \ No newline at end of file diff --git a/src/test/resources/testPrograms/inheritance/constructor/ConstructorInheritance2.monty b/src/test/resources/testPrograms/inheritance/constructor/ConstructorInheritance2.monty new file mode 100644 index 0000000..0c7d11e --- /dev/null +++ b/src/test/resources/testPrograms/inheritance/constructor/ConstructorInheritance2.monty @@ -0,0 +1,16 @@ +// Testing: ClassDeclaration +// +// The simple initializer call of an inherited class with a parameter must +// work. +// +// Expected output: HALLO + +class Ab: + + initializer(String a): + print(a) + +class Ba inherits Ab: + + initializer(String a): + parent(Ab).initializer(a) + +Ba x := Ba("HALLO") diff --git a/src/test/resources/testPrograms/inheritance/constructor/ConstructorInheritance2.output b/src/test/resources/testPrograms/inheritance/constructor/ConstructorInheritance2.output new file mode 100644 index 0000000..d3327f7 --- /dev/null +++ b/src/test/resources/testPrograms/inheritance/constructor/ConstructorInheritance2.output @@ -0,0 +1 @@ +HALLO \ No newline at end of file diff --git a/src/test/resources/testPrograms/inheritance/constructor/ConstructorInheritance3.monty b/src/test/resources/testPrograms/inheritance/constructor/ConstructorInheritance3.monty new file mode 100644 index 0000000..a76bfd8 --- /dev/null +++ b/src/test/resources/testPrograms/inheritance/constructor/ConstructorInheritance3.monty @@ -0,0 +1,17 @@ +// Testing: ClassDeclaration +// +// The simple initializer call of an inherited class with a variable as +// parameter must work. +// +// Expected output: HALLO + +class Ab: + + initializer(String a): + print(a) + +class Ba inherits Ab: + + initializer(String a): + parent(Ab).initializer(a) + +String hallo := "HALLO" +Ba x := Ba(hallo) diff --git a/src/test/resources/testPrograms/inheritance/constructor/ConstructorInheritance3.output b/src/test/resources/testPrograms/inheritance/constructor/ConstructorInheritance3.output new file mode 100644 index 0000000..d3327f7 --- /dev/null +++ b/src/test/resources/testPrograms/inheritance/constructor/ConstructorInheritance3.output @@ -0,0 +1 @@ +HALLO \ No newline at end of file diff --git a/src/test/resources/testPrograms/inheritance/constructor/ConstructorInheritance4.monty b/src/test/resources/testPrograms/inheritance/constructor/ConstructorInheritance4.monty new file mode 100644 index 0000000..eeb9992 --- /dev/null +++ b/src/test/resources/testPrograms/inheritance/constructor/ConstructorInheritance4.monty @@ -0,0 +1,19 @@ +// Testing: ClassDeclaration +// +// The simple initializer call of an inherited class with a variable as +// parameter and an assignment to an attribute must work. +// +// Expected output: HALLO + +class Ab: + + String someAttr + + + initializer(String a): + self.someAttr := a + +class Ba inherits Ab: + + initializer(String a): + parent(Ab).initializer(a) + +Ba x := Ba("HALLO") +print(x.someAttr) diff --git a/src/test/resources/testPrograms/inheritance/constructor/ConstructorInheritance4.output b/src/test/resources/testPrograms/inheritance/constructor/ConstructorInheritance4.output new file mode 100644 index 0000000..d3327f7 --- /dev/null +++ b/src/test/resources/testPrograms/inheritance/constructor/ConstructorInheritance4.output @@ -0,0 +1 @@ +HALLO \ No newline at end of file diff --git a/src/test/resources/testPrograms/inheritance/is/ClassInheritedIs1.monty b/src/test/resources/testPrograms/inheritance/is/ClassInheritedIs1.monty new file mode 100644 index 0000000..0da4b63 --- /dev/null +++ b/src/test/resources/testPrograms/inheritance/is/ClassInheritedIs1.monty @@ -0,0 +1,15 @@ +// Testing: ClassDeclaration with single inheritance and inheritance check. +// +// The type-check of an instance of A bound to a variable of type A must be +// true. +// +// Expected output: Ok + +class Ab: + pass + +Ab a := Ab() +if (a is Ab): + print("Ok") +else: + print("No") diff --git a/src/test/resources/testPrograms/inheritance/is/ClassInheritedIs1.output b/src/test/resources/testPrograms/inheritance/is/ClassInheritedIs1.output new file mode 100644 index 0000000..077fd65 --- /dev/null +++ b/src/test/resources/testPrograms/inheritance/is/ClassInheritedIs1.output @@ -0,0 +1 @@ +Ok \ No newline at end of file diff --git a/src/test/resources/testPrograms/inheritance/is/ClassInheritedIs2.monty b/src/test/resources/testPrograms/inheritance/is/ClassInheritedIs2.monty new file mode 100644 index 0000000..61a6dce --- /dev/null +++ b/src/test/resources/testPrograms/inheritance/is/ClassInheritedIs2.monty @@ -0,0 +1,18 @@ +// Testing: ClassDeclaration with single inheritance and inheritance check. +// +// The type-check of an instance of B bound to a variable of type A must be +// true as B inherits A. +// +// Expected output: Ok + +class Ab: + pass + +class Ba inherits Ab: + pass + +Ab a := Ba() +if (a is Ba): + print("Ok") +else: + print("No") diff --git a/src/test/resources/testPrograms/inheritance/is/ClassInheritedIs2.output b/src/test/resources/testPrograms/inheritance/is/ClassInheritedIs2.output new file mode 100644 index 0000000..077fd65 --- /dev/null +++ b/src/test/resources/testPrograms/inheritance/is/ClassInheritedIs2.output @@ -0,0 +1 @@ +Ok \ No newline at end of file diff --git a/src/test/resources/testPrograms/inheritance/is/ClassInheritedIs3.monty b/src/test/resources/testPrograms/inheritance/is/ClassInheritedIs3.monty new file mode 100644 index 0000000..cea3b6e --- /dev/null +++ b/src/test/resources/testPrograms/inheritance/is/ClassInheritedIs3.monty @@ -0,0 +1,18 @@ +// Testing: ClassDeclaration with single inheritance and inheritance check. +// +// The type-check of an instance of B bound to a variable of type A must be +// false. +// +// Expected output: Ok + +class Ab: + pass + +class Ba: + pass + +Ab a := Ab() +if (a is Ba): + print("No") +else: + print("Ok") diff --git a/src/test/resources/testPrograms/inheritance/is/ClassInheritedIs3.output b/src/test/resources/testPrograms/inheritance/is/ClassInheritedIs3.output new file mode 100644 index 0000000..077fd65 --- /dev/null +++ b/src/test/resources/testPrograms/inheritance/is/ClassInheritedIs3.output @@ -0,0 +1 @@ +Ok \ No newline at end of file diff --git a/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberBool1.monty b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberBool1.monty new file mode 100644 index 0000000..5ccc12c --- /dev/null +++ b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberBool1.monty @@ -0,0 +1,19 @@ +// Testing: VariableDeclaration in ClassDeclaration with single inheritance. +// +// The boolean inherited attribute is written and printed. The access via self +// must work. +// +// Expected output: 1 + +class Ab: + + initializer(): + self.attr := true + + + Bool attr + +class Ba inherits Ab: + + initializer(): + parent(Ab).initializer() + print(self.attr) + +Ba b := Ba() diff --git a/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberBool1.output b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberBool1.output new file mode 100644 index 0000000..56a6051 --- /dev/null +++ b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberBool1.output @@ -0,0 +1 @@ +1 \ No newline at end of file diff --git a/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberBool2.monty b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberBool2.monty new file mode 100644 index 0000000..b84f692 --- /dev/null +++ b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberBool2.monty @@ -0,0 +1,19 @@ +// Testing: VariableDeclaration in ClassDeclaration with single inheritance. +// +// The boolean inherited attribute is written and printed from outside the +// class. The access via self and the member access must work. +// +// Expected output: 1 + +class Ab: + + initializer(): + self.attr := true + + + Bool attr + +class Ba inherits Ab: + + initializer(): + parent(Ab).initializer() + +Ba b := Ba() +print(b.attr) diff --git a/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberBool2.output b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberBool2.output new file mode 100644 index 0000000..56a6051 --- /dev/null +++ b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberBool2.output @@ -0,0 +1 @@ +1 \ No newline at end of file diff --git a/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberBool3.monty b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberBool3.monty new file mode 100644 index 0000000..d6e8c86 --- /dev/null +++ b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberBool3.monty @@ -0,0 +1,21 @@ +// Testing: VariableDeclaration in ClassDeclaration with single inheritance. +// +// A boolean inherited attribute and a local variable exist with the same +// name. Both must be writable and readable. +// +// Expected output: 10 + +class Ab: + + initializer(): + self.attr := true + + + Bool attr + +class Ba inherits Ab: + + initializer(): + parent(Ab).initializer() + Bool attr := false + print(self.attr) + print(attr) + +Ba b := Ba() diff --git a/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberBool3.output b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberBool3.output new file mode 100644 index 0000000..9a03714 --- /dev/null +++ b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberBool3.output @@ -0,0 +1 @@ +10 \ No newline at end of file diff --git a/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberBool4.monty b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberBool4.monty new file mode 100644 index 0000000..3afe1ab --- /dev/null +++ b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberBool4.monty @@ -0,0 +1,20 @@ +// Testing: VariableDeclaration in ClassDeclaration with single inheritance. +// +// The boolean inherited attribute is written and a copy printed. The access +// via self must work. +// +// Expected output: 1 + +class Ab: + + initializer(): + self.attr := true + + + Bool attr + +class Ba inherits Ab: + + initializer(): + parent(Ab).initializer() + Bool copy := self.attr + print(copy) + +Ba b := Ba() diff --git a/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberBool4.output b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberBool4.output new file mode 100644 index 0000000..56a6051 --- /dev/null +++ b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberBool4.output @@ -0,0 +1 @@ +1 \ No newline at end of file diff --git a/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberChar1.monty b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberChar1.monty new file mode 100644 index 0000000..06d6f98 --- /dev/null +++ b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberChar1.monty @@ -0,0 +1,19 @@ +// Testing: VariableDeclaration in ClassDeclaration with single inheritance. +// +// The char inherited attribute is written and printed. The access via self +// must work. +// +// Expected output: M + +class Ab: + + initializer(): + self.attr := 'M' + + + Char attr + +class Ba inherits Ab: + + initializer(): + parent(Ab).initializer() + print(self.attr) + +Ba b := Ba() diff --git a/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberChar1.output b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberChar1.output new file mode 100644 index 0000000..ef6bce1 --- /dev/null +++ b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberChar1.output @@ -0,0 +1 @@ +M \ No newline at end of file diff --git a/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberChar2.monty b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberChar2.monty new file mode 100644 index 0000000..df44695 --- /dev/null +++ b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberChar2.monty @@ -0,0 +1,19 @@ +// Testing: VariableDeclaration in ClassDeclaration with single inheritance. +// +// The char inherited attribute is written and printed from outside the +// class. The access via self and the member access must work. +// +// Expected output: M + +class Ab: + + initializer(): + self.attr := 'M' + + + Char attr + +class Ba inherits Ab: + + initializer(): + parent(Ab).initializer() + +Ba b := Ba() +print(b.attr) diff --git a/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberChar2.output b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberChar2.output new file mode 100644 index 0000000..ef6bce1 --- /dev/null +++ b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberChar2.output @@ -0,0 +1 @@ +M \ No newline at end of file diff --git a/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberChar3.monty b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberChar3.monty new file mode 100644 index 0000000..9bab333 --- /dev/null +++ b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberChar3.monty @@ -0,0 +1,21 @@ +// Testing: VariableDeclaration in ClassDeclaration with single inheritance. +// +// A boolean inherited attribute and a local variable exist with the same +// name. Both must be writable and readable. +// +// Expected output: JO + +class Ab: + + initializer(): + self.attr := 'J' + + + Char attr + +class Ba inherits Ab: + + initializer(): + parent(Ab).initializer() + Char attr := 'O' + print(self.attr) + print(attr) + +Ba b := Ba() diff --git a/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberChar3.output b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberChar3.output new file mode 100644 index 0000000..444a896 --- /dev/null +++ b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberChar3.output @@ -0,0 +1 @@ +JO \ No newline at end of file diff --git a/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberChar4.monty b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberChar4.monty new file mode 100644 index 0000000..fbdaf3f --- /dev/null +++ b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberChar4.monty @@ -0,0 +1,20 @@ +// Testing: VariableDeclaration in ClassDeclaration with single inheritance. +// +// The boolean inherited attribute is written and a copy printed. The access +// via self must work. +// +// Expected output: M + +class Ab: + + initializer(): + self.attr := 'M' + + + Char attr + +class Ba inherits Ab: + + initializer(): + parent(Ab).initializer() + Char copy := self.attr + print(copy) + +Ba b := Ba() diff --git a/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberChar4.output b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberChar4.output new file mode 100644 index 0000000..ef6bce1 --- /dev/null +++ b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberChar4.output @@ -0,0 +1 @@ +M \ No newline at end of file diff --git a/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberComplex1.monty b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberComplex1.monty new file mode 100644 index 0000000..2304f10 --- /dev/null +++ b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberComplex1.monty @@ -0,0 +1,25 @@ +// Testing: VariableDeclaration in ClassDeclaration with single inheritance. +// +// A complex expression of chained inherited attributes must be accessible and +// readable. +// +// Expected output: Hallo Welt + +class Ab: + + String attr + + + initializer(): + self.attr := "Hallo Welt" + +class Ba inherits Ab: + + initializer(): + parent(Ab).initializer() + +class Ca: + + Ba attr + + + initializer(): + self.attr := Ba() + +Ca inst := Ca() +print(inst.attr.attr) diff --git a/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberComplex1.output b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberComplex1.output new file mode 100644 index 0000000..a92550c --- /dev/null +++ b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberComplex1.output @@ -0,0 +1 @@ +Hallo Welt \ No newline at end of file diff --git a/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberComplex2.monty b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberComplex2.monty new file mode 100644 index 0000000..20b004d --- /dev/null +++ b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberComplex2.monty @@ -0,0 +1,26 @@ +// Testing: VariableDeclaration in ClassDeclaration with single inheritance. +// +// A complex expression of chained inherited attributes must be accessible, +// writable and readable. +// +// Expected output: Hallo Welt + +class Ab: + + String attr + + + initializer(): + self.attr := "Nope" + +class Ba inherits Ab: + + initializer(): + parent(Ab).initializer() + +class Ca: + + Ba attr + + + initializer(): + self.attr := Ba() + +Ca inst := Ca() +inst.attr.attr := "Hallo Welt" +print(inst.attr.attr) diff --git a/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberComplex2.output b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberComplex2.output new file mode 100644 index 0000000..a92550c --- /dev/null +++ b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberComplex2.output @@ -0,0 +1 @@ +Hallo Welt \ No newline at end of file diff --git a/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberFloat1.monty b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberFloat1.monty new file mode 100644 index 0000000..9cbbaa9 --- /dev/null +++ b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberFloat1.monty @@ -0,0 +1,19 @@ +// Testing: VariableDeclaration in ClassDeclaration with single inheritance. +// +// The float inherited attribute is written and printed. The access via self +// must work. +// +// Expected output: 1.3 + +class Ab: + + initializer(): + self.attr := 1.3 + + + Float attr + +class Ba inherits Ab: + + initializer(): + parent(Ab).initializer() + print(self.attr) + +Ba b := Ba() diff --git a/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberFloat1.output b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberFloat1.output new file mode 100644 index 0000000..a58941b --- /dev/null +++ b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberFloat1.output @@ -0,0 +1 @@ +1.3 \ No newline at end of file diff --git a/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberFloat2.monty b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberFloat2.monty new file mode 100644 index 0000000..83a4fe1 --- /dev/null +++ b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberFloat2.monty @@ -0,0 +1,19 @@ +// Testing: VariableDeclaration in ClassDeclaration with single inheritance. +// +// The float inherited attribute is written and printed from outside the +// class. The access via self and the member access must work. +// +// Expected output: 1.3 + +class Ab: + + initializer(): + self.attr := 1.3 + + + Float attr + +class Ba inherits Ab: + + initializer(): + parent(Ab).initializer() + +Ba b := Ba() +print(b.attr) diff --git a/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberFloat2.output b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberFloat2.output new file mode 100644 index 0000000..a58941b --- /dev/null +++ b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberFloat2.output @@ -0,0 +1 @@ +1.3 \ No newline at end of file diff --git a/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberFloat3.monty b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberFloat3.monty new file mode 100644 index 0000000..e76a81e --- /dev/null +++ b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberFloat3.monty @@ -0,0 +1,21 @@ +// Testing: VariableDeclaration in ClassDeclaration with single inheritance. +// +// A float inherited attribute and a local variable exist with the same name. +// Both must be writable and readable. +// +// Expected output: 1.33.1 + +class Ab: + + initializer(): + self.attr := 1.3 + + + Float attr + +class Ba inherits Ab: + + initializer(): + parent(Ab).initializer() + Float attr := 3.1 + print(self.attr) + print(attr) + +Ba b := Ba() diff --git a/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberFloat3.output b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberFloat3.output new file mode 100644 index 0000000..9e9fac3 --- /dev/null +++ b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberFloat3.output @@ -0,0 +1 @@ +1.33.1 \ No newline at end of file diff --git a/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberFloat4.monty b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberFloat4.monty new file mode 100644 index 0000000..1d18245 --- /dev/null +++ b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberFloat4.monty @@ -0,0 +1,20 @@ +// Testing: VariableDeclaration in ClassDeclaration with single inheritance. +// +// The float attribute is written and a copy printed. The access via self +// must work. +// +// Expected output: 1.3 + +class Ab: + + initializer(): + self.attr := 1.3 + + + Float attr + +class Ba inherits Ab: + + initializer(): + parent(Ab).initializer() + Float copy := self.attr + print(copy) + +Ba b := Ba() diff --git a/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberFloat4.output b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberFloat4.output new file mode 100644 index 0000000..a58941b --- /dev/null +++ b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberFloat4.output @@ -0,0 +1 @@ +1.3 \ No newline at end of file diff --git a/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberInt1.monty b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberInt1.monty new file mode 100644 index 0000000..72d39cc --- /dev/null +++ b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberInt1.monty @@ -0,0 +1,19 @@ +// Testing: VariableDeclaration in ClassDeclaration with single inheritance. +// +// The int inherited attribute is written and printed. The access via self +// must work. +// +// Expected output: 1 + +class Ab: + + initializer(): + self.attr := 1 + + + Int attr + +class Ba inherits Ab: + + initializer(): + parent(Ab).initializer() + print(self.attr) + +Ba b := Ba() diff --git a/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberInt1.output b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberInt1.output new file mode 100644 index 0000000..56a6051 --- /dev/null +++ b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberInt1.output @@ -0,0 +1 @@ +1 \ No newline at end of file diff --git a/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberInt2.monty b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberInt2.monty new file mode 100644 index 0000000..b52c6a3 --- /dev/null +++ b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberInt2.monty @@ -0,0 +1,19 @@ +// Testing: VariableDeclaration in ClassDeclaration with single inheritance. +// +// The int inherited attribute is written and printed from outside the class. +// The access via self and the member access must work. +// +// Expected output: 1 + +class Ab: + + initializer(): + self.attr := 1 + + + Int attr + +class Ba inherits Ab: + + initializer(): + parent(Ab).initializer() + +Ba b := Ba() +print(b.attr) diff --git a/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberInt2.output b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberInt2.output new file mode 100644 index 0000000..56a6051 --- /dev/null +++ b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberInt2.output @@ -0,0 +1 @@ +1 \ No newline at end of file diff --git a/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberInt3.monty b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberInt3.monty new file mode 100644 index 0000000..71291dc --- /dev/null +++ b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberInt3.monty @@ -0,0 +1,21 @@ +// Testing: VariableDeclaration in ClassDeclaration with single inheritance. +// +// An int inherited attribute and a local variable exist with the same name. +// Both must be writable and readable. +// +// Expected output: 10 + +class Ab: + + initializer(): + self.attr := 1 + + + Int attr + +class Ba inherits Ab: + + initializer(): + parent(Ab).initializer() + Int attr := 0 + print(self.attr) + print(attr) + +Ba b := Ba() diff --git a/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberInt3.output b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberInt3.output new file mode 100644 index 0000000..9a03714 --- /dev/null +++ b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberInt3.output @@ -0,0 +1 @@ +10 \ No newline at end of file diff --git a/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberInt4.monty b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberInt4.monty new file mode 100644 index 0000000..4e31485 --- /dev/null +++ b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberInt4.monty @@ -0,0 +1,20 @@ +// Testing: VariableDeclaration in ClassDeclaration with single inheritance. +// +// The int inherited attribute is written and a copy printed. The access via +// self must work. +// +// Expected output: 1 + +class Ab: + + initializer(): + self.attr := 1 + + + Int attr + +class Ba inherits Ab: + + initializer(): + parent(Ab).initializer() + Int copy := self.attr + print(copy) + +Ba b := Ba() diff --git a/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberInt4.output b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberInt4.output new file mode 100644 index 0000000..56a6051 --- /dev/null +++ b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberInt4.output @@ -0,0 +1 @@ +1 \ No newline at end of file diff --git a/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberString1.monty b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberString1.monty new file mode 100644 index 0000000..8940d37 --- /dev/null +++ b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberString1.monty @@ -0,0 +1,19 @@ +// Testing: VariableDeclaration in ClassDeclaration with single inheritance. +// +// The string inherited attribute is written and printed. The access via self +// must work. +// +// Expected output: Hallo + +class Ab: + + initializer(): + self.attr := "Hallo" + + + String attr + +class Ba inherits Ab: + + initializer(): + parent(Ab).initializer() + print(self.attr) + +Ba b := Ba() diff --git a/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberString1.output b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberString1.output new file mode 100644 index 0000000..53f5007 --- /dev/null +++ b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberString1.output @@ -0,0 +1 @@ +Hallo \ No newline at end of file diff --git a/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberString2.monty b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberString2.monty new file mode 100644 index 0000000..9b515f1 --- /dev/null +++ b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberString2.monty @@ -0,0 +1,19 @@ +// Testing: VariableDeclaration in ClassDeclaration with single inheritance. +// +// The string inherited attribute is written and printed from outside the +// class. The access via self and the member access must work. +// +// Expected output: Hallo + +class Ab: + + initializer(): + self.attr := "Hallo" + + + String attr + +class Ba inherits Ab: + + initializer(): + parent(Ab).initializer() + +Ba b := Ba() +print(b.attr) diff --git a/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberString2.output b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberString2.output new file mode 100644 index 0000000..53f5007 --- /dev/null +++ b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberString2.output @@ -0,0 +1 @@ +Hallo \ No newline at end of file diff --git a/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberString3.monty b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberString3.monty new file mode 100644 index 0000000..d47f3c2 --- /dev/null +++ b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberString3.monty @@ -0,0 +1,21 @@ +// Testing: VariableDeclaration in ClassDeclaration with single inheritance. +// +// A string inherited attribute and a local variable exist with the same name. +// Both must be writable and readable. +// +// Expected output: HalloWelt + +class Ab: + + initializer(): + self.attr := "Hallo" + + + String attr + +class Ba inherits Ab: + + initializer(): + parent(Ab).initializer() + String attr := "Welt" + print(self.attr) + print(attr) + +Ba b := Ba() diff --git a/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberString3.output b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberString3.output new file mode 100644 index 0000000..b7b7804 --- /dev/null +++ b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberString3.output @@ -0,0 +1 @@ +HalloWelt \ No newline at end of file diff --git a/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberString4.monty b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberString4.monty new file mode 100644 index 0000000..fd33ada --- /dev/null +++ b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberString4.monty @@ -0,0 +1,20 @@ +// Testing: VariableDeclaration in ClassDeclaration with single inheritance. +// +// The string inherited attribute is written and a copy printed. The access +// via self must work. +// +// Expected output: Hallo + +class Ab: + + initializer(): + self.attr := "Hallo" + + + String attr + +class Ba inherits Ab: + + initializer(): + parent(Ab).initializer() + String copy := self.attr + print(copy) + +Ba b := Ba() diff --git a/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberString4.output b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberString4.output new file mode 100644 index 0000000..53f5007 --- /dev/null +++ b/src/test/resources/testPrograms/inheritance/member/ClassInheritedMemberString4.output @@ -0,0 +1 @@ +Hallo \ No newline at end of file diff --git a/src/test/resources/testPrograms/inheritance/methods/InheritanceMethods1.monty b/src/test/resources/testPrograms/inheritance/methods/InheritanceMethods1.monty new file mode 100644 index 0000000..364add1 --- /dev/null +++ b/src/test/resources/testPrograms/inheritance/methods/InheritanceMethods1.monty @@ -0,0 +1,26 @@ +// Testing: FunctionCall in ClassDeclaration with single inheritance. +// +// The inherited methods (procedure/function) must be callable and do/return +// the right stuff. +// +// Expected output: HelloWorldHelloWorld + +class Ab: + + printHello(): + print("Hello") + + + String returnHello(): + return "Hello" + +class Ba inherits Ab: + + printWorld(): + print("World") + + + String returnWorld(): + return "World" + +Ba b := Ba() +b.printHello() +b.printWorld() +print(b.returnHello()) +print(b.returnWorld()) diff --git a/src/test/resources/testPrograms/inheritance/methods/InheritanceMethods1.output b/src/test/resources/testPrograms/inheritance/methods/InheritanceMethods1.output new file mode 100644 index 0000000..1b52879 --- /dev/null +++ b/src/test/resources/testPrograms/inheritance/methods/InheritanceMethods1.output @@ -0,0 +1 @@ +HelloWorldHelloWorld \ No newline at end of file diff --git a/src/test/resources/testPrograms/inheritance/methods/InheritanceMethods2.monty b/src/test/resources/testPrograms/inheritance/methods/InheritanceMethods2.monty new file mode 100644 index 0000000..b201a2d --- /dev/null +++ b/src/test/resources/testPrograms/inheritance/methods/InheritanceMethods2.monty @@ -0,0 +1,24 @@ +// Testing: FunctionCall in ClassDeclaration with single inheritance. +// +// The inherited overriden methods (procedure/function) must be callable and +// do/return the right stuff. +// +// Expected output: HelloWorldHelloWorld + +class Ab: + + printHelloWorld(): + print("WorldHello") + + + String returnHelloWorld(): + return "WorldHello" + +class Ba inherits Ab: + + printHelloWorld(): + print("HelloWorld") + + + String returnHelloWorld(): + return "HelloWorld" + +Ab b := Ba() +b.printHelloWorld() +print(b.returnHelloWorld()) diff --git a/src/test/resources/testPrograms/inheritance/methods/InheritanceMethods2.output b/src/test/resources/testPrograms/inheritance/methods/InheritanceMethods2.output new file mode 100644 index 0000000..1b52879 --- /dev/null +++ b/src/test/resources/testPrograms/inheritance/methods/InheritanceMethods2.output @@ -0,0 +1 @@ +HelloWorldHelloWorld \ No newline at end of file diff --git a/src/test/resources/testPrograms/literals/BoolAsObject.monty b/src/test/resources/testPrograms/literals/BoolAsObject.monty new file mode 100644 index 0000000..bf5c268 --- /dev/null +++ b/src/test/resources/testPrograms/literals/BoolAsObject.monty @@ -0,0 +1,11 @@ +// Testing: Bool as Object +// +// A bool object must be castable to an Bool +// +// Expected output: 10 + +Object t := true +Object f := false + +print(t as Bool) +print(f as Bool) diff --git a/src/test/resources/testPrograms/literals/BoolAsObject.output b/src/test/resources/testPrograms/literals/BoolAsObject.output new file mode 100644 index 0000000..9a03714 --- /dev/null +++ b/src/test/resources/testPrograms/literals/BoolAsObject.output @@ -0,0 +1 @@ +10 \ No newline at end of file diff --git a/src/test/resources/testPrograms/literals/BoolConstructor.monty b/src/test/resources/testPrograms/literals/BoolConstructor.monty new file mode 100644 index 0000000..3bd4c9e --- /dev/null +++ b/src/test/resources/testPrograms/literals/BoolConstructor.monty @@ -0,0 +1,11 @@ +// Testing: Bool as Object +// +// A bool-initializer call must work. +// +// Expected output: 10 + +Bool t := Bool(true) +Bool f := Bool(false) + +print(t) +print(f) diff --git a/src/test/resources/testPrograms/literals/BoolConstructor.output b/src/test/resources/testPrograms/literals/BoolConstructor.output new file mode 100644 index 0000000..9a03714 --- /dev/null +++ b/src/test/resources/testPrograms/literals/BoolConstructor.output @@ -0,0 +1 @@ +10 \ No newline at end of file diff --git a/src/test/resources/testPrograms/literals/BoolIsObject.monty b/src/test/resources/testPrograms/literals/BoolIsObject.monty new file mode 100644 index 0000000..6b16b76 --- /dev/null +++ b/src/test/resources/testPrograms/literals/BoolIsObject.monty @@ -0,0 +1,17 @@ +// Testing: Bool as Object +// +// A bool must be an Object +// +// Expected output: Ok(Bool)Ok(Bool) + +Object b := true + +if b is Bool: + print("Ok(Bool)") +else: + print("Nope(Bool)") + +if true is Object: + print("Ok(Bool)") +else: + print("Nope(Bool)") diff --git a/src/test/resources/testPrograms/literals/BoolIsObject.output b/src/test/resources/testPrograms/literals/BoolIsObject.output new file mode 100644 index 0000000..7d17351 --- /dev/null +++ b/src/test/resources/testPrograms/literals/BoolIsObject.output @@ -0,0 +1 @@ +Ok(Bool)Ok(Bool) \ No newline at end of file diff --git a/src/test/resources/testPrograms/literals/CharAsObject.monty b/src/test/resources/testPrograms/literals/CharAsObject.monty new file mode 100644 index 0000000..b39e40a --- /dev/null +++ b/src/test/resources/testPrograms/literals/CharAsObject.monty @@ -0,0 +1,10 @@ +// Testing: Char as Object +// +// A char object must be castable to an Char +// +// Expected output: a + +Object c := 'a' + +print(c as Char) + diff --git a/src/test/resources/testPrograms/literals/CharAsObject.output b/src/test/resources/testPrograms/literals/CharAsObject.output new file mode 100644 index 0000000..2e65efe --- /dev/null +++ b/src/test/resources/testPrograms/literals/CharAsObject.output @@ -0,0 +1 @@ +a \ No newline at end of file diff --git a/src/test/resources/testPrograms/literals/CharConstructor.monty b/src/test/resources/testPrograms/literals/CharConstructor.monty new file mode 100644 index 0000000..a673179 --- /dev/null +++ b/src/test/resources/testPrograms/literals/CharConstructor.monty @@ -0,0 +1,9 @@ +// Testing: Char as Object +// +// A char-initializer call must work. +// +// Expected output: a + +Char c := Char('a') + +print(c) diff --git a/src/test/resources/testPrograms/literals/CharConstructor.output b/src/test/resources/testPrograms/literals/CharConstructor.output new file mode 100644 index 0000000..2e65efe --- /dev/null +++ b/src/test/resources/testPrograms/literals/CharConstructor.output @@ -0,0 +1 @@ +a \ No newline at end of file diff --git a/src/test/resources/testPrograms/literals/CharIsObject.monty b/src/test/resources/testPrograms/literals/CharIsObject.monty new file mode 100644 index 0000000..0bada09 --- /dev/null +++ b/src/test/resources/testPrograms/literals/CharIsObject.monty @@ -0,0 +1,17 @@ +// Testing: Char as Object +// +// A char must be an Object +// +// Expected output: Ok(Char)Ok(Char) + +Object c := 'a' + +if c is Char: + print("Ok(Char)") +else: + print("Nope(Char)") + +if 'a' is Object: + print("Ok(Char)") +else: + print("Nope(Char)") diff --git a/src/test/resources/testPrograms/literals/CharIsObject.output b/src/test/resources/testPrograms/literals/CharIsObject.output new file mode 100644 index 0000000..60924ae --- /dev/null +++ b/src/test/resources/testPrograms/literals/CharIsObject.output @@ -0,0 +1 @@ +Ok(Char)Ok(Char) \ No newline at end of file diff --git a/src/test/resources/testPrograms/literals/FloatAsObject.monty b/src/test/resources/testPrograms/literals/FloatAsObject.monty new file mode 100644 index 0000000..29c456e --- /dev/null +++ b/src/test/resources/testPrograms/literals/FloatAsObject.monty @@ -0,0 +1,12 @@ +// Testing: Float as Object +// +// A float object must be castable to an Float +// +// Expected output: 01.3 + +Object z := 0.0 +Object f := 1.3 + +print(z as Float) +print(f as Float) + diff --git a/src/test/resources/testPrograms/literals/FloatAsObject.output b/src/test/resources/testPrograms/literals/FloatAsObject.output new file mode 100644 index 0000000..7056186 --- /dev/null +++ b/src/test/resources/testPrograms/literals/FloatAsObject.output @@ -0,0 +1 @@ +01.3 \ No newline at end of file diff --git a/src/test/resources/testPrograms/literals/FloatConstructor.monty b/src/test/resources/testPrograms/literals/FloatConstructor.monty new file mode 100644 index 0000000..ddba9bd --- /dev/null +++ b/src/test/resources/testPrograms/literals/FloatConstructor.monty @@ -0,0 +1,11 @@ +// Testing: Float as Object +// +// A float-initializer call must work. +// +// Expected output: 01.3 + +Float z := Float(0.0) +Float f := Float(1.3) + +print(z) +print(f) diff --git a/src/test/resources/testPrograms/literals/FloatConstructor.output b/src/test/resources/testPrograms/literals/FloatConstructor.output new file mode 100644 index 0000000..7056186 --- /dev/null +++ b/src/test/resources/testPrograms/literals/FloatConstructor.output @@ -0,0 +1 @@ +01.3 \ No newline at end of file diff --git a/src/test/resources/testPrograms/literals/FloatIsObject.monty b/src/test/resources/testPrograms/literals/FloatIsObject.monty new file mode 100644 index 0000000..efe5f29 --- /dev/null +++ b/src/test/resources/testPrograms/literals/FloatIsObject.monty @@ -0,0 +1,17 @@ +// Testing: Float as Object +// +// A float must be an Object +// +// Expected output: Ok(Float)Ok(Float) + +Object f := 1.3 + +if f is Float: + print("Ok(Float)") +else: + print("Nope(Float)") + +if 0.0 is Object: + print("Ok(Float)") +else: + print("Nope(Float)") diff --git a/src/test/resources/testPrograms/literals/FloatIsObject.output b/src/test/resources/testPrograms/literals/FloatIsObject.output new file mode 100644 index 0000000..f074bff --- /dev/null +++ b/src/test/resources/testPrograms/literals/FloatIsObject.output @@ -0,0 +1 @@ +Ok(Float)Ok(Float) \ No newline at end of file diff --git a/src/test/resources/testPrograms/literals/IntAsObject.monty b/src/test/resources/testPrograms/literals/IntAsObject.monty new file mode 100644 index 0000000..603561e --- /dev/null +++ b/src/test/resources/testPrograms/literals/IntAsObject.monty @@ -0,0 +1,12 @@ +// Testing: Int as Object +// +// An int object must be castable to an Int +// +// Expected output: 042 + +Object z := 0 +Object i := 42 + +print(z as Int) +print(i as Int) + diff --git a/src/test/resources/testPrograms/literals/IntAsObject.output b/src/test/resources/testPrograms/literals/IntAsObject.output new file mode 100644 index 0000000..9f73fc0 --- /dev/null +++ b/src/test/resources/testPrograms/literals/IntAsObject.output @@ -0,0 +1 @@ +042 \ No newline at end of file diff --git a/src/test/resources/testPrograms/literals/IntConstructor.monty b/src/test/resources/testPrograms/literals/IntConstructor.monty new file mode 100644 index 0000000..9160a01 --- /dev/null +++ b/src/test/resources/testPrograms/literals/IntConstructor.monty @@ -0,0 +1,11 @@ +// Testing: Int as Object +// +// An int-initializer call must work. +// +// Expected output: 042 + +Int z := Int(0) +Int i := Int(42) + +print(z) +print(i) diff --git a/src/test/resources/testPrograms/literals/IntConstructor.output b/src/test/resources/testPrograms/literals/IntConstructor.output new file mode 100644 index 0000000..9f73fc0 --- /dev/null +++ b/src/test/resources/testPrograms/literals/IntConstructor.output @@ -0,0 +1 @@ +042 \ No newline at end of file diff --git a/src/test/resources/testPrograms/literals/IntIsObject.monty b/src/test/resources/testPrograms/literals/IntIsObject.monty new file mode 100644 index 0000000..d55f503 --- /dev/null +++ b/src/test/resources/testPrograms/literals/IntIsObject.monty @@ -0,0 +1,17 @@ +// Testing: Int as Object +// +// An int must be an Object +// +// Expected output: Ok(Int)Ok(Int) + +Object i := 42 + +if i is Int: + print("Ok(Int)") +else: + print("Nope(Int)") + +if 0 is Object: + print("Ok(Int)") +else: + print("Nope(Int)") diff --git a/src/test/resources/testPrograms/literals/IntIsObject.output b/src/test/resources/testPrograms/literals/IntIsObject.output new file mode 100644 index 0000000..8bd5ff8 --- /dev/null +++ b/src/test/resources/testPrograms/literals/IntIsObject.output @@ -0,0 +1 @@ +Ok(Int)Ok(Int) \ No newline at end of file diff --git a/src/test/resources/testPrograms/negativ/IdentifierNotDefined.error b/src/test/resources/testPrograms/negativ/IdentifierNotDefined.error new file mode 100644 index 0000000..3f092fe --- /dev/null +++ b/src/test/resources/testPrograms/negativ/IdentifierNotDefined.error @@ -0,0 +1 @@ +ResolveVisitor caught error in null: Identifier is not defined: x \ No newline at end of file diff --git a/src/test/resources/testPrograms/negativ/IdentifierNotDefined.monty b/src/test/resources/testPrograms/negativ/IdentifierNotDefined.monty new file mode 100644 index 0000000..137b95f --- /dev/null +++ b/src/test/resources/testPrograms/negativ/IdentifierNotDefined.monty @@ -0,0 +1,7 @@ +// Testing: Access to undefined variable +// +// Calls the print function with undefined variable x +// +// Expected output: Error + +print(x) \ No newline at end of file diff --git a/src/test/resources/testPrograms/negativ/callable/neg_Function1.error b/src/test/resources/testPrograms/negativ/callable/neg_Function1.error new file mode 100644 index 0000000..ce0d4a5 --- /dev/null +++ b/src/test/resources/testPrograms/negativ/callable/neg_Function1.error @@ -0,0 +1 @@ +ResolveVisitor caught error in null: Identifier is not defined: square \ No newline at end of file diff --git a/src/test/resources/testPrograms/negativ/callable/neg_Function1.monty b/src/test/resources/testPrograms/negativ/callable/neg_Function1.monty new file mode 100644 index 0000000..1983e7c --- /dev/null +++ b/src/test/resources/testPrograms/negativ/callable/neg_Function1.monty @@ -0,0 +1,10 @@ +// Testing: FunctionCall with wrong Paramaters +// +// The function is not called correctly in the print statement. +// +// Expected output: Error + +Int square(Int value): + return value * value + +print(square) \ No newline at end of file diff --git a/src/test/resources/testPrograms/negativ/callable/neg_Function2.error b/src/test/resources/testPrograms/negativ/callable/neg_Function2.error new file mode 100644 index 0000000..4ab72c2 --- /dev/null +++ b/src/test/resources/testPrograms/negativ/callable/neg_Function2.error @@ -0,0 +1 @@ +ResolveVisitor caught error in null: Type is not defined: Boolean \ No newline at end of file diff --git a/src/test/resources/testPrograms/negativ/callable/neg_Function2.monty b/src/test/resources/testPrograms/negativ/callable/neg_Function2.monty new file mode 100644 index 0000000..7fa38f9 --- /dev/null +++ b/src/test/resources/testPrograms/negativ/callable/neg_Function2.monty @@ -0,0 +1,8 @@ +// Testing: FunctionDeclaration +// +// The function is declared with the undefined type 'Boolean'. +// +// Expected output: Error + +Boolean square(Int value): + return value * value \ No newline at end of file diff --git a/src/test/resources/testPrograms/negativ/callable/neg_Function3.error b/src/test/resources/testPrograms/negativ/callable/neg_Function3.error new file mode 100644 index 0000000..aff6352 --- /dev/null +++ b/src/test/resources/testPrograms/negativ/callable/neg_Function3.error @@ -0,0 +1 @@ +TypeCheckVisitor caught error in ReturnStatement at file: neg_Function3.monty, line: 9, char: 1: Expected to return Int: \ No newline at end of file diff --git a/src/test/resources/testPrograms/negativ/callable/neg_Function3.monty b/src/test/resources/testPrograms/negativ/callable/neg_Function3.monty new file mode 100644 index 0000000..744adf0 --- /dev/null +++ b/src/test/resources/testPrograms/negativ/callable/neg_Function3.monty @@ -0,0 +1,9 @@ +// Testing: FunctionDeclaration +// +// The function is missing a declaration type. +// +// Expected output: Error + +Int square(Int value): + String str := "I will cause a TypeMisMatch!" + return str \ No newline at end of file diff --git a/src/test/resources/testPrograms/negativ/callable/neg_Function4.error b/src/test/resources/testPrograms/negativ/callable/neg_Function4.error new file mode 100644 index 0000000..760589c --- /dev/null +++ b/src/test/resources/testPrograms/negativ/callable/neg_Function4.error @@ -0,0 +1 @@ +error \ No newline at end of file diff --git a/src/test/resources/testPrograms/negativ/callable/neg_Function4.monty.ignore b/src/test/resources/testPrograms/negativ/callable/neg_Function4.monty.ignore new file mode 100644 index 0000000..b998577 --- /dev/null +++ b/src/test/resources/testPrograms/negativ/callable/neg_Function4.monty.ignore @@ -0,0 +1,17 @@ +// Testing: FunctionDeclaration & Return +// +// A function must contain a return in every branch of conditional +// statement. +// +// Expected output: Error + +String branch(Int x): + String y + if x = 10: + y := "10" + return y + else: + y := "2" + + +print(branch(1)) \ No newline at end of file diff --git a/src/test/resources/testPrograms/negativ/callable/neg_Procedure1.error b/src/test/resources/testPrograms/negativ/callable/neg_Procedure1.error new file mode 100644 index 0000000..8c09dbb --- /dev/null +++ b/src/test/resources/testPrograms/negativ/callable/neg_Procedure1.error @@ -0,0 +1 @@ +TypeCheckVisitor caught error in ReturnStatement at file: neg_Procedure1.monty, line: 9, char: 1: Expected to return void. \ No newline at end of file diff --git a/src/test/resources/testPrograms/negativ/callable/neg_Procedure1.monty b/src/test/resources/testPrograms/negativ/callable/neg_Procedure1.monty new file mode 100644 index 0000000..4df1380 --- /dev/null +++ b/src/test/resources/testPrograms/negativ/callable/neg_Procedure1.monty @@ -0,0 +1,9 @@ +// Testing: ProcedureDeclaration and ProcedureCall +// +// Procedures can't have return types so they mustn't return +// an expression that evaluates to a type. +// +// Expected output: Error + +square(Int value): + return value \ No newline at end of file diff --git a/src/test/resources/testPrograms/negativ/callable/neg_Procedure2.error b/src/test/resources/testPrograms/negativ/callable/neg_Procedure2.error new file mode 100644 index 0000000..a779e71 --- /dev/null +++ b/src/test/resources/testPrograms/negativ/callable/neg_Procedure2.error @@ -0,0 +1 @@ +TypeCheckVisitor caught error in FunctionCall at file: neg_Procedure2.monty, line: 13, char: 0: Arguments of function call do not match declaration. \ No newline at end of file diff --git a/src/test/resources/testPrograms/negativ/callable/neg_Procedure2.monty b/src/test/resources/testPrograms/negativ/callable/neg_Procedure2.monty new file mode 100644 index 0000000..0b4bc76 --- /dev/null +++ b/src/test/resources/testPrograms/negativ/callable/neg_Procedure2.monty @@ -0,0 +1,13 @@ +// Testing: ProcedureDeclaration & Return +// +// Printing the result of a procedure should end in an error +// or print emtpy String XXXTODO Currently this tests ends in a +// Java NullPointer Exception. +// +// Expected output: Error or Empty String + +calc(Int x): + Int val := x*x + return + +print(calc(2)) \ No newline at end of file diff --git a/src/test/resources/testPrograms/negativ/scoping/RedeclarationOtherType.error b/src/test/resources/testPrograms/negativ/scoping/RedeclarationOtherType.error new file mode 100644 index 0000000..ad6d505 --- /dev/null +++ b/src/test/resources/testPrograms/negativ/scoping/RedeclarationOtherType.error @@ -0,0 +1 @@ +DeclarationVisitor caught error in VariableDeclaration at file: RedeclarationOtherType.monty, line: 9, char: 0: greeting \ No newline at end of file diff --git a/src/test/resources/testPrograms/negativ/scoping/RedeclarationOtherType.monty b/src/test/resources/testPrograms/negativ/scoping/RedeclarationOtherType.monty new file mode 100644 index 0000000..9f7fb3a --- /dev/null +++ b/src/test/resources/testPrograms/negativ/scoping/RedeclarationOtherType.monty @@ -0,0 +1,9 @@ +// Testing: Scope +// +// A Variable must not be redeclarable within the same Scope, +// even if it has a different type. +// +// Expected output: Error + +String greeting := "Guten Morgen" +Bool greeting := true \ No newline at end of file diff --git a/src/test/resources/testPrograms/negativ/scoping/RedeclarationSameType.error b/src/test/resources/testPrograms/negativ/scoping/RedeclarationSameType.error new file mode 100644 index 0000000..56e49a3 --- /dev/null +++ b/src/test/resources/testPrograms/negativ/scoping/RedeclarationSameType.error @@ -0,0 +1 @@ +DeclarationVisitor caught error in VariableDeclaration at file: RedeclarationSameType.monty, line: 8, char: 0: greeting \ No newline at end of file diff --git a/src/test/resources/testPrograms/negativ/scoping/RedeclarationSameType.monty b/src/test/resources/testPrograms/negativ/scoping/RedeclarationSameType.monty new file mode 100644 index 0000000..e135734 --- /dev/null +++ b/src/test/resources/testPrograms/negativ/scoping/RedeclarationSameType.monty @@ -0,0 +1,8 @@ +// Testing: Scope +// +// A Variable must not be redeclarable within the same Scope. +// +// Expected output: Error + +String greeting := "Guten Morgen" +String greeting := "Guten Tag" \ No newline at end of file diff --git a/src/test/resources/testPrograms/negativ/scoping/VariableAccess.error b/src/test/resources/testPrograms/negativ/scoping/VariableAccess.error new file mode 100644 index 0000000..227affb --- /dev/null +++ b/src/test/resources/testPrograms/negativ/scoping/VariableAccess.error @@ -0,0 +1 @@ +ResolveVisitor caught error in null: Identifier is not defined: b \ No newline at end of file diff --git a/src/test/resources/testPrograms/negativ/scoping/VariableAccess.monty b/src/test/resources/testPrograms/negativ/scoping/VariableAccess.monty new file mode 100644 index 0000000..87af7a7 --- /dev/null +++ b/src/test/resources/testPrograms/negativ/scoping/VariableAccess.monty @@ -0,0 +1,9 @@ +// Testing: Lexical scoping +// +// B must not be writable if it is not declared yet. +// +// Expected output: Error + +Int a := 3 +b := a +Int b \ No newline at end of file diff --git a/src/test/resources/testPrograms/negativ/scoping/VariableAccess2.error b/src/test/resources/testPrograms/negativ/scoping/VariableAccess2.error new file mode 100644 index 0000000..ca5a8d9 --- /dev/null +++ b/src/test/resources/testPrograms/negativ/scoping/VariableAccess2.error @@ -0,0 +1 @@ +ResolveVisitor caught error in null: Identifier is not defined: var \ No newline at end of file diff --git a/src/test/resources/testPrograms/negativ/scoping/VariableAccess2.monty b/src/test/resources/testPrograms/negativ/scoping/VariableAccess2.monty new file mode 100644 index 0000000..e4e94d3 --- /dev/null +++ b/src/test/resources/testPrograms/negativ/scoping/VariableAccess2.monty @@ -0,0 +1,13 @@ +// Testing: Lexical scoping +// +// var must be declared & initialized before it can be used in function's decl. +// +// Expected output: Error + +Int function(): + Int copy := var + return copy + +Int var := 42 + +print(function()) diff --git a/src/test/resources/testPrograms/negativ/scoping/VariableAccess3.error b/src/test/resources/testPrograms/negativ/scoping/VariableAccess3.error new file mode 100644 index 0000000..227affb --- /dev/null +++ b/src/test/resources/testPrograms/negativ/scoping/VariableAccess3.error @@ -0,0 +1 @@ +ResolveVisitor caught error in null: Identifier is not defined: b \ No newline at end of file diff --git a/src/test/resources/testPrograms/negativ/scoping/VariableAccess3.monty b/src/test/resources/testPrograms/negativ/scoping/VariableAccess3.monty new file mode 100644 index 0000000..6f3d838 --- /dev/null +++ b/src/test/resources/testPrograms/negativ/scoping/VariableAccess3.monty @@ -0,0 +1,8 @@ +// Testing: Lexical scoping +// +// B must not be writable if it is not declared. +// +// Expected output: Error + +Int a := 3 +b := a \ No newline at end of file diff --git a/src/test/resources/testPrograms/negativ/scoping/VariableAccess4.error b/src/test/resources/testPrograms/negativ/scoping/VariableAccess4.error new file mode 100644 index 0000000..ca5a8d9 --- /dev/null +++ b/src/test/resources/testPrograms/negativ/scoping/VariableAccess4.error @@ -0,0 +1 @@ +ResolveVisitor caught error in null: Identifier is not defined: var \ No newline at end of file diff --git a/src/test/resources/testPrograms/negativ/scoping/VariableAccess4.monty b/src/test/resources/testPrograms/negativ/scoping/VariableAccess4.monty new file mode 100644 index 0000000..a259ebb --- /dev/null +++ b/src/test/resources/testPrograms/negativ/scoping/VariableAccess4.monty @@ -0,0 +1,8 @@ +// Testing: Lexical scoping +// +// var must not be readable if it is not declared yet. +// +// Expected output: Error + +print(var) +Int var := 42 \ No newline at end of file diff --git a/src/test/resources/testPrograms/negativ/scoping/VariableAccess5.error b/src/test/resources/testPrograms/negativ/scoping/VariableAccess5.error new file mode 100644 index 0000000..8a75026 --- /dev/null +++ b/src/test/resources/testPrograms/negativ/scoping/VariableAccess5.error @@ -0,0 +1 @@ +some useful error message. \ No newline at end of file diff --git a/src/test/resources/testPrograms/negativ/scoping/VariableAccess5.monty.ignore b/src/test/resources/testPrograms/negativ/scoping/VariableAccess5.monty.ignore new file mode 100644 index 0000000..e356f1d --- /dev/null +++ b/src/test/resources/testPrograms/negativ/scoping/VariableAccess5.monty.ignore @@ -0,0 +1,12 @@ +// Testing: Lexical scoping +// +// var must not be readable if it is not initialized yet. +// +// Expected output: Error +// +// This test is ignored atm, since a lot more contextual analysis is needed, in +// order to correclty ensure only access of already initialized variables. + +Int var +print(var) +var := 42 \ No newline at end of file diff --git a/src/test/resources/testPrograms/negativ/scoping/VariableAccess6.error b/src/test/resources/testPrograms/negativ/scoping/VariableAccess6.error new file mode 100644 index 0000000..46b12b7 --- /dev/null +++ b/src/test/resources/testPrograms/negativ/scoping/VariableAccess6.error @@ -0,0 +1 @@ +ResolveVisitor caught error in null: Identifier is not defined: answer \ No newline at end of file diff --git a/src/test/resources/testPrograms/negativ/scoping/VariableAccess6.monty b/src/test/resources/testPrograms/negativ/scoping/VariableAccess6.monty new file mode 100644 index 0000000..1558991 --- /dev/null +++ b/src/test/resources/testPrograms/negativ/scoping/VariableAccess6.monty @@ -0,0 +1,15 @@ +// Testing: Lexical scoping vs simultaneous visibility +// +// answer within calcAnswerToLifeAndStuff shadows the outer scope one. +// But since we do not have simultaneous visibility within procedures, +// answers must not be accessible, when accessed prior to declaration. +// +// Expected output: Error + +Int answer := 42 + +calcAnswerToLifeAndStuff(): + print(answer) + Int answer := 43 + +calcAnswerToLifeAndStuff() \ No newline at end of file diff --git a/src/test/resources/testPrograms/object/Object1.monty b/src/test/resources/testPrograms/object/Object1.monty new file mode 100644 index 0000000..5bac744 --- /dev/null +++ b/src/test/resources/testPrograms/object/Object1.monty @@ -0,0 +1,7 @@ +// Testing: The monty baseclass Object. +// +// Object must be instantiable. +// +// Expected output: + +Object b := Object() diff --git a/src/test/resources/testPrograms/object/Object1.output b/src/test/resources/testPrograms/object/Object1.output new file mode 100644 index 0000000..e69de29 diff --git a/src/test/resources/testPrograms/object/Object2.monty b/src/test/resources/testPrograms/object/Object2.monty new file mode 100644 index 0000000..97bcee6 --- /dev/null +++ b/src/test/resources/testPrograms/object/Object2.monty @@ -0,0 +1,10 @@ +// Testing: The monty baseclass Object. +// +// Object must be usable as normal Object (e.g. pass it arround). +// +// Expected output: + +Object returnsObject(Object o): + return o + +Object o := returnsObject(Object()) diff --git a/src/test/resources/testPrograms/object/Object2.output b/src/test/resources/testPrograms/object/Object2.output new file mode 100644 index 0000000..e69de29 diff --git a/src/test/resources/testPrograms/object/Object3.monty b/src/test/resources/testPrograms/object/Object3.monty new file mode 100644 index 0000000..5438354 --- /dev/null +++ b/src/test/resources/testPrograms/object/Object3.monty @@ -0,0 +1,10 @@ +// Testing: The monty baseclass Object. +// +// A class inheriting nothing must inherit Object. +// +// Expected output: + +class Ab: + pass + +Object a := Ab() diff --git a/src/test/resources/testPrograms/object/Object3.output b/src/test/resources/testPrograms/object/Object3.output new file mode 100644 index 0000000..e69de29 diff --git a/src/test/resources/testPrograms/object/Object4.monty b/src/test/resources/testPrograms/object/Object4.monty new file mode 100644 index 0000000..3d9e9e1 --- /dev/null +++ b/src/test/resources/testPrograms/object/Object4.monty @@ -0,0 +1,12 @@ +// Testing: The monty baseclass Object. +// +// A class inheriting nothing must inherit Object and be castable.. +// +// Expected output: 42 + +class Ab: + + Int attr := 42 + +Object o := Ab() +Ab a := o as Ab +print(a.attr) diff --git a/src/test/resources/testPrograms/object/Object4.output b/src/test/resources/testPrograms/object/Object4.output new file mode 100644 index 0000000..f70d7bb --- /dev/null +++ b/src/test/resources/testPrograms/object/Object4.output @@ -0,0 +1 @@ +42 \ No newline at end of file diff --git a/src/test/resources/testPrograms/overloading/OverloadingConstructor1.monty b/src/test/resources/testPrograms/overloading/OverloadingConstructor1.monty new file mode 100644 index 0000000..e09d2b3 --- /dev/null +++ b/src/test/resources/testPrograms/overloading/OverloadingConstructor1.monty @@ -0,0 +1,50 @@ +// Testing: Overloading of initializers +// +// The correct overloaded initializer must be called. +// +// Expected output: :empty:i:f:s:b:ii:ff:ss:bb + +class Ab: + + String attr + + + initializer(): + self.attr := ":empty" + print(self.attr) + + + initializer(Int x): + self.attr := ":i" + print(self.attr) + + initializer(Float x): + self.attr := ":f" + print(self.attr) + + initializer(String x): + self.attr := ":s" + print(self.attr) + + initializer(Bool x): + self.attr := ":b" + print(self.attr) + + + initializer(Int x1, Int x2): + self.attr := ":ii" + print(self.attr) + + initializer(Float x1, Float x2): + self.attr := ":ff" + print(self.attr) + + initializer(String x1, String x2): + self.attr := ":ss" + print(self.attr) + + initializer(Bool x1, Bool x2): + self.attr := ":bb" + print(self.attr) + +Ab empty := Ab() + +Ab i := Ab(42) +Ab f := Ab(1.3) +Ab s := Ab("Hallo") +Ab b := Ab(true) + +Ab ii := Ab(42, 24) +Ab ff := Ab(1.3, 3.1) +Ab ss := Ab("Hallo", "Welt") +Ab bb := Ab(true, false) diff --git a/src/test/resources/testPrograms/overloading/OverloadingConstructor1.output b/src/test/resources/testPrograms/overloading/OverloadingConstructor1.output new file mode 100644 index 0000000..e6178ca --- /dev/null +++ b/src/test/resources/testPrograms/overloading/OverloadingConstructor1.output @@ -0,0 +1 @@ +:empty:i:f:s:b:ii:ff:ss:bb \ No newline at end of file diff --git a/src/test/resources/testPrograms/overloading/OverloadingFunction1.monty b/src/test/resources/testPrograms/overloading/OverloadingFunction1.monty new file mode 100644 index 0000000..9ff6922 --- /dev/null +++ b/src/test/resources/testPrograms/overloading/OverloadingFunction1.monty @@ -0,0 +1,47 @@ +// Testing: Overloading of functions +// +// The correct overloaded function with predefined types must be called. +// +// Expected output: :No:i:s:f:b:ii:ss:ff:bb + +Bool function(): + print(":No") + return false + +Bool function(Int x): + print(":i") + return false +Bool function(String x): + print(":s") + return false +Bool function(Float x): + print(":f") + return false +Bool function(Bool x): + print(":b") + return false + +Bool function(Int x1, Int x2): + print(":ii") + return false +Bool function(String x1, String x2): + print(":ss") + return false +Bool function(Float x1, Float x2): + print(":ff") + return false +Bool function(Bool x1, Bool x2): + print(":bb") + return false + +function() + +function(42) +function("Hallo") +function(1.3) +function(true) + +function(42, 42) +function("Hallo", "Welt") +function(1.3, 3.1) +function(true, false) diff --git a/src/test/resources/testPrograms/overloading/OverloadingFunction1.output b/src/test/resources/testPrograms/overloading/OverloadingFunction1.output new file mode 100644 index 0000000..893566f --- /dev/null +++ b/src/test/resources/testPrograms/overloading/OverloadingFunction1.output @@ -0,0 +1 @@ +:No:i:s:f:b:ii:ss:ff:bb \ No newline at end of file diff --git a/src/test/resources/testPrograms/overloading/OverloadingFunction2.monty b/src/test/resources/testPrograms/overloading/OverloadingFunction2.monty new file mode 100644 index 0000000..3eb68e2 --- /dev/null +++ b/src/test/resources/testPrograms/overloading/OverloadingFunction2.monty @@ -0,0 +1,37 @@ +// Testing: Overloading of functions +// +// The correct overloaded function in combination with different blocks must +// be called. +// +// Expected output: :No2:i:s:f:b:No1 + +Bool function(): + print(":No1") + return false + +if true: + Bool function(): + print(":No2") + return false + + Bool function(Int x): + print(":i") + return false + Bool function(String x): + print(":s") + return false + Bool function(Float x): + print(":f") + return false + Bool function(Bool x): + print(":b") + return false + + function() + + function(42) + function("Hallo") + function(1.3) + function(true) + +function() diff --git a/src/test/resources/testPrograms/overloading/OverloadingFunction2.output b/src/test/resources/testPrograms/overloading/OverloadingFunction2.output new file mode 100644 index 0000000..a43cf6e --- /dev/null +++ b/src/test/resources/testPrograms/overloading/OverloadingFunction2.output @@ -0,0 +1 @@ +:No2:i:s:f:b:No1 \ No newline at end of file diff --git a/src/test/resources/testPrograms/overloading/OverloadingFunction3.monty b/src/test/resources/testPrograms/overloading/OverloadingFunction3.monty new file mode 100644 index 0000000..214315d --- /dev/null +++ b/src/test/resources/testPrograms/overloading/OverloadingFunction3.monty @@ -0,0 +1,28 @@ +// Testing: Overloading of functions. +// +// The correct overloaded function with user defined types must be called. +// +// Expected output: :A:B + +class Ab: + + Bool attr + + + initializer(): + self.attr := true + +class Ba: + + Bool attr + + + initializer(): + self.attr := true + +Bool function(Ab a): + print(":A") + return false + +Bool function(Ba b): + print(":B") + return false + +function(Ab()) +function(Ba()) diff --git a/src/test/resources/testPrograms/overloading/OverloadingFunction3.output b/src/test/resources/testPrograms/overloading/OverloadingFunction3.output new file mode 100644 index 0000000..996964b --- /dev/null +++ b/src/test/resources/testPrograms/overloading/OverloadingFunction3.output @@ -0,0 +1 @@ +:A:B \ No newline at end of file diff --git a/src/test/resources/testPrograms/overloading/OverloadingProcedure1.monty b/src/test/resources/testPrograms/overloading/OverloadingProcedure1.monty new file mode 100644 index 0000000..7b10435 --- /dev/null +++ b/src/test/resources/testPrograms/overloading/OverloadingProcedure1.monty @@ -0,0 +1,38 @@ +// Testing: Overloading of procedures +// +// The correct overloaded procedure with predefined types must be called. +// +// Expected output: :No:i:s:f:b:ii:ss:ff:bb + +procedure(): + print(":No") + +procedure(Int x): + print(":i") +procedure(String x): + print(":s") +procedure(Float x): + print(":f") +procedure(Bool x): + print(":b") + +procedure(Int x1, Int x2): + print(":ii") +procedure(String x1, String x2): + print(":ss") +procedure(Float x1, Float x2): + print(":ff") +procedure(Bool x1, Bool x2): + print(":bb") + +procedure() + +procedure(42) +procedure("Hallo") +procedure(1.3) +procedure(true) + +procedure(42, 42) +procedure("Hallo", "Welt") +procedure(1.3, 3.1) +procedure(true, false) diff --git a/src/test/resources/testPrograms/overloading/OverloadingProcedure1.output b/src/test/resources/testPrograms/overloading/OverloadingProcedure1.output new file mode 100644 index 0000000..893566f --- /dev/null +++ b/src/test/resources/testPrograms/overloading/OverloadingProcedure1.output @@ -0,0 +1 @@ +:No:i:s:f:b:ii:ss:ff:bb \ No newline at end of file diff --git a/src/test/resources/testPrograms/overloading/OverloadingProcedure2.monty b/src/test/resources/testPrograms/overloading/OverloadingProcedure2.monty new file mode 100644 index 0000000..e488ddb --- /dev/null +++ b/src/test/resources/testPrograms/overloading/OverloadingProcedure2.monty @@ -0,0 +1,31 @@ +// Testing: Overloading of procedures +// +// The correct overloaded procedure in combination with different blocks must +// be called. +// +// Expected output: :No2:i:s:f:b:No1 + +procedure(): + print(":No1") + +if true: + procedure(): + print(":No2") + + procedure(Int x): + print(":i") + procedure(String x): + print(":s") + procedure(Float x): + print(":f") + procedure(Bool x): + print(":b") + + procedure() + + procedure(42) + procedure("Hallo") + procedure(1.3) + procedure(true) + +procedure() diff --git a/src/test/resources/testPrograms/overloading/OverloadingProcedure2.output b/src/test/resources/testPrograms/overloading/OverloadingProcedure2.output new file mode 100644 index 0000000..a43cf6e --- /dev/null +++ b/src/test/resources/testPrograms/overloading/OverloadingProcedure2.output @@ -0,0 +1 @@ +:No2:i:s:f:b:No1 \ No newline at end of file diff --git a/src/test/resources/testPrograms/overloading/OverloadingProcedure3.monty b/src/test/resources/testPrograms/overloading/OverloadingProcedure3.monty new file mode 100644 index 0000000..b95be50 --- /dev/null +++ b/src/test/resources/testPrograms/overloading/OverloadingProcedure3.monty @@ -0,0 +1,26 @@ +// Testing: Overloading of procedures +// +// The correct overloaded procedure with user defined types must be called. +// +// Expected output: :A:B + +class Ab: + + Bool attr + + + initializer(): + self.attr := true + +class Ba: + + Bool attr + + + initializer(): + self.attr := true + +procedure(Ab a): + print(":A") + +procedure(Ba b): + print(":B") + +procedure(Ab()) +procedure(Ba()) diff --git a/src/test/resources/testPrograms/overloading/OverloadingProcedure3.output b/src/test/resources/testPrograms/overloading/OverloadingProcedure3.output new file mode 100644 index 0000000..996964b --- /dev/null +++ b/src/test/resources/testPrograms/overloading/OverloadingProcedure3.output @@ -0,0 +1 @@ +:A:B \ No newline at end of file diff --git a/src/test/resources/testPrograms/print/PrintBoolean.monty b/src/test/resources/testPrograms/print/PrintBoolean.monty new file mode 100644 index 0000000..8cf642e --- /dev/null +++ b/src/test/resources/testPrograms/print/PrintBoolean.monty @@ -0,0 +1,6 @@ +// Testing: The print function with boolean. +// +// Expected output: 10 + +print(true) +print(false) diff --git a/src/test/resources/testPrograms/print/PrintBoolean.output b/src/test/resources/testPrograms/print/PrintBoolean.output new file mode 100644 index 0000000..9a03714 --- /dev/null +++ b/src/test/resources/testPrograms/print/PrintBoolean.output @@ -0,0 +1 @@ +10 \ No newline at end of file diff --git a/src/test/resources/testPrograms/print/PrintChar.monty b/src/test/resources/testPrograms/print/PrintChar.monty new file mode 100644 index 0000000..8847cc9 --- /dev/null +++ b/src/test/resources/testPrograms/print/PrintChar.monty @@ -0,0 +1,8 @@ +// Testing: The print function with char. +// +// Expected output: HAHA + +print('H') +print('A') +print('H') +print('A') diff --git a/src/test/resources/testPrograms/print/PrintChar.output b/src/test/resources/testPrograms/print/PrintChar.output new file mode 100644 index 0000000..05f97d0 --- /dev/null +++ b/src/test/resources/testPrograms/print/PrintChar.output @@ -0,0 +1 @@ +HAHA \ No newline at end of file diff --git a/src/test/resources/testPrograms/print/PrintFloat.monty b/src/test/resources/testPrograms/print/PrintFloat.monty new file mode 100644 index 0000000..618fc86 --- /dev/null +++ b/src/test/resources/testPrograms/print/PrintFloat.monty @@ -0,0 +1,6 @@ +// Testing: The print function with float. +// +// Expected output: 01.3 + +print(0.0) +print(1.3) diff --git a/src/test/resources/testPrograms/print/PrintFloat.output b/src/test/resources/testPrograms/print/PrintFloat.output new file mode 100644 index 0000000..7056186 --- /dev/null +++ b/src/test/resources/testPrograms/print/PrintFloat.output @@ -0,0 +1 @@ +01.3 \ No newline at end of file diff --git a/src/test/resources/testPrograms/print/PrintInt.monty b/src/test/resources/testPrograms/print/PrintInt.monty new file mode 100644 index 0000000..ea8a6d4 --- /dev/null +++ b/src/test/resources/testPrograms/print/PrintInt.monty @@ -0,0 +1,6 @@ +// Testing: The print function with int. +// +// Expected output: 042 + +print(0) +print(42) diff --git a/src/test/resources/testPrograms/print/PrintInt.output b/src/test/resources/testPrograms/print/PrintInt.output new file mode 100644 index 0000000..9f73fc0 --- /dev/null +++ b/src/test/resources/testPrograms/print/PrintInt.output @@ -0,0 +1 @@ +042 \ No newline at end of file diff --git a/src/test/resources/testPrograms/print/PrintString.monty b/src/test/resources/testPrograms/print/PrintString.monty new file mode 100644 index 0000000..f2cff49 --- /dev/null +++ b/src/test/resources/testPrograms/print/PrintString.monty @@ -0,0 +1,6 @@ +// Testing: The print function with string. +// +// Expected output: Hallo + +print("") +print("Hallo") diff --git a/src/test/resources/testPrograms/print/PrintString.output b/src/test/resources/testPrograms/print/PrintString.output new file mode 100644 index 0000000..53f5007 --- /dev/null +++ b/src/test/resources/testPrograms/print/PrintString.output @@ -0,0 +1 @@ +Hallo \ No newline at end of file diff --git a/src/test/resources/testPrograms/print/PrintVariableBoolean.monty b/src/test/resources/testPrograms/print/PrintVariableBoolean.monty new file mode 100644 index 0000000..8274e22 --- /dev/null +++ b/src/test/resources/testPrograms/print/PrintVariableBoolean.monty @@ -0,0 +1,6 @@ +// Testing: The print function with a boolean variable. +// +// Expected output: 1 + +Bool var := true +print(var) diff --git a/src/test/resources/testPrograms/print/PrintVariableBoolean.output b/src/test/resources/testPrograms/print/PrintVariableBoolean.output new file mode 100644 index 0000000..56a6051 --- /dev/null +++ b/src/test/resources/testPrograms/print/PrintVariableBoolean.output @@ -0,0 +1 @@ +1 \ No newline at end of file diff --git a/src/test/resources/testPrograms/print/PrintVariableChar.monty b/src/test/resources/testPrograms/print/PrintVariableChar.monty new file mode 100644 index 0000000..faafb99 --- /dev/null +++ b/src/test/resources/testPrograms/print/PrintVariableChar.monty @@ -0,0 +1,6 @@ +// Testing: The print function with a char variable. +// +// Expected output: M + +Char var := 'M' +print(var) diff --git a/src/test/resources/testPrograms/print/PrintVariableChar.output b/src/test/resources/testPrograms/print/PrintVariableChar.output new file mode 100644 index 0000000..ef6bce1 --- /dev/null +++ b/src/test/resources/testPrograms/print/PrintVariableChar.output @@ -0,0 +1 @@ +M \ No newline at end of file diff --git a/src/test/resources/testPrograms/print/PrintVariableFloat.monty b/src/test/resources/testPrograms/print/PrintVariableFloat.monty new file mode 100644 index 0000000..384d41e --- /dev/null +++ b/src/test/resources/testPrograms/print/PrintVariableFloat.monty @@ -0,0 +1,6 @@ +// Testing: The print function with a float variable. +// +// Expected output: 1.3 + +Float var := 1.3 +print(var) diff --git a/src/test/resources/testPrograms/print/PrintVariableFloat.output b/src/test/resources/testPrograms/print/PrintVariableFloat.output new file mode 100644 index 0000000..a58941b --- /dev/null +++ b/src/test/resources/testPrograms/print/PrintVariableFloat.output @@ -0,0 +1 @@ +1.3 \ No newline at end of file diff --git a/src/test/resources/testPrograms/print/PrintVariableInt.monty b/src/test/resources/testPrograms/print/PrintVariableInt.monty new file mode 100644 index 0000000..5ec4eee --- /dev/null +++ b/src/test/resources/testPrograms/print/PrintVariableInt.monty @@ -0,0 +1,6 @@ +// Testing: The print function with an int variable. +// +// Expected output: 42 + +Int var := 42 +print(var) diff --git a/src/test/resources/testPrograms/print/PrintVariableInt.output b/src/test/resources/testPrograms/print/PrintVariableInt.output new file mode 100644 index 0000000..f70d7bb --- /dev/null +++ b/src/test/resources/testPrograms/print/PrintVariableInt.output @@ -0,0 +1 @@ +42 \ No newline at end of file diff --git a/src/test/resources/testPrograms/print/PrintVariableString.monty b/src/test/resources/testPrograms/print/PrintVariableString.monty new file mode 100644 index 0000000..0b1fb3a --- /dev/null +++ b/src/test/resources/testPrograms/print/PrintVariableString.monty @@ -0,0 +1,6 @@ +// Testing: The print function with a string variable. +// +// Expected output: Hallo + +String var := "Hallo" +print(var) diff --git a/src/test/resources/testPrograms/print/PrintVariableString.output b/src/test/resources/testPrograms/print/PrintVariableString.output new file mode 100644 index 0000000..53f5007 --- /dev/null +++ b/src/test/resources/testPrograms/print/PrintVariableString.output @@ -0,0 +1 @@ +Hallo \ No newline at end of file diff --git a/src/test/resources/testPrograms/print/PrintWhitespaces.monty b/src/test/resources/testPrograms/print/PrintWhitespaces.monty new file mode 100644 index 0000000..79288a7 --- /dev/null +++ b/src/test/resources/testPrograms/print/PrintWhitespaces.monty @@ -0,0 +1,11 @@ +// Testing: Printing of Whitespaces +// +// We don't want whitespace in the output to be trimmed or changed in any way. +// To that end we print a series of whitespace characters and test for them +// in order to verify that they haven't been modified. +// +// Expected output: + +String str := " " +print(str) +print(" ") \ No newline at end of file diff --git a/src/test/resources/testPrograms/print/PrintWhitespaces.output b/src/test/resources/testPrograms/print/PrintWhitespaces.output new file mode 100644 index 0000000..a0e231e --- /dev/null +++ b/src/test/resources/testPrograms/print/PrintWhitespaces.output @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/test/resources/testPrograms/print/PrintWhitespaces2.monty.ignore b/src/test/resources/testPrograms/print/PrintWhitespaces2.monty.ignore new file mode 100644 index 0000000..bae7314 --- /dev/null +++ b/src/test/resources/testPrograms/print/PrintWhitespaces2.monty.ignore @@ -0,0 +1,15 @@ +// Testing: Printing of Whitespaces +// +// We don't want whitespace in the output to be trimmed or changed in any way. +// To that end we print a series of whitespace characters and test for them +// in order to verify that they haven't been modified. In addition to ordinary +// whitespace, we have inserted some whitespace characters via escape sequences +// to cater for newlines and tabs. +// +// Expected output: + +String str := " " +print(str) +print("\n") +print("\n") +print(" \t") \ No newline at end of file diff --git a/src/test/resources/testPrograms/print/PrintWhitespaces2.output b/src/test/resources/testPrograms/print/PrintWhitespaces2.output new file mode 100644 index 0000000..d7fe131 --- /dev/null +++ b/src/test/resources/testPrograms/print/PrintWhitespaces2.output @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/test/resources/testPrograms/scoping/Redeclaration.monty b/src/test/resources/testPrograms/scoping/Redeclaration.monty new file mode 100644 index 0000000..562d065 --- /dev/null +++ b/src/test/resources/testPrograms/scoping/Redeclaration.monty @@ -0,0 +1,17 @@ +// Testing: Scope +// +// A Variable must be redeclarable within a new Scope. +// +// Expected output: outerinnerinnerinnerouter + +Int counter := 0 +String ausgabe := "outer" + +print(ausgabe) + +while counter < 3: + String ausgabe := "inner" + print(ausgabe) + counter := counter + 1 + +print(ausgabe) \ No newline at end of file diff --git a/src/test/resources/testPrograms/scoping/Redeclaration.output b/src/test/resources/testPrograms/scoping/Redeclaration.output new file mode 100644 index 0000000..0190767 --- /dev/null +++ b/src/test/resources/testPrograms/scoping/Redeclaration.output @@ -0,0 +1 @@ +outerinnerinnerinnerouter \ No newline at end of file diff --git a/src/test/resources/testPrograms/scoping/SimultaneouslyVisibleFunctions.monty b/src/test/resources/testPrograms/scoping/SimultaneouslyVisibleFunctions.monty new file mode 100644 index 0000000..b5e83c6 --- /dev/null +++ b/src/test/resources/testPrograms/scoping/SimultaneouslyVisibleFunctions.monty @@ -0,0 +1,14 @@ +// Testing: Lexical scoping / Simultaneous visibility +// +// The functions caller and callee must be callable before their declaration, +// because of their simultaneous visibility. +// +// Expected output: reihenfolge ist egal + +caller() + +caller(): + callee() + +callee(): + print("reihenfolge ist egal") \ No newline at end of file diff --git a/src/test/resources/testPrograms/scoping/SimultaneouslyVisibleFunctions.output b/src/test/resources/testPrograms/scoping/SimultaneouslyVisibleFunctions.output new file mode 100644 index 0000000..32c3735 --- /dev/null +++ b/src/test/resources/testPrograms/scoping/SimultaneouslyVisibleFunctions.output @@ -0,0 +1 @@ +reihenfolge ist egal \ No newline at end of file diff --git a/src/test/resources/testPrograms/scoping/SimultaneouslyVisibleObjects.monty b/src/test/resources/testPrograms/scoping/SimultaneouslyVisibleObjects.monty new file mode 100644 index 0000000..8049270 --- /dev/null +++ b/src/test/resources/testPrograms/scoping/SimultaneouslyVisibleObjects.monty @@ -0,0 +1,15 @@ +// Testing: Lexical scoping / Simultaneous visibility +// +// The class attributes einBaum and einAst must be visible before their lexical +// declaration for the reason that their scope is created by class instantiation. +// +// Expected output: reihenfolge ist equal + +Wald einWald := Wald() +print(einWald.einBaum.einAst) + +class Baum: + + String einAst := "reihenfolge ist equal" + +class Wald: + + Baum einBaum := Baum() diff --git a/src/test/resources/testPrograms/scoping/SimultaneouslyVisibleObjects.output b/src/test/resources/testPrograms/scoping/SimultaneouslyVisibleObjects.output new file mode 100644 index 0000000..265301d --- /dev/null +++ b/src/test/resources/testPrograms/scoping/SimultaneouslyVisibleObjects.output @@ -0,0 +1 @@ +reihenfolge ist equal \ No newline at end of file diff --git a/src/test/resources/testPrograms/scoping/VariableAccess.monty b/src/test/resources/testPrograms/scoping/VariableAccess.monty new file mode 100644 index 0000000..3329c88 --- /dev/null +++ b/src/test/resources/testPrograms/scoping/VariableAccess.monty @@ -0,0 +1,13 @@ +// Testing: Lexical scoping +// +// answer is not declared within function calcAnswerToLifeAndStuff, +// so answer from outer scope is accessed. +// +// Expected output: 42 + +Int answer := 42 + +calcAnswerToLifeAndStuff(): + print(answer) + +calcAnswerToLifeAndStuff() \ No newline at end of file diff --git a/src/test/resources/testPrograms/scoping/VariableAccess.output b/src/test/resources/testPrograms/scoping/VariableAccess.output new file mode 100644 index 0000000..f70d7bb --- /dev/null +++ b/src/test/resources/testPrograms/scoping/VariableAccess.output @@ -0,0 +1 @@ +42 \ No newline at end of file diff --git a/src/test/resources/testPrograms/variables/GlobalVariableBoolean1.monty b/src/test/resources/testPrograms/variables/GlobalVariableBoolean1.monty new file mode 100644 index 0000000..3db7cca --- /dev/null +++ b/src/test/resources/testPrograms/variables/GlobalVariableBoolean1.monty @@ -0,0 +1,13 @@ +// Testing: VariableDeclaration and VariableAccess in a ModuleDeclaration. +// +// The boolean variable must be visible and readable inside the procedure +// output(). +// +// Expected output: 1 + +Bool hello := true + +output(): + print(hello) + +output() diff --git a/src/test/resources/testPrograms/variables/GlobalVariableBoolean1.output b/src/test/resources/testPrograms/variables/GlobalVariableBoolean1.output new file mode 100644 index 0000000..56a6051 --- /dev/null +++ b/src/test/resources/testPrograms/variables/GlobalVariableBoolean1.output @@ -0,0 +1 @@ +1 \ No newline at end of file diff --git a/src/test/resources/testPrograms/variables/GlobalVariableBoolean2.monty b/src/test/resources/testPrograms/variables/GlobalVariableBoolean2.monty new file mode 100644 index 0000000..c270251 --- /dev/null +++ b/src/test/resources/testPrograms/variables/GlobalVariableBoolean2.monty @@ -0,0 +1,14 @@ +// Testing: VariableDeclaration and VariableAccess in a ModuleDeclaration. +// +// The boolean variable must be visible, writable and readable inside the +// procedure output(). +// +// Expected output: 1 + +Bool hello + +output(): + hello := true + print(hello) + +output() diff --git a/src/test/resources/testPrograms/variables/GlobalVariableBoolean2.output b/src/test/resources/testPrograms/variables/GlobalVariableBoolean2.output new file mode 100644 index 0000000..56a6051 --- /dev/null +++ b/src/test/resources/testPrograms/variables/GlobalVariableBoolean2.output @@ -0,0 +1 @@ +1 \ No newline at end of file diff --git a/src/test/resources/testPrograms/variables/GlobalVariableChar1.monty b/src/test/resources/testPrograms/variables/GlobalVariableChar1.monty new file mode 100644 index 0000000..626a650 --- /dev/null +++ b/src/test/resources/testPrograms/variables/GlobalVariableChar1.monty @@ -0,0 +1,13 @@ +// Testing: VariableDeclaration and VariableAccess in a ModuleDeclaration. +// +// The char variable must be visible and readable inside the procedure +// output(). +// +// Expected output: M + +Char hello := 'M' + +output(): + print(hello) + +output() diff --git a/src/test/resources/testPrograms/variables/GlobalVariableChar1.output b/src/test/resources/testPrograms/variables/GlobalVariableChar1.output new file mode 100644 index 0000000..ef6bce1 --- /dev/null +++ b/src/test/resources/testPrograms/variables/GlobalVariableChar1.output @@ -0,0 +1 @@ +M \ No newline at end of file diff --git a/src/test/resources/testPrograms/variables/GlobalVariableChar2.monty b/src/test/resources/testPrograms/variables/GlobalVariableChar2.monty new file mode 100644 index 0000000..fdfb746 --- /dev/null +++ b/src/test/resources/testPrograms/variables/GlobalVariableChar2.monty @@ -0,0 +1,14 @@ +// Testing: VariableDeclaration and VariableAccess in a ModuleDeclaration. +// +// The char variable must be visible, writable and readable inside the +// procedure output(). +// +// Expected output: M + +Char hello + +output(): + hello := 'M' + print(hello) + +output() diff --git a/src/test/resources/testPrograms/variables/GlobalVariableChar2.output b/src/test/resources/testPrograms/variables/GlobalVariableChar2.output new file mode 100644 index 0000000..ef6bce1 --- /dev/null +++ b/src/test/resources/testPrograms/variables/GlobalVariableChar2.output @@ -0,0 +1 @@ +M \ No newline at end of file diff --git a/src/test/resources/testPrograms/variables/GlobalVariableFloat1.monty b/src/test/resources/testPrograms/variables/GlobalVariableFloat1.monty new file mode 100644 index 0000000..d674c59 --- /dev/null +++ b/src/test/resources/testPrograms/variables/GlobalVariableFloat1.monty @@ -0,0 +1,13 @@ +// Testing: VariableDeclaration and VariableAccess in a ModuleDeclaration. +// +// The float variable must be visible and readable inside the procedure +// output(). +// +// Expected output: 1.3 + +Float hello := 1.3 + +output(): + print(hello) + +output() diff --git a/src/test/resources/testPrograms/variables/GlobalVariableFloat1.output b/src/test/resources/testPrograms/variables/GlobalVariableFloat1.output new file mode 100644 index 0000000..a58941b --- /dev/null +++ b/src/test/resources/testPrograms/variables/GlobalVariableFloat1.output @@ -0,0 +1 @@ +1.3 \ No newline at end of file diff --git a/src/test/resources/testPrograms/variables/GlobalVariableFloat2.monty b/src/test/resources/testPrograms/variables/GlobalVariableFloat2.monty new file mode 100644 index 0000000..8618f58 --- /dev/null +++ b/src/test/resources/testPrograms/variables/GlobalVariableFloat2.monty @@ -0,0 +1,14 @@ +// Testing: VariableDeclaration and VariableAccess in a ModuleDeclaration. +// +// The float variable must be visible, writable and readable inside the +// procedure output(). +// +// Expected output: 1.3 + +Float hello + +output(): + hello := 1.3 + print(hello) + +output() diff --git a/src/test/resources/testPrograms/variables/GlobalVariableFloat2.output b/src/test/resources/testPrograms/variables/GlobalVariableFloat2.output new file mode 100644 index 0000000..a58941b --- /dev/null +++ b/src/test/resources/testPrograms/variables/GlobalVariableFloat2.output @@ -0,0 +1 @@ +1.3 \ No newline at end of file diff --git a/src/test/resources/testPrograms/variables/GlobalVariableInt1.monty b/src/test/resources/testPrograms/variables/GlobalVariableInt1.monty new file mode 100644 index 0000000..f48e6a2 --- /dev/null +++ b/src/test/resources/testPrograms/variables/GlobalVariableInt1.monty @@ -0,0 +1,13 @@ +// Testing: VariableDeclaration and VariableAccess in a ModuleDeclaration. +// +// The int variable must be visible and readable inside the procedure +// output(). +// +// Expected output: 42 + +Int hello := 42 + +output(): + print(hello) + +output() diff --git a/src/test/resources/testPrograms/variables/GlobalVariableInt1.output b/src/test/resources/testPrograms/variables/GlobalVariableInt1.output new file mode 100644 index 0000000..f70d7bb --- /dev/null +++ b/src/test/resources/testPrograms/variables/GlobalVariableInt1.output @@ -0,0 +1 @@ +42 \ No newline at end of file diff --git a/src/test/resources/testPrograms/variables/GlobalVariableInt2.monty b/src/test/resources/testPrograms/variables/GlobalVariableInt2.monty new file mode 100644 index 0000000..4c13e8e --- /dev/null +++ b/src/test/resources/testPrograms/variables/GlobalVariableInt2.monty @@ -0,0 +1,14 @@ +// Testing: VariableDeclaration and VariableAccess in a ModuleDeclaration. +// +// The int variable must be visible, writable and readable inside the +// procedure output(). +// +// Expected output: 42 + +Int hello + +output(): + hello := 42 + print(hello) + +output() diff --git a/src/test/resources/testPrograms/variables/GlobalVariableInt2.output b/src/test/resources/testPrograms/variables/GlobalVariableInt2.output new file mode 100644 index 0000000..f70d7bb --- /dev/null +++ b/src/test/resources/testPrograms/variables/GlobalVariableInt2.output @@ -0,0 +1 @@ +42 \ No newline at end of file diff --git a/src/test/resources/testPrograms/variables/GlobalVariableString1.monty b/src/test/resources/testPrograms/variables/GlobalVariableString1.monty new file mode 100644 index 0000000..57eb5c0 --- /dev/null +++ b/src/test/resources/testPrograms/variables/GlobalVariableString1.monty @@ -0,0 +1,13 @@ +// Testing: VariableDeclaration and VariableAccess in a ModuleDeclaration. +// +// The string variable must be visible and readable inside the procedure +// output(). +// +// Expected output: Hello + +String hello := "Hello" + +output(): + print(hello) + +output() diff --git a/src/test/resources/testPrograms/variables/GlobalVariableString1.output b/src/test/resources/testPrograms/variables/GlobalVariableString1.output new file mode 100644 index 0000000..5ab2f8a --- /dev/null +++ b/src/test/resources/testPrograms/variables/GlobalVariableString1.output @@ -0,0 +1 @@ +Hello \ No newline at end of file diff --git a/src/test/resources/testPrograms/variables/GlobalVariableString2.monty b/src/test/resources/testPrograms/variables/GlobalVariableString2.monty new file mode 100644 index 0000000..1a48b72 --- /dev/null +++ b/src/test/resources/testPrograms/variables/GlobalVariableString2.monty @@ -0,0 +1,14 @@ +// Testing: VariableDeclaration and VariableAccess in a ModuleDeclaration. +// +// The string variable must be visible, writable and readable inside the +// procedure output(). +// +// Expected output: Hello + +String hello + +output(): + hello := "Hello" + print(hello) + +output() diff --git a/src/test/resources/testPrograms/variables/GlobalVariableString2.output b/src/test/resources/testPrograms/variables/GlobalVariableString2.output new file mode 100644 index 0000000..5ab2f8a --- /dev/null +++ b/src/test/resources/testPrograms/variables/GlobalVariableString2.output @@ -0,0 +1 @@ +Hello \ No newline at end of file