CODEGEN_HOW_TO0000644000175000017500000001136412714113765011666 0ustar olesolesThis is a brief explanation on how to drive JEL's code generator in order to generate Java bytecode bypassing JEL's parser. If you plan to generate expressions by a program (as opposed to letting user to type them) this document might help you to eliminate parsing overhead. It might be also useful to someone who wishes to build a compiler for more complex languages on top of JEL. Why would you want to use JEL's code generator, as opposed to other Java assemblers/code generators ? Two main reasons for this are 1) Size. Up to my knowledge JEL is smallest of Java assemblers. 2) Performance. Due to the table-driven design instructions are fetched from pre-built tables instead of computing them at run-time. 2) Convenience. JEL can match data types to instructions to automatically generate the correct Java instructions for a particular operation on a particular data type. It does widening data type conversions automatically. There are two modes in which you can use JEL's code generator. The first is RAW assembler, it is provided by gnu.jel.ClassFile, and the second is type-matching assembler (implemented in gnu.jel.OPxxx classes). I. RAW MODE. By manipulating methods of gnu.jel.ClassFile you can create almost arbitrary Java classfiles (not only descendants of gnu.jel.CompiledExpression). The only feature currently absent from ClassFile is writing Exception tables (but this can be easily added). The ClassFile frees user from paying attention to the details of the Java class file format (like constant pool handling) and concentrate directly on the bytecode. II. TYPE-MATCHING ASSEMBLER. This helps to generate the bytecode once you have started a method of your class using ClassFile. It only works for expressions right now, but can be extended in obvious way to handle the control structures, which was not implemented because it would blow up the size compiler size and go out of a niche intended for JEL. I do have plans (when time permits) to make another project for a full featured programming language compiler on top of JEL. In order to generate the code for an expression you need first write it in a reverse Polish notation, then, set up an empty paramOPs stack, and then instantiate the OPxxx classes for each operand/operation in order. After passing through all your expression from left to right you'll have only a single OP in paramOPs stack, which represents all your expression. For example suppose you want to add a numbers 1+2+2 in reverse Polish notation this reads as 2 2 1 + + to create JEL's internal representation of this expression you do java.util.Stack paramOps= new java.util.Stack(); paramOPs.push(new OPLoad(new Byte(2))); paramOPs.push(new OPLoad(new Integer(2))); paramOPs.push(new OPLoad(new Long(1))); paramOPs.push(new OPbinary(paramOPs,0)); // 0 codes for '+' operation paramOPs.push(new OPbinary(paramOPs,0)); your code is now OP code=(OP) paramOPs.pop(); The type matching and widening conversions are done automatically by JEL, you can query the result type by checking code.resType field. In the case of the expression above the result will be equal to Class.forName("java.lang.Long"). You can perform constants folding on an expression by doing code.eval(); and throwing away a possibly emerged exception, which only signals that the code can't be evaluated completely. For the expression given above there will be no exception, because it is constant. Finally, you can flush the Java bytecode into the ClassFile (say, named cf) you have already set up. code.compile(cf); It will be appended to the code for the current method you already have there. III. WHAT INTERFACES MAY OR MAY NOT CHANGE. The reason for writing this document was that JEL internal interfaces have reached more or less optimal shape. Nevertheless, some things may change in future. In particular, the additional (convenience) bytecodes defined in ClassFile.code(long) method may change. The ClassFile.newMethod() will certainly change when exception tables will be implemented (however a compatible version may be provided). The methods of gnu.jel.OP will not change (there can be some more added though), and the constructors of all existing gnu.jel.OPxxx classes will not change (they are all what is needed to know to use JEL's code generator for expressions). If you are interested in using JEL's code generator directly, please drop me a note, so that I can inform you about interface changes. I hope this text was helpful. If not, send your suggestions to metlov@fti.dn.ua . Please, contact me also if I forgot to make some of the methods described above (or required otherwise) public. Copyright (C) 2009 Konstantin L. Metlov This file is licensed to you under the terms of GNU Free Documentation License as given in the appendix of JEL Manual. COPYING0000644000175000017500000010451312714113765010612 0ustar olesoles 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 . docs/0000755000175000017500000000000013053271321010471 5ustar olesolesdocs/manual.html0000644000175000017500000022751012714113765012655 0ustar olesoles Java Expressions Library

Java Expressions Library

Dr. Konstantin L. Metlov

Licensing

Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the Appendix.


Chapter 1. About this manual

This manual is mostly examples-based. It starts with two simple step-by-step examples (showing how to deal with static and dynamic libraries), which should give enough information for basic JEL usage (but don't forget to read the rest of this manual to learn how to get the top performance from JEL). Additional information can be found in API documentation.

Chapter 2. JEL design goals

The main design goal was to create light weight expression compiler generating extremely fast code. The main emphasis is the code execution time and not the compilation time (it is nevertheless small). The other goal was to make JEL language to be very close to Java language with direct access to all built-in Java data types and functions.

Chapter 3. Features

  • Support for all Java data types (boolean, byte, char, short, long, int, float, double, arrays, references)

  • Octal (0456) and hexadecimal (0x1FFF) literals.

  • Support for all Java arithmetic operators: + (add),- (subtract), * (multiply), / (divide), % (remainder), & (bitwise and),| (bitwise or), ^ (bitwise xor),~ (bitwise complement), << (left shift), >> (right signed shift), >>> (right unsigned shift); on most of supported data types according to Java Language Specification (JLS)

  • Comparison operators (==,!=,<,>=,>,<=) as defined by Java Language Specification (JLS).

  • dot (".") operator on objects ("abc".length()==3).

  • dot (".") operator on objects ("abc".length()==3).

  • Boolean logical operators (&&,||,!) with lazy evaluation (i.e. in the expression false&&complexBooleanFunction() the function is never called).

  • Conditionals (true?2:3 = 2)

  • Direct access to methods and fields of Java objects.

  • Method overloading according to Java Language Specification.

  • Support for methods with variable number of arguments (varargs), which is enabled for all methods, accepting array as their last argument.

  • Dynamic variables interface allowing to add variables to JEL namespace without supplying the class file defining them.

  • Automatic unwrapping of designated objects to Java primitive types.

  • Support for strings. Objects of class java.lang.String can be directly entered into expressions using double quotes, also the standard Java escape codes are parsed. Example : "a string\n\015".

  • String concatenation ("a"+2+(2>3)+object = "a2false"+object.toString()).

  • User definable string comparison using usual relational operators "<", "<=", ">", ">=", "==", "!=", which uses locale by default.

  • User-controllable object down-casting using "(class.name)var" syntax. It is possible to assign names to classes in JEL expressions to be different from their real Java class names.

  • Constants folding, extended (by default, but can be controlled) to static methods (which are automatically called at compile time) and static fields (which are considered constants).

  • High performance of generated code.

Chapter 4. How to use JEL.

In this section a simple example of a program using JEL is given, and explained with references to more detailed sections of this manual. The example program evaluates the expression given on its command line (similar program exists in the distribution under the name ./samples/Calculator.java), let's follow it step by step.

    public static void main(String[] args) {
    
    // Assemble the expression
    StringBuffer expr_sb=new StringBuffer();
    for(int i=0;i<args.length;i++) {
      expr_sb.append(args[i]);
      expr_sb.append(' ');
      };
    String expr=expr_sb.toString();
  

This first part of the program is not related to JEL. It's purpose is to assemble the expression, possibly, containing spaces into the single line. This has to be done, because shells tend to tokenize parameters but we don't need it here.

    // Set up the library
    Class[] staticLib=new Class[1];
    try {
      staticLib[0]=Class.forName("java.lang.Math");
    } catch(ClassNotFoundException e) {
      // Can't be ;)) ...... in java ... ;)
    };
    Library lib=new Library(staticLib,null,null,null,null);
    try {
    lib.markStateDependent("random",null);
    } catch (NoSuchMethodException e) {
      // Can't be also
    };
  

This piece of code establishes the namespace for use in JEL compiled expressions. The gnu.jel.Library object maintains this namespace.

There can be two types of names in the Library : static and virtual (dynamic).

Methods and variables of the first class are assumed (by default) to be dependent only on their arguments i.e. not to save any information from call to call (they are "stateless")... Examples are mathematical functions like sin, cos, log, constants E, PI in java.lang.Math. For such methods (fields) it does not matter how many times (when) they will be called (their value will be taken) the result will always be the same provided arguments (if they are present) are the same. Stateless methods will be evaluated by JEL at compile time if their arguments are constants (known at compile time). To define set of static functions(fields) it is needed to pass the array of Class objects, defining those functions, as the first parameter of the library constructor (see example above). Note ONLY STATIC functions of the Classes, passed in the first argument of the gnu.jel.Library constructor will be defined in the namespace. By default all static functions are considered "stateless" by JEL.

However, some static functions still save their state (in static variables) in between calls. Thus they return different results, depending on when (how many times) they are is called even if their arguments are the same. If such function is evaluated at compile time, we have troubles, because it will be evaluated only once during expression lifetime and it's state dependence will be lost. Typical example of the static function, having a state is java.lang.Math.random. JEL has special mechanism, provided by gnu.jel.Library class to mark static functions as state dependent. (see the above example to find out how it was done for the java.lang.Math.random)

The virtual functions, which are explicitly state dependent, will be discussed later in this document. The example we currently consider does not use them. However, virtual functions are, actually, most important to JEL because expression, containing all stateless functions, is a constant, it will be completely evaluated at compile time, there is absolutely no sense to evaluate such expression repeatedly (this is what JEL was designed for). Still we shall continue with this simple example as the following code is mostly independent of whether we use virtual functions or not...

    // Compile
    CompiledExpression expr_c=null;
    try {
      expr_c=Evaluator.compile(expr,lib);
    } catch (CompilationException ce) {
      System.err.print("–––COMPILATION ERROR :");
      System.err.println(ce.getMessage());
      System.err.print("                       ");
      System.err.println(expr);
      int column=ce.getColumn(); // Column, where error was found
      for(int i=0;i<column+23-1;i++) System.err.print(' ');
      System.err.println('^');
    };

This chunk of code is for the expression compilation. The crucial line is the call to Evaluator.compile, it is the point, where expression gets transformed into Java bytecode, loaded into the Java Virtual Machine using JEL ClassLoader and returned to caller as an instance of the subclass of gnu.jel.CompiledExpression. Typical user of JEL is not required to know what magic is going on inside of Evaluator.compile(...). Other code in this chunk is for the error reporting and will be discussed in the specialized section Error detection and reporting below.

      if (expr_c !=null) {
      
      // Evaluate (Can do it now any number of times FAST !!!)
      Number result=null;
      try {
	result=(Number)expr_c.evaluate(null);
      } catch (Throwable e) {
	System.err.println("Exception emerged from JEL compiled"+
			   " code (IT'S OK) :");
	System.err.print(e);
      };
  

This code does the evaluation of the expression. It is done by calling the evaluate method of the JEL compiled class, it is defined abstract in gnu.jel.CompiledExpression but is redefined in the class compiled by JEL. The argument of this method is discussed in the section on virtual functions below. If only static functions are present in the library it is safe to pass the null pointer as the argument to evaluate.

Result of the evaluate method is always an object. JEL converts primitive numeric types into instances of corresponding Java reflection classes (read the section Making things faster to find out how to avoid this conversion). For example, a value of primitive type long will be returned as an instance of java.lang.Long class (int maps to java.lang.Integer, float to java.lang.Float, etc.). If result is an arbitrary Java object it is returned as the reference to that object.

The

try ... catch

clause around the call to evaluate will be enforced by the Java compiler. It is required as errors can appear during evaluation. The general rule is: syntax, types incompatibility and function resolution errors will be reported at compile time (as thrown instance of gnu.jel.CompilationException), while the errors in the values of numbers will be reported at the execution time. For example expression "1/0" will generate no error at compile time (nevertheless it is the constant expression and its evaluation is attempted), but at the time of calling execute you will get a java.lang.ArithmeticError (division by zero) as it should be.

      // Print result
      if (result==null) 
	System.out.println("void");
      else
	System.out.println(result.toString());
   };
};

This last piece of code will print the result. And is concluding our brief tour of the JEL usage.

Chapter 5. Using libraries

The namespace of JEL expressions is represented by gnu.jel.Library class. Its constructor:

Library(Class[] staticLib, Class[] dynamicLib,
Class[] dotClasses, DVMap  resolver,
Hashtable cnmap)

has five arguments. Their purposes are following:

staticLib

enumerates classes whose static methods are exported to JEL namespace and become usable from within expressions. Such methods do not require this pointer supplied to them at execution time. More details

dynamicLib

enumerates classes whose virtual methods are exported. These methods require the references to the corresponding classes (this pointers) supplied to the expression at run-time. This is done using the Class[]> argument of CompiledExpression's evaluate method. More details

dotClasses

controls access for the dot (".") operator on classes. More details

resolver

Dynamic variables interface. Allows to add new variables to the expressions names without supplying the class files defining them. More details

cnmap

Maps the class names usable inside JEL expressions for non-primitive type casts into the Java classes More details

The details on usage of each of these arguments are given in a separate sections below.

The working example using all current functionality of JEL namespace is given in the examples/YourTestBed directory in the distribution. You'll want to check it after reading this section.

Exporting static methods of classes to JEL namespace.

The array of references to classes (java.lang.Class) whose public static methods and fields are to be exported should be passed as the first argument of the library constructor (staticLib). The public static fields and methods of all these classes are merged together into the JEL namespace. The non-public or non-static members of staticLib classes are ignored.

Methods overloading is supported and works also across classes (because the JEL namespace works similarly to the namespace defined in a single Java class). For example, if a class C1 contains the method public static C1.func(int) and a class C2 contains the method public static C2.func(double) and both these classes are passed as elements of the staticLib array. Then, the JEL expression "func(1)" calls C1.func(int) and the expression "func(1.0)" calls C2.func(double). It also means that methods and fields of all classes supplied to the Library are subject to the same constraints as members of a single Java class.

Moreover, because JEL allows to call methods with no arguments omitting the empty brackets (that is "func()" and "func" are equivalent) there should be no fields and methods with no arguments having the same names in all classes presented to the Library constructor.

To check whether the set of classes you gave to the library constructor satisfies all required constraints run your program against the debug version of JEL library (jel_g.jar). Then, potential problems will be reported to you on the standard output.

Exporting virtual methods of classes to JEL namespace.

The second argument of the library constructor (dynamicLib) works similarly to the first one. Except that only public virtual members are taken from the listed classes. These members are merged into the namespace created from classes from the staticLib. The rules for methods overloading are the same as for classes listed in the first argument of library constructor. Also, the overloading is working across the classes listed in both first and second arguments of the Library constructor.

The crucial difference in the handling of classes listed in the dynamicLib and the staticLib comes from the fact that virtual members of dynamicLib require this reference to the instance of the object of their defining class be supplied at run-time. Thus, if C1 contains the virtual method public func(double x) its invocation actually requires two arguments, one is x and the other is the reference to the instance of class C1.

References to the instances of classes of the dynamicLib array are supplied at the execution time to the argument of the evaluate(Object[] context) method of gnu.jel.CompiledExpression. The elements of the context array should be instances of classes listed in dynamicLib array at compile time and there should be one-to-one correspondence between them. For example, if

dynamicLib[0]=com.mycompany.MyClass.class)

, the corresponding entry in the context array, context[0], must be a reference to the instance of com.mycompany.MyClass.

Formally, for every i, it should be possible to cast the object in the context[i] into the class, supplied in the dynamicLib[i] array of the Library constructor, otherwise ClassCastException will be thrown from evaluate.

Let's walk through the example, which calculates function of the single variable many times and uses virtual method calls. This example will consist of two classes : a user written class (providing access to the variable) and the main class compiling and evaluating expressions. First start with the variable provider:

public class VariableProvider {
  public double xvar;
  
  public double x() {return xvar;};
};

This class is trivial, it just defines the function, returning the value of the variable x.

In the main class (see the first JEL example for headers) the code, constructing the library will be replaced with:

    // Set up library
    Class[] staticLib=new Class[1];
    try {
      staticLib[0]=Class.forName("java.lang.Math");
    } catch(ClassNotFoundException e) {
      // Can't be ;)) ...... in java ... ;)
    };

    Class[] dynamicLib=new Class[1];
    VariableProvider variables=new VariableProvider();
    Object[] context=new Object[1];
    context[0]=variables;
    dynamicLib[0]=variables.getClass();
    
    Library lib=new Library(staticLib,dynamicLib,null,null,null);
    try {
    lib.markStateDependent("random",null);
    } catch (NoSuchMethodException e) {
      // Can't be also
    };

Absent in the static example, the additional code creates the VariableProvider and assigns its reference to an element of context array (to be passed to the evaluate method of the compiled expression). Also, now the dynamicLib array as not null and contains the reference to the VariableProvider class.

The code for compilation is exactly the same as in the example for static functions, except we have additional function x and the variable xvar defined for use inside the compiled expressions. JEL has the special notation for the functions, having no arguments, namely, brackets in "x()" can be omitted to be "x". This allows to compile now ( with the above defined library) the expressions like "sin(x)", "exp(x*x)", "pow(sin(x),2)+pow(cos(x),2)"...

The code for evaluation of an expression having virtual functions is replaced with:

      if (expr_c !=null) {
    
        try {
           for(int i=0;i<100;i++) {
              variables.xvar=i;      // <- Value of the variable
              System.out.println(expr_c.evaluate(context));
                               //^^^^^^^^^^^^^^^ evaluating 100 times
           };
        } catch (Throwable e) {
	   System.err.println("Exception emerged from JEL compiled"+
		              " code (IT'S OK) :");
           System.err.print(e);
        };
    };

Note the two major differences: 1. we have explicitly assigned the value to the variable; 2. the array of object references (consisting of one element in this example) is passed to the evaluate method. This piece of code will evaluate expressions for x=0..99 with step 1.

This concludes our dynamic library example. Try to modify the ./Calculator.java sample yourself to allow compilation of virtual functions as described above.

Variable number of arguments support.

Since the version 2.0.3 JEL supports calling methods with variable number of arguments. Moreover, because the information about the variable arguments declaration is not available via Java reflection, this support extends to all methods, having the array last argument. For example, if two following functions are declared in the library classes (static or dynamic)

       public int sum (int[] args);
       public double powersum(double power, double[] args);

it is possible to use them in the expressions as "sum(1)", "sum(1,2)", "powersum(2,1,2,3)", etc... The argument array will be created automatically by the compiler in these cases. The methods with variable number of arguments are subject to the same method overloading rules, automatic argument type conversions and constants folding as other methods.

Enabling the dot operator on objects.

The third argument of gnu.jel.Library constructor enumerates classes which are available for dot operator within the expression. If this parameter is null JEL would not allow to use the dot operator at all. If it is an array of the length zero (e.g. new Class[0]) JEL will open access to public methods of ALL objects encountered in the expression. From the security point of view allowing access to all objects can be dangerous, that is why there is a third case of non-zero length array explicitly enumerating classes allowing the dot operator on them.

Once the dot operator is allowed on a class, it is possible to call all its public methods using the syntax ".method(arg1,arg2,...)" in any context where this class appears in an expression.

Dynamic variables interface.

All methods of exporting names into JEL namespace described up to this point relied on the Java class files for actual description of methods names and parameters. However, sometimes it is required to add a new variable to JEL namespace at run-time.

One of the solutions would be to generate a new class file (e.g. using JEL) and supply it as a first or second argument of the library constructor. Unfortunately this can be quite cumbersome and time consuming.

The other solution can be to define a family of methods in JEL namespace

YYY getXXXProperty(String name)

for each possible variable types, where YYY is the class representing the property type and XXX is the name of the type. Then, supposing we have methods

  double getDoubleProperty(String name); // YYY=double XXX=Double
  String getStringProperty(String name); // YYY=java.lang.String XXX=String

in the JEL namespace (either static or dynamic), the variables with arbitrary names can be entered into expression using the syntax

getStringProperty("x") +
  (getDoubleProperty("y")+1.0)

This way has two drawbacks: 1) user has to remember the type of the variable (to call the appropriate getXXX() method); 2) a lot to type.

Since the version 0.9.3 JEL provides the way to solve both these problems. To do that the fourth argument (resolver) of the library constructor is used. This argument supplies the reference to the subclass of gnu.jel.DVMap, and is used by JEL to resolve the dynamic variable names. The gnu.jel.DVMap has an abstract method

public String getTypeName(String  name)

which returns XXX (see above) for a given variable name, or null if no such variable is defined. Note that for resolver to work the family of methods

YYY getXXXProperty(String name)

must still be present in JEL namespace (e.g. as members of one of dynamicLib[] classes).

Then, supposing

resolver.getTypeName("x")=="String" &&
resolver.getTypeName("y")=="Double"

the expression "x+(y+1.0)" will be automatically converted by JEL into

getStringProperty("x")+(getDoubleProperty("y")+1.0)

and compiled. Thus, user does not have to remember the variable types, typing is reduced and the existence of variables can be checked at the compile time.

JEL also supports a hierarchical structure of variables. This means the dot (".") symbol can be present in the dynamic variable names. For example if

resolver.getTypeName("x")!=null && 
resolver.getTypeName("x.f1")=="String" && 
resolver.getTypeName("x.f2")=="Double"

the expression "x.f1+(x.f2+1.0)" will be compiled by JEL as

getStringProperty("x.f1")+(getDoubleProperty("x.f2")+1.0)

and (combined with dot operator) the expression "x.f1.length()" will result in the length of the string getString("x1.f1").

Notice in the last example that if one wants to have defined the dynamic variable "x.y" the variable "x" must also be the dynamic variable (resolver.getTypeName("x")!=null).

If there is conflict between the dynamic variable name and other name in JEL namespace the dynamic variable has a priority.

Since JEL 0.9.9 it is possible to translate the names of dynamic variables from strings into the constants of Java primitive types. This is done using non-identity DVMap.translate method. The translation helps to improve performance in some cases.

Consider the following example. Suppose the underlying storage for dynamic variables is an array (or Vector), so that the value of the variable can be obtained by an integer index into that array (like numbered columns in a spreadsheet). Next, assume you still want to refer to the variables by names (e.g. you allowed user to assign names to the columns). Now, if the first column is named "x" and is of Double type, an expression "x", using dynamic variables interface with identity translation will be compiled into getDoubleProperty("x"). It means the translation of the string "x" into the column number 1 will have to be performed at run-time each time the expression is evaluated. Considering that Java strings are immutable, this may incur a substantial performance penalty.

The performance can be improved if the translate method of DVMap is overridden by the following:

public Object translate(String name) {
   if (name.equals("x")) return new Integer(1);
   return name;
   };

This is already a non-identity translation. With such DVMap the expression "x" will be compiled by JEL into getDoubleProperty(1), note that it is getDoubleProperty(int) method, which is called. This way the mapping of the variable name into the variable index is performed at compile-time, while at run-time the index is readily available. By defining the appropriate translations the dynamic variable lookup can be split in a user-controlled way between the expression compilation and execution stages to achieve the best performance.

The translate method is allowed to return only instances of Java reflection classes wrapping the primitive types (java.lang.Integer, java.lang.Double, etc), or strings (otherwise an exception will emerge at compile-time). This is because only these types of objects can be stored in the Java class files directly. Also, it is responsibility of the caller to ensure that JEL namespace contains getXXXProperty methods with all the necessary argument types, corresponding to the translations defined in DVMap. For identity translations only getXXXProperty methods accepting strings are necessary.

Objects down-casting.

The cnmap argument of gnu.jel.Library constructor, allows to enable the non-primitive type casts in JEL compiled expressions. If cnmap!=null it must be java.util.Hashtable with java.lang.Class objects as elements and java.lang.String objects as keys. When the object cast "(non_primitive_type_name) var" is encountered in the expression, "the non_primitive_type_name" string is looked in the cnmap hashtable and the cast to the corresponding class is generated by JEL. The absence of the name in the hashtable produces the compile-time error. It is possible for keys in cnmap to contain "." (dot) symbols in them.

Chapter 6. Automatic unwrapping of objects to primitive types.

This problem appears mostly when one uses dynamic variables, but may also arise in other cases. Suppose a reference to the object of the class Weight (representing a weight of a certain item) appeared in the expression. It is clear that Weight is always represented by a floating point number (although it may have other properties, like units). If the class Weight has the method

public double getValue()

the value of weight can be accessed in expressions using syntax w.getValue(), supposing the variable w has type Weight.

To save typing (since version 0.9.3 of JEL) one may have the class Weight implement gnu.jel.reflect.Double interface. Then, the aforementioned getValue method will be called automatically by JEL (or object w will be "unwrapped" to primitive type). This unwrapping will be performed automatically when needed: one can have expressions "w+1.0" meaning "w.getValue()+1" and "w.getUnits()" both valid (in the second case w is not "unwrapped").

There are gnu.jel.reflect.* interfaces for all Java primitive types. To use the automatic unwrapping one just needs to make his classes to implement one of these interfaces.

There is a similar mechanism for strings (since version 0.9.6) and a corresponding empty interface gnu.jel.reflect.String to denote objects automatically convertible to java.lang.String by means of their .toString() method. For example, if x is of a class implementing gnu.jel.reflect.String interface the expression x+"a" will be compiled into x.toString()+"a" (otherwise this expression produces a error message). The objects automatically convertible to strings can also be supplied as arguments of methods requiring java.lang.String (usual method overloading rules apply). Still, in the current version of JEL it is impossible to cast methods of java.lang.String on such objects. That is x.substring(1) is a syntax error (unless x itself has the .substring(int) method). This deficiency can be addressed in future.

Chapter 7. Error detection and reporting

Expressions are made by human, and making errors is the natural property of humans, consequently, JEL has to be aware of that.

There are two places, where errors can appear. First are the compilation errors, which are thrown in the form of gnu.jel.CompilationException by the gnu.jel.Evaluator.compile. These errors signal about syntax problems in the entered expressions, wrong function names, illegal types combinations, but NOT about illegal values of arguments of functions. The second source of errors is the compiled code itself, Throwables, thrown out of gnu.jel.CompiledExpression.evaluate are primarily due to the invalid values of function arguments.

Compilation errors are easy to process. Normally, you should surround compilation by the

   try {
      // ... compilation
   catch (CompilationException e) {
      // ... process and report the error
   }

block. Caught gnu.jel.CompilationException can be interrogated, then, on the subject of WHERE error has occurred (getCol) and WHAT was the error (getMessage). This information should then be presented to user. It is wise to use information about error column to position the cursor automatically to the erroneous place in the expression.

Errors of the second type are appearing during the function evaluation and can not be so nicely dealt with by JEL. They depend on the actual library, supplied to the compiler. For example methods of java.lang.Math do not generate any checked exceptions at all (still, Errors are possible), but you may connect library, of functions throwing exceptions. As a general rule : exceptions thrown by functions from the library are thrown from evaluate method

Chapter 8. Making things faster

In the above text the result of the computation, returned by evaluate was always an object. While this is very flexible it is not very fast. Objects have to be allocated on heap and garbage collected. When the result of computation is a value of one of Java primitive types it can be desirable to retrieve it without creation of the object. This can be done (since the version 0.2 of JEL) with evaluateXX() family of calls (see gnu.jel.CompiledExpression. There is an evaluateXX() method for each Java primitive type, if you know what type expression has you can just call the corresponding method.

If you do not know the type of the compiled expression you can query it using getType. Be warned, that the call to wrong evaluateXX method will result in exception. Another tricky point is that JEL always selects smallest data type for constant representation. Namely, expression "1" has type byte and not int, thus in most cases you will have to query the type, and only then, call the proper evaluateXX method.

It is anyway possible to eliminate type checks at evaluation time completely. There is a version of compile method in gnu.jel.Evaluator, which allows to fix the type of the result. It directs the compiler to perform the widening conversion to the given type, before returning the result. For example: if you fix the type to be int (passing java.lang.Integer.TYPE as an argument to compile) all expressions (such as "1", "2+5", "2*2") will be evaluated by evaluate_int method of the compiled expression. Also, the attempt to evaluate "1+2L" will be rejected by compiler, asking to insert the explicit narrowing conversion (such as "(int)(1+2L)").

Chapter 9. Serialization of compiled expressions

There used to be a specialized serialization interface in JEL up to version 0.8.3. The need for such interface was dictated by the fact that JEL allowed to use constants of arbitrary reference types in expressions, which is not supported directly by the Java class file format. Starting with version 0.9 this feature was removed and now JEL generates ordinary Java class files.

To store compiled expressions into a file just grab their code with gnu.jel.Evaluator.compileBits. The code is returned as a byte array which is easy to save/restore. Then, the expression can be instantiated using gnu.jel.ImageLoader with the code

byte[] image; 
// ... code to read the JEL-generated class file into the "image" ...
CompiledExpression expression=(CompiledExpression)(ImageLoader.load(image)).newInstance();

or, alternatively, by compiling your source against generated class file. Note that in this version of JEL all generated classes have the name "dump" and are in the root package. If there will be such need in future the Evaluator interface can be extended to assign user-supplied names for new expressions.

Chapter 10. Limitations of JEL

There is one serious limitation, which should be mentioned. Actually it is not a JEL limitation but rather a limitation of the typical Java run-time

To load compiled expressions into the Java virtual machine memory JEL uses a custom java.lang.ClassLoader. While there is nothing wrong with that, setting up a classLoader is a privileged operation in Java. This means either JEL should run in a Java application (there are no security restrictions on Java applications), or , if JEL is distributed in some custom applet the applet should be signed.

Chapter 11. Summarizing remarks

I hope you found JEL useful. Don't hesitate to contact me if there are any problems with JEL, please, report BUGS, suggest tests, send me your patches,... There are still many improvements to be done.

Most current information about JEL should be available at http://www.fti.dn.ua/JEL/.

JEL is the "free software" and is distributed to you under terms of GNU General Public License. Find the precise terms of the license in the file ./COPYING in the root of this distribution.

Please, contact the author directly if you'd like JEL to be commercially licensed to you on a different terms.

Appendix A. GNU Free Documentation License

Version 1.3, 3 November 2008

Copyright © 2000, 2001, 2002, 2007, 2008 Free Software Foundation, Inc.

Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.

0. PREAMBLE

The purpose of this License is to make a manual, textbook, or other functional and useful document “free” in the sense of freedom: to assure everyone the effective freedom to copy and redistribute it, with or without modifying it, either commercially or noncommercially. Secondarily, this License preserves for the author and publisher a way to get credit for their work, while not being considered responsible for modifications made by others.

This License is a kind of “copyleft”, which means that derivative works of the document must themselves be free in the same sense. It complements the GNU General Public License, which is a copyleft license designed for free software.

We have designed this License in order to use it for manuals for free software, because free software needs free documentation: a free program should come with manuals providing the same freedoms that the software does. But this License is not limited to software manuals; it can be used for any textual work, regardless of subject matter or whether it is published as a printed book. We recommend this License principally for works whose purpose is instruction or reference.

1. APPLICABILITY AND DEFINITIONS

This License applies to any manual or other work, in any medium, that contains a notice placed by the copyright holder saying it can be distributed under the terms of this License. Such a notice grants a world-wide, royalty-free license, unlimited in duration, to use that work under the conditions stated herein. The “Document”, below, refers to any such manual or work. Any member of the public is a licensee, and is addressed as “you”. You accept the license if you copy, modify or distribute the work in a way requiring permission under copyright law.

A “Modified Version” of the Document means any work containing the Document or a portion of it, either copied verbatim, or with modifications and/or translated into another language.

A “Secondary Section” is a named appendix or a front-matter section of the Document that deals exclusively with the relationship of the publishers or authors of the Document to the Document’s overall subject (or to related matters) and contains nothing that could fall directly within that overall subject. (Thus, if the Document is in part a textbook of mathematics, a Secondary Section may not explain any mathematics.) The relationship could be a matter of historical connection with the subject or with related matters, or of legal, commercial, philosophical, ethical or political position regarding them.

The “Invariant Sections” are certain Secondary Sections whose titles are designated, as being those of Invariant Sections, in the notice that says that the Document is released under this License. If a section does not fit the above definition of Secondary then it is not allowed to be designated as Invariant. The Document may contain zero Invariant Sections. If the Document does not identify any Invariant Sections then there are none.

The “Cover Texts” are certain short passages of text that are listed, as Front-Cover Texts or Back-Cover Texts, in the notice that says that the Document is released under this License. A Front-Cover Text may be at most 5 words, and a Back-Cover Text may be at most 25 words.

A “Transparent” copy of the Document means a machine-readable copy, represented in a format whose specification is available to the general public, that is suitable for revising the document straightforwardly with generic text editors or (for images composed of pixels) generic paint programs or (for drawings) some widely available drawing editor, and that is suitable for input to text formatters or for automatic translation to a variety of formats suitable for input to text formatters. A copy made in an otherwise Transparent file format whose markup, or absence of markup, has been arranged to thwart or discourage subsequent modification by readers is not Transparent. An image format is not Transparent if used for any substantial amount of text. A copy that is not “Transparent” is called “Opaque”.

Examples of suitable formats for Transparent copies include plain ASCII without markup, Texinfo input format, LaTeX input format, SGML or XML using a publicly available DTD, and standard-conforming simple HTML, PostScript or PDF designed for human modification. Examples of transparent image formats include PNG, XCF and JPG. Opaque formats include proprietary formats that can be read and edited only by proprietary word processors, SGML or XML for which the DTD and/or processing tools are not generally available, and the machine-generated HTML, PostScript or PDF produced by some word processors for output purposes only.

The “Title Page” means, for a printed book, the title page itself, plus such following pages as are needed to hold, legibly, the material this License requires to appear in the title page. For works in formats which do not have any title page as such, “Title Page” means the text near the most prominent appearance of the work’s title, preceding the beginning of the body of the text.

The “publisher” means any person or entity that distributes copies of the Document to the public.

A section “Entitled XYZ” means a named subunit of the Document whose title either is precisely XYZ or contains XYZ in parentheses following text that translates XYZ in another language. (Here XYZ stands for a specific section name mentioned below, such as “Acknowledgements”, “Dedications”, “Endorsements”, or “History”.) To “Preserve the Title” of such a section when you modify the Document means that it remains a section “Entitled XYZ” according to this definition.

The Document may include Warranty Disclaimers next to the notice which states that this License applies to the Document. These Warranty Disclaimers are considered to be included by reference in this License, but only as regards disclaiming warranties: any other implication that these Warranty Disclaimers may have is void and has no effect on the meaning of this License.

2. VERBATIM COPYING

You may copy and distribute the Document in any medium, either commercially or noncommercially, provided that this License, the copyright notices, and the license notice saying this License applies to the Document are reproduced in all copies, and that you add no other conditions whatsoever to those of this License. You may not use technical measures to obstruct or control the reading or further copying of the copies you make or distribute. However, you may accept compensation in exchange for copies. If you distribute a large enough number of copies you must also follow the conditions in section 3.

You may also lend copies, under the same conditions stated above, and you may publicly display copies.

3. COPYING IN QUANTITY

If you publish printed copies (or copies in media that commonly have printed covers) of the Document, numbering more than 100, and the Document’s license notice requires Cover Texts, you must enclose the copies in covers that carry, clearly and legibly, all these Cover Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on the back cover. Both covers must also clearly and legibly identify you as the publisher of these copies. The front cover must present the full title with all words of the title equally prominent and visible. You may add other material on the covers in addition. Copying with changes limited to the covers, as long as they preserve the title of the Document and satisfy these conditions, can be treated as verbatim copying in other respects.

If the required texts for either cover are too voluminous to fit legibly, you should put the first ones listed (as many as fit reasonably) on the actual cover, and continue the rest onto adjacent pages.

If you publish or distribute Opaque copies of the Document numbering more than 100, you must either include a machine-readable Transparent copy along with each Opaque copy, or state in or with each Opaque copy a computer-network location from which the general network-using public has access to download using public-standard network protocols a complete Transparent copy of the Document, free of added material. If you use the latter option, you must take reasonably prudent steps, when you begin distribution of Opaque copies in quantity, to ensure that this Transparent copy will remain thus accessible at the stated location until at least one year after the last time you distribute an Opaque copy (directly or through your agents or retailers) of that edition to the public.

It is requested, but not required, that you contact the authors of the Document well before redistributing any large number of copies, to give them a chance to provide you with an updated version of the Document.

4. MODIFICATIONS

You may copy and distribute a Modified Version of the Document under the conditions of sections 2 and 3 above, provided that you release the Modified Version under precisely this License, with the Modified Version filling the role of the Document, thus licensing distribution and modification of the Modified Version to whoever possesses a copy of it. In addition, you must do these things in the Modified Version:

  1. Use in the Title Page (and on the covers, if any) a title distinct from that of the Document, and from those of previous versions (which should, if there were any, be listed in the History section of the Document). You may use the same title as a previous version if the original publisher of that version gives permission.
  2. List on the Title Page, as authors, one or more persons or entities responsible for authorship of the modifications in the Modified Version, together with at least five of the principal authors of the Document (all of its principal authors, if it has fewer than five), unless they release you from this requirement.
  3. State on the Title page the name of the publisher of the Modified Version, as the publisher.
  4. Preserve all the copyright notices of the Document.
  5. Add an appropriate copyright notice for your modifications adjacent to the other copyright notices.
  6. Include, immediately after the copyright notices, a license notice giving the public permission to use the Modified Version under the terms of this License, in the form shown in the Addendum below.
  7. Preserve in that license notice the full lists of Invariant Sections and required Cover Texts given in the Document’s license notice.
  8. Include an unaltered copy of this License.
  9. Preserve the section Entitled “History”, Preserve its Title, and add to it an item stating at least the title, year, new authors, and publisher of the Modified Version as given on the Title Page. If there is no section Entitled “History” in the Document, create one stating the title, year, authors, and publisher of the Document as given on its Title Page, then add an item describing the Modified Version as stated in the previous sentence.
  10. Preserve the network location, if any, given in the Document for public access to a Transparent copy of the Document, and likewise the network locations given in the Document for previous versions it was based on. These may be placed in the “History” section. You may omit a network location for a work that was published at least four years before the Document itself, or if the original publisher of the version it refers to gives permission.
  11. For any section Entitled “Acknowledgements” or “Dedications”, Preserve the Title of the section, and preserve in the section all the substance and tone of each of the contributor acknowledgements and/or dedications given therein.
  12. Preserve all the Invariant Sections of the Document, unaltered in their text and in their titles. Section numbers or the equivalent are not considered part of the section titles.
  13. Delete any section Entitled “Endorsements”. Such a section may not be included in the Modified Version.
  14. Do not retitle any existing section to be Entitled “Endorsements” or to conflict in title with any Invariant Section.
  15. Preserve any Warranty Disclaimers.

If the Modified Version includes new front-matter sections or appendices that qualify as Secondary Sections and contain no material copied from the Document, you may at your option designate some or all of these sections as invariant. To do this, add their titles to the list of Invariant Sections in the Modified Version’s license notice. These titles must be distinct from any other section titles.

You may add a section Entitled “Endorsements”, provided it contains nothing but endorsements of your Modified Version by various parties — for example, statements of peer review or that the text has been approved by an organization as the authoritative definition of a standard.

You may add a passage of up to five words as a Front-Cover Text, and a passage of up to 25 words as a Back-Cover Text, to the end of the list of Cover Texts in the Modified Version. Only one passage of Front-Cover Text and one of Back-Cover Text may be added by (or through arrangements made by) any one entity. If the Document already includes a cover text for the same cover, previously added by you or by arrangement made by the same entity you are acting on behalf of, you may not add another; but you may replace the old one, on explicit permission from the previous publisher that added the old one.

The author(s) and publisher(s) of the Document do not by this License give permission to use their names for publicity for or to assert or imply endorsement of any Modified Version.

5. COMBINING DOCUMENTS

You may combine the Document with other documents released under this License, under the terms defined in section 4 above for modified versions, provided that you include in the combination all of the Invariant Sections of all of the original documents, unmodified, and list them all as Invariant Sections of your combined work in its license notice, and that you preserve all their Warranty Disclaimers.

The combined work need only contain one copy of this License, and multiple identical Invariant Sections may be replaced with a single copy. If there are multiple Invariant Sections with the same name but different contents, make the title of each such section unique by adding at the end of it, in parentheses, the name of the original author or publisher of that section if known, or else a unique number. Make the same adjustment to the section titles in the list of Invariant Sections in the license notice of the combined work.

In the combination, you must combine any sections Entitled “History” in the various original documents, forming one section Entitled “History”; likewise combine any sections Entitled “Acknowledgements”, and any sections Entitled “Dedications”. You must delete all sections Entitled “Endorsements”.

6. COLLECTIONS OF DOCUMENTS

You may make a collection consisting of the Document and other documents released under this License, and replace the individual copies of this License in the various documents with a single copy that is included in the collection, provided that you follow the rules of this License for verbatim copying of each of the documents in all other respects.

You may extract a single document from such a collection, and distribute it individually under this License, provided you insert a copy of this License into the extracted document, and follow this License in all other respects regarding verbatim copying of that document.

7. AGGREGATION WITH INDEPENDENT WORKS

A compilation of the Document or its derivatives with other separate and independent documents or works, in or on a volume of a storage or distribution medium, is called an “aggregate” if the copyright resulting from the compilation is not used to limit the legal rights of the compilation’s users beyond what the individual works permit. When the Document is included in an aggregate, this License does not apply to the other works in the aggregate which are not themselves derivative works of the Document.

If the Cover Text requirement of section 3 is applicable to these copies of the Document, then if the Document is less than one half of the entire aggregate, the Document’s Cover Texts may be placed on covers that bracket the Document within the aggregate, or the electronic equivalent of covers if the Document is in electronic form. Otherwise they must appear on printed covers that bracket the whole aggregate.

8. TRANSLATION

Translation is considered a kind of modification, so you may distribute translations of the Document under the terms of section 4. Replacing Invariant Sections with translations requires special permission from their copyright holders, but you may include translations of some or all Invariant Sections in addition to the original versions of these Invariant Sections. You may include a translation of this License, and all the license notices in the Document, and any Warranty Disclaimers, provided that you also include the original English version of this License and the original versions of those notices and disclaimers. In case of a disagreement between the translation and the original version of this License or a notice or disclaimer, the original version will prevail.

If a section in the Document is Entitled “Acknowledgements”, “Dedications”, or “History”, the requirement (section 4) to Preserve its Title (section 1) will typically require changing the actual title.

9. TERMINATION

You may not copy, modify, sublicense, or distribute the Document except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, or distribute it is void, and will automatically terminate your rights under this License.

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, receipt of a copy of some or all of the same material does not give you any rights to use it.

10. FUTURE REVISIONS OF THIS LICENSE

The Free Software Foundation may publish new, revised versions of the GNU Free Documentation 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. See Copyleft.

Each version of the License is given a distinguishing version number. If the Document specifies that a particular numbered version of this License “or any later version” applies to it, you have the option of following the terms and conditions either of that specified version or of any later version that has been published (not as a draft) by the Free Software Foundation. If the Document does not specify a version number of this License, you may choose any version ever published (not as a draft) by the Free Software Foundation. If the Document specifies that a proxy can decide which future versions of this License can be used, that proxy’s public statement of acceptance of a version permanently authorizes you to choose that version for the Document.

11. RELICENSING

“Massive Multiauthor Collaboration Site” (or “MMC Site”) means any World Wide Web server that publishes copyrightable works and also provides prominent facilities for anybody to edit those works. A public wiki that anybody can edit is an example of such a server. A “Massive Multiauthor Collaboration” (or “MMC”) contained in the site means any set of copyrightable works thus published on the MMC site.

“CC-BY-SA” means the Creative Commons Attribution-Share Alike 3.0 license published by Creative Commons Corporation, a not-for-profit corporation with a principal place of business in San Francisco, California, as well as future copyleft versions of that license published by that same organization.

“Incorporate” means to publish or republish a Document, in whole or in part, as part of another Document.

An MMC is “eligible for relicensing” if it is licensed under this License, and if all works that were first published under this License somewhere other than this MMC, and subsequently incorporated in whole or in part into the MMC, (1) had no cover texts or invariant sections, and (2) were thus incorporated prior to November 1, 2008.

The operator of an MMC Site may republish an MMC contained in the site under CC-BY-SA on the same site at any time before August 1, 2009, provided the MMC is eligible for relicensing.

ADDENDUM: How to use this License for your documents

To use this License in a document you have written, include a copy of the License in the document and put the following copyright and license notices just after the title page:

Copyright © YEAR YOUR NAME

Permission is granted to copy, distribute and/or modify this document under the
terms of the GNU Free Documentation License, Version 1.3 or any later version
published by the Free Software Foundation; with no Invariant Sections, no
Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in
the section entitled “GNU Free Documentation License”.

If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts, replace the “with… Texts.” line with this:

with the Invariant Sections being LIST THEIR TITLES, with the Front-Cover Texts
being LIST, and with the Back-Cover Texts being LIST.

If you have Invariant Sections without Cover Texts, or some other combination of the three, merge those two alternatives to suit the situation.

If your document contains nontrivial examples of program code, we recommend releasing these examples in parallel under your choice of free software license, such as the GNU General Public License, to permit their use in free software.

docs/EC.html0000644000175000017500000001211212714113765011655 0ustar olesoles BNF for EC.jj

BNF for EC.jj

NON-TERMINALS

expression ::= conditional ( <EOF> )
conditional ::= lor ( "?" conditional ":" conditional )?
lor ::= land ( <LOR> land )*
land ::= bor ( <LAND> bor )*
bor ::= bxor ( <OR> bxor )*
bxor ::= band ( <XOR> band )*
band ::= equality ( <AND> equality )*
equality ::= relation ( ( <EQ> | <NE> ) relation )*
relation ::= shift ( ( <LT> | <GE> | <GT> | <LE> ) shift )*
shift ::= sum ( ( <LS> | <RS> | <RUS> ) sum )*
sum ::= term ( ( <PLUS> | <MINUS> ) term )*
term ::= unary ( ( <MULTIPLY> | <DIVIDE> | <REMAINDER> ) unary )*
unary ::= ( <BWCOMPL> | <LOGCOMPL> | <MINUS> ) unary
| "(" <ID> ( "." <ID> )* ")" element
| element
element ::= <TRUE>
| <FALSE>
| ( ( literal | "(" conditional ")" | invocation ) ( <DOT> invocation )* )
invocation ::= <ID> ( "(" ( conditional ( "," conditional )* )? ")" )? ( "[" conditional "]" )*
literal ::= <INTEGER_LITERAL>
| <FLOATING_POINT_LITERAL>
| <CHARACTER_LITERAL>
| <STRING_LITERAL>
README0000644000175000017500000001124112714113765010432 0ustar olesolesThis document corresponds to the jel version 2.1.1 Distribution assembled May 9 2016. Welcome to Java Expressions Library (JEL) . JEL is designed to evaluate expressions, written in simple, JAVA like language. Unlike many other approaches to the same problem, JEL, is not interpreter but it is a compiler. It compiles expressions directly to Java bytecodes. Other feature of JEL is the possibility to call Java functions directly (without any wrappers) from the expressions it compiles. JEL also performs constants folding extended to static methods (so that sin(1.0) is considered a constant expression and evaluated at a compile time) with possibility to override this behaviour on method by method basis, i.e. for Math.random(). One of the design goals of JEL was to make it as SMALL as possible, but with extensibility in mind. You can find more details about JEL and its features if You open file ./docs/manual.html in Your favorite WWW browser. I. DISTRIBUTED FILES The structure of the distribution is following: ./docs Contains documentation, both written and javadoc generated. ./lib Holds precompiled JEL library in two versions : optimized (jel.jar),and debug (jel_g.jar). If You use JEL regularly it is the best to put one of those libraries into Your CLASSPATH. the third file in this directory (jel_rt.jar) is a runtime for unserialized JEL compiled expressions (includes String manipulation library). ./samples Contains samples and test suite for JEL. Currently (version 2.1.1) there is only one sample, Calculator. If You write a simple, free program, using JEL, I will be happy to put is as a sample. Anyway, there are still more samples coming in the next version. ./source Contains JEL source. If You make any modifications to JEL it is the best to do them directly in the ./src directory, because it most closely resembles the structure of my SVN repository. This directory contains ALL source files, some of them are duplicated in ./samples but ./src is the master copy. It should be possible to build JEL by running ant in this directory. II. INSTALLATION There is not much care to take about JEL installation. First, of course, You need to install JAVA (if You don't have it already). JEL 2.0 should work in any JDK 5 compatible Java virtual machine (for older JDKs please use earlier versons of JEL). If You don't want to type long command lines I would suggest to put JEL into the Java CLASSPATH. The other approach can be to write shell scripts, prepending ./lib/jel.jar to CLASSPATH of programs, using JEL. I didn't prepackage such scripts first of all, because I have CLASSPATH set, and, second , because these scripts will be very much platform dependent. When compling JEL from source it is important to have the code generator tables in place (otherwise the exception with the message "[DEBUG] Exception when reading tables" will be thrown). The tables are kept in "gnu/jel/tables.dat" file inside of lib/*.jar archives, and (provided gnu/jel/TableKeeper.java is unchanged) can be simply copied into src/gnu/jel before running the freshly recompiled code. If you change the tables in TableKeeper.java, it is necessary to regenerate the "tables.dat". If you use the ANT build script the "tables.dat" file will be rebuilt automatically for you. Otherwise you'll need to compile the TableWriter.java and run it inside of "source/src/java" directory with the command "java gnu.jel.TableKeeper". After the run, the file "gnu/jel/tables.dat" will be written. The non-debug version of TableKeeper.java has the code for writing "tables.dat" file omitted. III. TEST SUITE It is recommended to run JEL test suite after the installation. Please consult ./samples/testsuite/README.TestSuite for details on how to run it. IIV. LICENSING JEL is distributed to You under terms of the GNU General Public License. This means it is "free software" (see file ./COPYING for precise definition). However, any program, using JEL _MUST_ be the "free software" as well. Commercial support is available. To find out more contact me (metlov@fti.dn.ua) directly. I would be very happy to consider requests for JEL enhancements and modifications (to fit some particular purpose), syntax of the input language, for example, can be easily changed... Contact me directly if You need customized, supported version of JEL. (c) 1998-2016 Konstantin L. Metlov This software is distributed to You under the terms of the GNU General Public license (GPLv3 and later). Copying and modifications are permitted. NO WARRANTY of any kind is provided. For precise terms of the license see the file COPYING in the root of the distribution. RELNOTES0000644000175000017500000000200412714113765010725 0ustar olesoles NEW FEATURES in version 2.1.1. 1. Better error messages for numerical literal overflow. Unlike the previous versions, which simply claimed that an unexpected character is encountered when numerical literals were too large to fit in various data types, this version returns a fully customizable error messages in a number of such cases. 2. Automatic boxing of the primitive types (and JEL reflection types). JEL now automatically wraps the primitive types into the corresponding Java reflection objects. Thus, it is now possible to call the function func(Integer i) via the expression "func(1)". Note that in this case two conversions are actually performed: 1) from byte to int (which is evaluated at compile time); 2) from int to java.lang.Integer (which takes place at run time). Still, it is advisable to use the primitive types in your expressions as much as possible for the best performance. 3. Minor spelling fixes. May 9 2016 Konstantin L. Metlov. samples/0000755000175000017500000000000012714113720011206 5ustar olesolessamples/calculator/0000755000175000017500000000000013053271321013336 5ustar olesolessamples/calculator/README0000644000175000017500000000376712714113765014245 0ustar olesolesHow to run the JEL calculator. Calculator is one of the simpliest (and FIRST) JEL based programs. It takes the expression as it's input, evaluates it once and prints the result. The sample command line to invoke the calculator on Windows is jre -cp ".;../../lib/jel.jar" Calculator "2*2" on Linux this will be java -cp ".:../../lib/jel.jar" Calculator "2*2" Both these commans should print the answer 4 promptly in their respec- tive environments. You can use functions, of java.lang.Math in your expressions. Expressions to try : "2*2", "pow(sin(1),2)+pow(sin(3),2)", "exp(log(55))", "exp(log(55F))", or any other.... Please report BUGS to metlov@fti.dn.ua. Notes : 1. Some shells try to interpret parts of expressions themselves when they are not quoted. For example expression "2|2" can not be properly executed in bash without quotes. Be sure to quote expressions if Your shell requires it. 2. This example does not demonstrate actual power of JEL as expression is evaluated only once. Then, compiling it becomes the waste of resources. Have this in mind, please. 3. The same as the first note. For the simple programs (as Calculator) You can achieve faster performance by DISABLING the JIT compiler in Your VM. This is because only single expression is to be compiled most methods in the compiler are executed only once. Be informed, that the classical(not HotSpot) JIT compiles methods when they are actually called. There is certain overhead connected with JIT compilation, and if most methods are going to be executed once better performance can be achieved by DISABLING jit. In the long run, of course, JVM with JIT outperforms JVM without it. Try to compare the runtime of jre -cp ".;../../lib/jel.jar" Calculator "2*2" and jre -nojit -cp ".;../../lib/jel.jar" Calculator "2*2" to see which is faster. Copyright (C) 2016 Konstantin L. Metlov This file is licensed to you under the terms of GNU Free Documentation License as given in the appendix of JEL Manual. samples/calculator/Calculator.java0000644000175000017500000001005412714113765016304 0ustar olesoles/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * This file is part of the Java Expressions Library (JEL). * For more information about JEL visit : http://fti.dn.ua/JEL/ * * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2006, 2007, 2009 Konstantin L. Metlov * * 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 . */ import gnu.jel.Evaluator; import gnu.jel.CompiledExpression; import gnu.jel.Library; import gnu.jel.CompilationException; public class Calculator { static final String[] help= {" This is a simple calculator, based on JEL.", "", " to use this calculator issue the following command :", " java Calculator \"expression\"", "", "Don't forget to use quotes around the expression if Your shell requires", " it. For example \"1&3\" will fail in WinNT cmd without quotes.", " The expression language is intuitively simple. You can use binary ", " operations : '+','-','*','/','%'(remainder),'&'(bitwise and),", " '|'(bitwise or), '^'(bitwise xor) , unary negation '-'. Also all ", " standard static functions of java.lang.Math are at Your disposal.", "Examples of expressions : \"1+1\", \"sin(1)\", \"random()\" .", "", "Of course the use of the compiler (what JEL is actually is) is crazy for ", "calculating expressions only once. This has a HUGE performance loss, but,", "this is just the demo. Enjoy !!!", "", "(c) 2009 by Konstantin L. Metlov (metlov@fti.dn.ua)", " This program is the free software and was distributed to You under", " terms of GNU General Public License. You should have the text of the", " license together with the source code of this sample and JEL itself.", " If You don't have the source code or license- contact me immediately." }; public static void main(String[] args) { if (args.length==0) { for(int i=0;i[1]; try { staticLib[0]=Class.forName("java.lang.Math"); } catch(ClassNotFoundException e) { // Can't be ;)) ...... in java ... ;) }; Library lib=new Library(staticLib,null,null,null,null); try { lib.markStateDependent("random",null); } catch (CompilationException e) { // Can't be also }; // Compile CompiledExpression expr_c=null; try { expr_c=Evaluator.compile(expr,lib); } catch (CompilationException ce) { System.err.print("--- COMPILATION ERROR :"); System.err.println(ce.getMessage()); System.err.print(" "); System.err.println(expr); int column=ce.getColumn(); // Column, where error was found for(int i=0;i. */ // This class is both used to resolve the dynamic variable names and // to provide their values. These two functions can also be // implemented by two different classes. public class DVResolverProvider extends gnu.jel.DVMap { private java.util.HashMap properties= new java.util.HashMap(); // adds a new property protected void addProperty(String name,Object value) { properties.put(name,value); }; // implements the method of DVResolver interface, // used by the compiler to query about available dynamic // variables public String getTypeName(String name) { Object val=properties.get(name); if (val==null) return null; // dynamic variable does not exist if (val instanceof Data) return "Data"; if (val instanceof String) return "String"; // the type is not supported we say the variable is not defined return null; }; // Next we have those YYY getXXXProperty(String) methods described in // the manual public Data getDataProperty(String name) { return (Data)properties.get(name); }; public String getStringProperty(String name) { return (String)properties.get(name); }; }; samples/testbed/GlobalContext.java0000644000175000017500000000217712714113765016270 0ustar olesoles/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * This file is part of the Java Expressions Library (JEL). * For more information about JEL visit : http://fti.dn.ua/JEL/ * * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2006, 2007, 2009 Konstantin L. Metlov * * 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 . */ public class GlobalContext { public double x; public Data d1; public Data d2; public GlobalContext(double x, Data d1, Data d2) { this.x=x; this.d1=d1; this.d2=d2; }; }; samples/testbed/YourTestBed.java0000644000175000017500000001100112714113765015716 0ustar olesoles/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * This file is part of the Java Expressions Library (JEL). * For more information about JEL visit : http://fti.dn.ua/JEL/ * * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2006, 2007, 2009 Konstantin L. Metlov * * 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 . */ public class YourTestBed { public static void main(String[] args) throws Throwable { //********************************************************** //**** to use JEL we first have to define the namespace **** // we shall export the static methods of java.lang.Math Class[] stLib=new Class[1]; stLib[0]=java.lang.Math.class; // we shall enable access to methods of two classes Class[] dynLib=new Class[2]; // we export global context fields/methods dynLib[0]=GlobalContext.class; // we export YYY getXXXProperty() methods for dynamic variable access dynLib[1]=DVResolverProvider.class; // this initializes the resolver object DVResolverProvider resolver=new DVResolverProvider(); // we shall allow dot operators on strings and data Class[] dotLib=new Class[2]; dotLib[0]=Data.class; dotLib[1]=java.lang.String.class; // finally, the namespace is defined by constructing the library class gnu.jel.Library lib= new gnu.jel.Library(stLib,dynLib,dotLib,resolver,null); //********************************************************** //******** Now we setup the global context and data ******* Object[] context=new Object[2]; GlobalContext gc=new GlobalContext(0.2,new Data(2),new Data(10)); context[0]=gc; context[1]=resolver; // this pointer for YYY getXXXProperty() methos //********************************************************** //******** We are ready to compile some expressions ******* gnu.jel.CompiledExpression expr; // constant expression expr=gnu.jel.Evaluator.compile("2*2",lib); System.out.println("2*2="+expr.evaluate(context)); // expression accessing the variables expr=gnu.jel.Evaluator.compile("x",lib); System.out.println("x="+expr.evaluate(context)); // three expressions accessing the variables with dot operator expr=gnu.jel.Evaluator.compile("d1.value",lib); System.out.println("d1.value="+expr.evaluate(context)); // expr=gnu.jel.Evaluator.compile("d2.value",lib); System.out.println("d2.value="+expr.evaluate(context)); // expr=gnu.jel.Evaluator.compile("(d1.value+d2.value)*x*10",lib); System.out.println("(d1.value+d2.value)*x*10="+expr.evaluate(context)); // also using static functions expr=gnu.jel.Evaluator.compile("round((d1.value+d2.value)*x*10)",lib); System.out.println("round((d1.value+d2.value)*x*10)="+expr.evaluate(context)); // LET's try dynamic variables // First, we add few _DYNAMICALLY_, this can (and intended to) be // done after the gnu.jel.Library initialization resolver.addProperty("sDvar","str1"); resolver.addProperty("dataDvar",new Data(3)); // now we can access them expr=gnu.jel.Evaluator.compile("sDvar",lib); System.out.println("sDvar="+expr.evaluate(context)); expr=gnu.jel.Evaluator.compile("dataDvar",lib); System.out.println("dataDvar="+expr.evaluate(context)); // it is possible to have hierarchical name space // let's add a second level of hierarchy resolver.addProperty("sDvar.data1",new Data(5)); resolver.addProperty("sDvar.data2",new Data(6)); resolver.addProperty("sDvar.str","This is string"); // we can access these also expr=gnu.jel.Evaluator.compile("sDvar.data1",lib); System.out.println("sDvar.data1="+expr.evaluate(context)); expr=gnu.jel.Evaluator.compile("sDvar.str",lib); System.out.println("sDvar.str="+expr.evaluate(context)); expr=gnu.jel.Evaluator.compile("sDvar.data2",lib); System.out.println("sDvar.data2="+expr.evaluate(context)); // they are ready for calculations expr=gnu.jel.Evaluator.compile("sDvar.data1+sDvar.data2+1",lib); System.out.println("sDvar.data1+sDvar.data2+1="+expr.evaluate(context)); // You can add more expressions here }; }; samples/testbed/Data.java0000644000175000017500000000236312714113765014371 0ustar olesoles/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * This file is part of the Java Expressions Library (JEL). * For more information about JEL visit : http://fti.dn.ua/JEL/ * * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2006, 2007, 2009 Konstantin L. Metlov * * 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 . */ public class Data implements gnu.jel.reflect.Double { public double value=10.0; public double squared_value() { return value*value; }; public Data(double value) { this.value=value; }; // implements gnu.jel.reflect.Double interface public double getValue() { return value; }; }; samples/testsuite/0000755000175000017500000000000013053271321013236 5ustar olesolessamples/testsuite/README0000644000175000017500000000212612714113765014131 0ustar olesolesThis is the testsuite for JEL. It contains many expressions (>15000), testing various aspects of the compiler. Apart from being useful in JEL development, this test suite may help the users to test compati- bility of JEL with their version of JVM (in case it is a non-standard one, or after a major Java specification update). Please run the testsuite jar file from the current directory in JEL distribution like this: java -jar tests.jar Testsuite depends on ../../source/third-party/junit.jar and tests JEL classes in ../../lib/jel.jar. If you need to test the debug version of the library (e.g. for a better diagnostics after jel.jar testing have failed), you will need to specify the class path and the main class manually like this: java -cp tests.jar:../../source/third-party/junit.jar:../../lib/jel_g.jar gnu.jel.JELTestSuite More tests in form of patches or wishes are always WELCOME !!! Copyright (C) 2009 Konstantin L. Metlov This file is licensed to you under the terms of GNU Free Documentation License as given in the appendix of JEL Manual. source/0000755000175000017500000000000013053271321011041 5ustar olesolessource/build.xml0000644000175000017500000002763412714113765012710 0ustar olesoles JEL]]> Copyright © 1998-${build.year} Konstantin L. Metlov All Rights Reserved.

Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the JEL manual.

]]>
source/src/0000755000175000017500000000000012714113765011642 5ustar olesolessource/src/docs/0000755000175000017500000000000012714113765012572 5ustar olesolessource/src/docs/README0000644000175000017500000001124112714113765013451 0ustar olesolesThis document corresponds to the jel version 2.1.1 Distribution assembled May 9 2016. Welcome to Java Expressions Library (JEL) . JEL is designed to evaluate expressions, written in simple, JAVA like language. Unlike many other approaches to the same problem, JEL, is not interpreter but it is a compiler. It compiles expressions directly to Java bytecodes. Other feature of JEL is the possibility to call Java functions directly (without any wrappers) from the expressions it compiles. JEL also performs constants folding extended to static methods (so that sin(1.0) is considered a constant expression and evaluated at a compile time) with possibility to override this behaviour on method by method basis, i.e. for Math.random(). One of the design goals of JEL was to make it as SMALL as possible, but with extensibility in mind. You can find more details about JEL and its features if You open file ./docs/manual.html in Your favorite WWW browser. I. DISTRIBUTED FILES The structure of the distribution is following: ./docs Contains documentation, both written and javadoc generated. ./lib Holds precompiled JEL library in two versions : optimized (jel.jar),and debug (jel_g.jar). If You use JEL regularly it is the best to put one of those libraries into Your CLASSPATH. the third file in this directory (jel_rt.jar) is a runtime for unserialized JEL compiled expressions (includes String manipulation library). ./samples Contains samples and test suite for JEL. Currently (version 2.1.1) there is only one sample, Calculator. If You write a simple, free program, using JEL, I will be happy to put is as a sample. Anyway, there are still more samples coming in the next version. ./source Contains JEL source. If You make any modifications to JEL it is the best to do them directly in the ./src directory, because it most closely resembles the structure of my SVN repository. This directory contains ALL source files, some of them are duplicated in ./samples but ./src is the master copy. It should be possible to build JEL by running ant in this directory. II. INSTALLATION There is not much care to take about JEL installation. First, of course, You need to install JAVA (if You don't have it already). JEL 2.0 should work in any JDK 5 compatible Java virtual machine (for older JDKs please use earlier versons of JEL). If You don't want to type long command lines I would suggest to put JEL into the Java CLASSPATH. The other approach can be to write shell scripts, prepending ./lib/jel.jar to CLASSPATH of programs, using JEL. I didn't prepackage such scripts first of all, because I have CLASSPATH set, and, second , because these scripts will be very much platform dependent. When compling JEL from source it is important to have the code generator tables in place (otherwise the exception with the message "[DEBUG] Exception when reading tables" will be thrown). The tables are kept in "gnu/jel/tables.dat" file inside of lib/*.jar archives, and (provided gnu/jel/TableKeeper.java is unchanged) can be simply copied into src/gnu/jel before running the freshly recompiled code. If you change the tables in TableKeeper.java, it is necessary to regenerate the "tables.dat". If you use the ANT build script the "tables.dat" file will be rebuilt automatically for you. Otherwise you'll need to compile the TableWriter.java and run it inside of "source/src/java" directory with the command "java gnu.jel.TableKeeper". After the run, the file "gnu/jel/tables.dat" will be written. The non-debug version of TableKeeper.java has the code for writing "tables.dat" file omitted. III. TEST SUITE It is recommended to run JEL test suite after the installation. Please consult ./samples/testsuite/README.TestSuite for details on how to run it. IIV. LICENSING JEL is distributed to You under terms of the GNU General Public License. This means it is "free software" (see file ./COPYING for precise definition). However, any program, using JEL _MUST_ be the "free software" as well. Commercial support is available. To find out more contact me (metlov@fti.dn.ua) directly. I would be very happy to consider requests for JEL enhancements and modifications (to fit some particular purpose), syntax of the input language, for example, can be easily changed... Contact me directly if You need customized, supported version of JEL. (c) 1998-2016 Konstantin L. Metlov This software is distributed to You under the terms of the GNU General Public license (GPLv3 and later). Copying and modifications are permitted. NO WARRANTY of any kind is provided. For precise terms of the license see the file COPYING in the root of the distribution. source/src/docs/CODEGEN_HOW_TO0000644000175000017500000001136412714113765014705 0ustar olesolesThis is a brief explanation on how to drive JEL's code generator in order to generate Java bytecode bypassing JEL's parser. If you plan to generate expressions by a program (as opposed to letting user to type them) this document might help you to eliminate parsing overhead. It might be also useful to someone who wishes to build a compiler for more complex languages on top of JEL. Why would you want to use JEL's code generator, as opposed to other Java assemblers/code generators ? Two main reasons for this are 1) Size. Up to my knowledge JEL is smallest of Java assemblers. 2) Performance. Due to the table-driven design instructions are fetched from pre-built tables instead of computing them at run-time. 2) Convenience. JEL can match data types to instructions to automatically generate the correct Java instructions for a particular operation on a particular data type. It does widening data type conversions automatically. There are two modes in which you can use JEL's code generator. The first is RAW assembler, it is provided by gnu.jel.ClassFile, and the second is type-matching assembler (implemented in gnu.jel.OPxxx classes). I. RAW MODE. By manipulating methods of gnu.jel.ClassFile you can create almost arbitrary Java classfiles (not only descendants of gnu.jel.CompiledExpression). The only feature currently absent from ClassFile is writing Exception tables (but this can be easily added). The ClassFile frees user from paying attention to the details of the Java class file format (like constant pool handling) and concentrate directly on the bytecode. II. TYPE-MATCHING ASSEMBLER. This helps to generate the bytecode once you have started a method of your class using ClassFile. It only works for expressions right now, but can be extended in obvious way to handle the control structures, which was not implemented because it would blow up the size compiler size and go out of a niche intended for JEL. I do have plans (when time permits) to make another project for a full featured programming language compiler on top of JEL. In order to generate the code for an expression you need first write it in a reverse Polish notation, then, set up an empty paramOPs stack, and then instantiate the OPxxx classes for each operand/operation in order. After passing through all your expression from left to right you'll have only a single OP in paramOPs stack, which represents all your expression. For example suppose you want to add a numbers 1+2+2 in reverse Polish notation this reads as 2 2 1 + + to create JEL's internal representation of this expression you do java.util.Stack paramOps= new java.util.Stack(); paramOPs.push(new OPLoad(new Byte(2))); paramOPs.push(new OPLoad(new Integer(2))); paramOPs.push(new OPLoad(new Long(1))); paramOPs.push(new OPbinary(paramOPs,0)); // 0 codes for '+' operation paramOPs.push(new OPbinary(paramOPs,0)); your code is now OP code=(OP) paramOPs.pop(); The type matching and widening conversions are done automatically by JEL, you can query the result type by checking code.resType field. In the case of the expression above the result will be equal to Class.forName("java.lang.Long"). You can perform constants folding on an expression by doing code.eval(); and throwing away a possibly emerged exception, which only signals that the code can't be evaluated completely. For the expression given above there will be no exception, because it is constant. Finally, you can flush the Java bytecode into the ClassFile (say, named cf) you have already set up. code.compile(cf); It will be appended to the code for the current method you already have there. III. WHAT INTERFACES MAY OR MAY NOT CHANGE. The reason for writing this document was that JEL internal interfaces have reached more or less optimal shape. Nevertheless, some things may change in future. In particular, the additional (convenience) bytecodes defined in ClassFile.code(long) method may change. The ClassFile.newMethod() will certainly change when exception tables will be implemented (however a compatible version may be provided). The methods of gnu.jel.OP will not change (there can be some more added though), and the constructors of all existing gnu.jel.OPxxx classes will not change (they are all what is needed to know to use JEL's code generator for expressions). If you are interested in using JEL's code generator directly, please drop me a note, so that I can inform you about interface changes. I hope this text was helpful. If not, send your suggestions to metlov@fti.dn.ua . Please, contact me also if I forgot to make some of the methods described above (or required otherwise) public. Copyright (C) 2009 Konstantin L. Metlov This file is licensed to you under the terms of GNU Free Documentation License as given in the appendix of JEL Manual. source/src/docs/manual.xml0000644000175000017500000021614412714113765014601 0ustar olesoles Java Expressions Library Dr Konstantin Metlov L. 1998 1999 2000 2001 2003 2006 2007 2009 2015 Konstantin L. Metlov <metlov@fti.dn.ua> Licensing Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the Appendix. About this manual This manual is mostly examples-based. It starts with two simple step-by-step examples (showing how to deal with static and dynamic libraries), which should give enough information for basic JEL usage (but don't forget to read the rest of this manual to learn how to get the top performance from JEL). Additional information can be found in API documentation. JEL design goals The main design goal was to create light weight expression compiler generating extremely fast code. The main emphasis is the code execution time and not the compilation time (it is nevertheless small). The other goal was to make JEL language to be very close to Java language with direct access to all built-in Java data types and functions. Features Support for all Java data types (boolean, byte, char, short, long, int, float, double, arrays, references) Octal (0456) and hexadecimal (0x1FFF) literals. Support for all Java arithmetic operators: + (add),- (subtract), * (multiply), / (divide), % (remainder), & (bitwise and),| (bitwise or), ^ (bitwise xor),~ (bitwise complement), << (left shift), >> (right signed shift), >>> (right unsigned shift); on most of supported data types according to Java Language Specification (JLS) Comparison operators (==,!=,<,>=,>,<=) as defined by Java Language Specification (JLS). dot (".") operator on objects ("abc".length()==3). dot (".") operator on objects ("abc".length()==3). Boolean logical operators (&&,||,!) with lazy evaluation (i.e. in the expression false&&complexBooleanFunction() the function is never called). Conditionals (true?2:3 = 2) Direct access to methods and fields of Java objects. Method overloading according to Java Language Specification. Support for methods with variable number of arguments (varargs), which is enabled for all methods, accepting array as their last argument. Dynamic variables interface allowing to add variables to JEL namespace without supplying the class file defining them. Automatic unwrapping of designated objects to Java primitive types. Support for strings. Objects of class java.lang.String can be directly entered into expressions using double quotes, also the standard Java escape codes are parsed. Example : "a string\n\015". String concatenation ("a"+2+(2>3)+object = "a2false"+object.toString()). User definable string comparison using usual relational operators "<", "<=", ">", ">=", "==", "!=", which uses locale by default. User-controllable object down-casting using "(class.name)var" syntax. It is possible to assign names to classes in JEL expressions to be different from their real Java class names. Constants folding, extended (by default, but can be controlled) to static methods (which are automatically called at compile time) and static fields (which are considered constants). High performance of generated code. How to use JEL. In this section a simple example of a program using JEL is given, and explained with references to more detailed sections of this manual. The example program evaluates the expression given on its command line (similar program exists in the distribution under the name ./samples/Calculator.java), let's follow it step by step. public static void main(String[] args) { // Assemble the expression StringBuffer expr_sb=new StringBuffer(); for(int i=0;i<args.length;i++) { expr_sb.append(args[i]); expr_sb.append(' '); }; String expr=expr_sb.toString(); This first part of the program is not related to JEL. It's purpose is to assemble the expression, possibly, containing spaces into the single line. This has to be done, because shells tend to tokenize parameters but we don't need it here. // Set up the library Class[] staticLib=new Class[1]; try { staticLib[0]=Class.forName("java.lang.Math"); } catch(ClassNotFoundException e) { // Can't be ;)) ...... in java ... ;) }; Library lib=new Library(staticLib,null,null,null,null); try { lib.markStateDependent("random",null); } catch (NoSuchMethodException e) { // Can't be also }; This piece of code establishes the namespace for use in JEL compiled expressions. The gnu.jel.Library object maintains this namespace. There can be two types of names in the Library : static and virtual (dynamic). Methods and variables of the first class are assumed (by default) to be dependent only on their arguments i.e. not to save any information from call to call (they are "stateless")... Examples are mathematical functions like sin, cos, log, constants E, PI in java.lang.Math. For such methods (fields) it does not matter how many times (when) they will be called (their value will be taken) the result will always be the same provided arguments (if they are present) are the same. Stateless methods will be evaluated by JEL at compile time if their arguments are constants (known at compile time). To define set of static functions(fields) it is needed to pass the array of Class objects, defining those functions, as the first parameter of the library constructor (see example above). Note ONLY STATIC functions of the Classes, passed in the first argument of the gnu.jel.Library constructor will be defined in the namespace. By default all static functions are considered "stateless" by JEL. However, some static functions still save their state (in static variables) in between calls. Thus they return different results, depending on when (how many times) they are is called even if their arguments are the same. If such function is evaluated at compile time, we have troubles, because it will be evaluated only once during expression lifetime and it's state dependence will be lost. Typical example of the static function, having a state is java.lang.Math.random. JEL has special mechanism, provided by gnu.jel.Library class to mark static functions as state dependent. (see the above example to find out how it was done for the java.lang.Math.random) The virtual functions, which are explicitly state dependent, will be discussed later in this document. The example we currently consider does not use them. However, virtual functions are, actually, most important to JEL because expression, containing all stateless functions, is a constant, it will be completely evaluated at compile time, there is absolutely no sense to evaluate such expression repeatedly (this is what JEL was designed for). Still we shall continue with this simple example as the following code is mostly independent of whether we use virtual functions or not... // Compile CompiledExpression expr_c=null; try { expr_c=Evaluator.compile(expr,lib); } catch (CompilationException ce) { System.err.print("–––COMPILATION ERROR :"); System.err.println(ce.getMessage()); System.err.print(" "); System.err.println(expr); int column=ce.getColumn(); // Column, where error was found for(int i=0;i<column+23-1;i++) System.err.print(' '); System.err.println('^'); }; This chunk of code is for the expression compilation. The crucial line is the call to Evaluator.compile, it is the point, where expression gets transformed into Java bytecode, loaded into the Java Virtual Machine using JEL ClassLoader and returned to caller as an instance of the subclass of gnu.jel.CompiledExpression. Typical user of JEL is not required to know what magic is going on inside of Evaluator.compile(...). Other code in this chunk is for the error reporting and will be discussed in the specialized section below. if (expr_c !=null) { // Evaluate (Can do it now any number of times FAST !!!) Number result=null; try { result=(Number)expr_c.evaluate(null); } catch (Throwable e) { System.err.println("Exception emerged from JEL compiled"+ " code (IT'S OK) :"); System.err.print(e); }; This code does the evaluation of the expression. It is done by calling the evaluate method of the JEL compiled class, it is defined abstract in gnu.jel.CompiledExpression but is redefined in the class compiled by JEL. The argument of this method is discussed in the section on virtual functions below. If only static functions are present in the library it is safe to pass the null pointer as the argument to evaluate. Result of the evaluate method is always an object. JEL converts primitive numeric types into instances of corresponding Java reflection classes (read the section to find out how to avoid this conversion). For example, a value of primitive type long will be returned as an instance of java.lang.Long class (int maps to java.lang.Integer, float to java.lang.Float, etc.). If result is an arbitrary Java object it is returned as the reference to that object. The try ... catch clause around the call to evaluate will be enforced by the Java compiler. It is required as errors can appear during evaluation. The general rule is: syntax, types incompatibility and function resolution errors will be reported at compile time (as thrown instance of gnu.jel.CompilationException), while the errors in the values of numbers will be reported at the execution time. For example expression "1/0" will generate no error at compile time (nevertheless it is the constant expression and its evaluation is attempted), but at the time of calling execute you will get a java.lang.ArithmeticError (division by zero) as it should be. // Print result if (result==null) System.out.println("void"); else System.out.println(result.toString()); }; }; This last piece of code will print the result. And is concluding our brief tour of the JEL usage. Using libraries The namespace of JEL expressions is represented by gnu.jel.Library class. Its constructor: Library(Class[] staticLib, Class[] dynamicLib, Class[] dotClasses, DVMap  resolver, Hashtable cnmap)has five arguments. Their purposes are following: staticLib enumerates classes whose static methods are exported to JEL namespace and become usable from within expressions. Such methods do not require this pointer supplied to them at execution time. More details dynamicLib enumerates classes whose virtual methods are exported. These methods require the references to the corresponding classes (this pointers) supplied to the expression at run-time. This is done using the Class[]> argument of CompiledExpression's evaluate method. More details dotClasses controls access for the dot (".") operator on classes. More details resolver Dynamic variables interface. Allows to add new variables to the expressions names without supplying the class files defining them. More details cnmap Maps the class names usable inside JEL expressions for non-primitive type casts into the Java classes More details The details on usage of each of these arguments are given in a separate sections below. The working example using all current functionality of JEL namespace is given in the examples/YourTestBed directory in the distribution. You'll want to check it after reading this section.
Exporting static methods of classes to JEL namespace. The array of references to classes (java.lang.Class) whose public static methods and fields are to be exported should be passed as the first argument of the library constructor (staticLib). The public static fields and methods of all these classes are merged together into the JEL namespace. The non-public or non-static members of staticLib classes are ignored. Methods overloading is supported and works also across classes (because the JEL namespace works similarly to the namespace defined in a single Java class). For example, if a class C1 contains the method public static C1.func(int) and a class C2 contains the method public static C2.func(double) and both these classes are passed as elements of the staticLib array. Then, the JEL expression "func(1)" calls C1.func(int) and the expression "func(1.0)" calls C2.func(double). It also means that methods and fields of all classes supplied to the Library are subject to the same constraints as members of a single Java class. Moreover, because JEL allows to call methods with no arguments omitting the empty brackets (that is "func()" and "func" are equivalent) there should be no fields and methods with no arguments having the same names in all classes presented to the Library constructor. To check whether the set of classes you gave to the library constructor satisfies all required constraints run your program against the debug version of JEL library (jel_g.jar). Then, potential problems will be reported to you on the standard output.
Exporting virtual methods of classes to JEL namespace. The second argument of the library constructor (dynamicLib) works similarly to the first one. Except that only public virtual members are taken from the listed classes. These members are merged into the namespace created from classes from the staticLib. The rules for methods overloading are the same as for classes listed in the first argument of library constructor. Also, the overloading is working across the classes listed in both first and second arguments of the Library constructor. The crucial difference in the handling of classes listed in the dynamicLib and the staticLib comes from the fact that virtual members of dynamicLib require this reference to the instance of the object of their defining class be supplied at run-time. Thus, if C1 contains the virtual method public func(double x) its invocation actually requires two arguments, one is x and the other is the reference to the instance of class C1. References to the instances of classes of the dynamicLib array are supplied at the execution time to the argument of the evaluate(Object[] context) method of gnu.jel.CompiledExpression. The elements of the context array should be instances of classes listed in dynamicLib array at compile time and there should be one-to-one correspondence between them. For example, if dynamicLib[0]=com.mycompany.MyClass.class), the corresponding entry in the context array, context[0], must be a reference to the instance of com.mycompany.MyClass. Formally, for every i, it should be possible to cast the object in the context[i] into the class, supplied in the dynamicLib[i] array of the Library constructor, otherwise ClassCastException will be thrown from evaluate. Let's walk through the example, which calculates function of the single variable many times and uses virtual method calls. This example will consist of two classes : a user written class (providing access to the variable) and the main class compiling and evaluating expressions. First start with the variable provider:public class VariableProvider { public double xvar; public double x() {return xvar;}; }; This class is trivial, it just defines the function, returning the value of the variable x. In the main class (see the first JEL example for headers) the code, constructing the library will be replaced with: // Set up library Class[] staticLib=new Class[1]; try { staticLib[0]=Class.forName("java.lang.Math"); } catch(ClassNotFoundException e) { // Can't be ;)) ...... in java ... ;) }; Class[] dynamicLib=new Class[1]; VariableProvider variables=new VariableProvider(); Object[] context=new Object[1]; context[0]=variables; dynamicLib[0]=variables.getClass(); Library lib=new Library(staticLib,dynamicLib,null,null,null); try { lib.markStateDependent("random",null); } catch (NoSuchMethodException e) { // Can't be also };Absent in the static example, the additional code creates the VariableProvider and assigns its reference to an element of context array (to be passed to the evaluate method of the compiled expression). Also, now the dynamicLib array as not null and contains the reference to the VariableProvider class. The code for compilation is exactly the same as in the example for static functions, except we have additional function x and the variable xvar defined for use inside the compiled expressions. JEL has the special notation for the functions, having no arguments, namely, brackets in "x()" can be omitted to be "x". This allows to compile now ( with the above defined library) the expressions like "sin(x)", "exp(x*x)", "pow(sin(x),2)+pow(cos(x),2)"... The code for evaluation of an expression having virtual functions is replaced with: if (expr_c !=null) { try { for(int i=0;i<100;i++) { variables.xvar=i; // <- Value of the variable System.out.println(expr_c.evaluate(context)); //^^^^^^^^^^^^^^^ evaluating 100 times }; } catch (Throwable e) { System.err.println("Exception emerged from JEL compiled"+ " code (IT'S OK) :"); System.err.print(e); }; }; Note the two major differences: 1. we have explicitly assigned the value to the variable; 2. the array of object references (consisting of one element in this example) is passed to the evaluate method. This piece of code will evaluate expressions for x=0..99 with step 1. This concludes our dynamic library example. Try to modify the ./Calculator.java sample yourself to allow compilation of virtual functions as described above.
Variable number of arguments support. Since the version 2.0.3 JEL supports calling methods with variable number of arguments. Moreover, because the information about the variable arguments declaration is not available via Java reflection, this support extends to all methods, having the array last argument. For example, if two following functions are declared in the library classes (static or dynamic) public int sum (int[] args); public double powersum(double power, double[] args); it is possible to use them in the expressions as "sum(1)", "sum(1,2)", "powersum(2,1,2,3)", etc... The argument array will be created automatically by the compiler in these cases. The methods with variable number of arguments are subject to the same method overloading rules, automatic argument type conversions and constants folding as other methods.
Enabling the dot operator on objects. The third argument of gnu.jel.Library constructor enumerates classes which are available for dot operator within the expression. If this parameter is null JEL would not allow to use the dot operator at all. If it is an array of the length zero (e.g. new Class[0]) JEL will open access to public methods of ALL objects encountered in the expression. From the security point of view allowing access to all objects can be dangerous, that is why there is a third case of non-zero length array explicitly enumerating classes allowing the dot operator on them. Once the dot operator is allowed on a class, it is possible to call all its public methods using the syntax ".method(arg1,arg2,...)" in any context where this class appears in an expression.
Dynamic variables interface. All methods of exporting names into JEL namespace described up to this point relied on the Java class files for actual description of methods names and parameters. However, sometimes it is required to add a new variable to JEL namespace at run-time. One of the solutions would be to generate a new class file (e.g. using JEL) and supply it as a first or second argument of the library constructor. Unfortunately this can be quite cumbersome and time consuming. The other solution can be to define a family of methods in JEL namespace YYY getXXXProperty(String name)for each possible variable types, where YYY is the class representing the property type and XXX is the name of the type. Then, supposing we have methods double getDoubleProperty(String name); // YYY=double XXX=Double String getStringProperty(String name); // YYY=java.lang.String XXX=Stringin the JEL namespace (either static or dynamic), the variables with arbitrary names can be entered into expression using the syntaxgetStringProperty("x") + (getDoubleProperty("y")+1.0) This way has two drawbacks: 1) user has to remember the type of the variable (to call the appropriate getXXX() method); 2) a lot to type. Since the version 0.9.3 JEL provides the way to solve both these problems. To do that the fourth argument (resolver) of the library constructor is used. This argument supplies the reference to the subclass of gnu.jel.DVMap, and is used by JEL to resolve the dynamic variable names. The gnu.jel.DVMap has an abstract method public String getTypeName(String name) which returns XXX (see above) for a given variable name, or null if no such variable is defined. Note that for resolver to work the family of methods YYY getXXXProperty(String name) must still be present in JEL namespace (e.g. as members of one of dynamicLib[] classes). Then, supposingresolver.getTypeName("x")=="String" && resolver.getTypeName("y")=="Double" the expression "x+(y+1.0)" will be automatically converted by JEL into getStringProperty("x")+(getDoubleProperty("y")+1.0) and compiled. Thus, user does not have to remember the variable types, typing is reduced and the existence of variables can be checked at the compile time. JEL also supports a hierarchical structure of variables. This means the dot (".") symbol can be present in the dynamic variable names. For example if resolver.getTypeName("x")!=null && resolver.getTypeName("x.f1")=="String" && resolver.getTypeName("x.f2")=="Double" the expression "x.f1+(x.f2+1.0)" will be compiled by JEL as getStringProperty("x.f1")+(getDoubleProperty("x.f2")+1.0) and (combined with dot operator) the expression "x.f1.length()" will result in the length of the string getString("x1.f1"). Notice in the last example that if one wants to have defined the dynamic variable "x.y" the variable "x" must also be the dynamic variable (resolver.getTypeName("x")!=null). If there is conflict between the dynamic variable name and other name in JEL namespace the dynamic variable has a priority. Since JEL 0.9.9 it is possible to translate the names of dynamic variables from strings into the constants of Java primitive types. This is done using non-identity DVMap.translate method. The translation helps to improve performance in some cases. Consider the following example. Suppose the underlying storage for dynamic variables is an array (or Vector), so that the value of the variable can be obtained by an integer index into that array (like numbered columns in a spreadsheet). Next, assume you still want to refer to the variables by names (e.g. you allowed user to assign names to the columns). Now, if the first column is named "x" and is of Double type, an expression "x", using dynamic variables interface with identity translation will be compiled into getDoubleProperty("x"). It means the translation of the string "x" into the column number 1 will have to be performed at run-time each time the expression is evaluated. Considering that Java strings are immutable, this may incur a substantial performance penalty. The performance can be improved if the translate method of DVMap is overridden by the following: public Object translate(String name) { if (name.equals("x")) return new Integer(1); return name; }; This is already a non-identity translation. With such DVMap the expression "x" will be compiled by JEL into getDoubleProperty(1), note that it is getDoubleProperty(int) method, which is called. This way the mapping of the variable name into the variable index is performed at compile-time, while at run-time the index is readily available. By defining the appropriate translations the dynamic variable lookup can be split in a user-controlled way between the expression compilation and execution stages to achieve the best performance. The translate method is allowed to return only instances of Java reflection classes wrapping the primitive types (java.lang.Integer, java.lang.Double, etc), or strings (otherwise an exception will emerge at compile-time). This is because only these types of objects can be stored in the Java class files directly. Also, it is responsibility of the caller to ensure that JEL namespace contains getXXXProperty methods with all the necessary argument types, corresponding to the translations defined in DVMap. For identity translations only getXXXProperty methods accepting strings are necessary.
Objects down-casting. The cnmap argument of gnu.jel.Library constructor, allows to enable the non-primitive type casts in JEL compiled expressions. If cnmap!=null it must be java.util.Hashtable with java.lang.Class objects as elements and java.lang.String objects as keys. When the object cast "(non_primitive_type_name) var" is encountered in the expression, "the non_primitive_type_name" string is looked in the cnmap hashtable and the cast to the corresponding class is generated by JEL. The absence of the name in the hashtable produces the compile-time error. It is possible for keys in cnmap to contain "." (dot) symbols in them.
Automatic unwrapping of objects to primitive types. This problem appears mostly when one uses dynamic variables, but may also arise in other cases. Suppose a reference to the object of the class Weight (representing a weight of a certain item) appeared in the expression. It is clear that Weight is always represented by a floating point number (although it may have other properties, like units). If the class Weight has the method public double getValue() the value of weight can be accessed in expressions using syntax w.getValue(), supposing the variable w has type Weight. To save typing (since version 0.9.3 of JEL) one may have the class Weight implement gnu.jel.reflect.Double interface. Then, the aforementioned getValue method will be called automatically by JEL (or object w will be "unwrapped" to primitive type). This unwrapping will be performed automatically when needed: one can have expressions "w+1.0" meaning "w.getValue()+1" and "w.getUnits()" both valid (in the second case w is not "unwrapped"). There are gnu.jel.reflect.* interfaces for all Java primitive types. To use the automatic unwrapping one just needs to make his classes to implement one of these interfaces. There is a similar mechanism for strings (since version 0.9.6) and a corresponding empty interface gnu.jel.reflect.String to denote objects automatically convertible to java.lang.String by means of their .toString() method. For example, if x is of a class implementing gnu.jel.reflect.String interface the expression x+"a" will be compiled into x.toString()+"a" (otherwise this expression produces a error message). The objects automatically convertible to strings can also be supplied as arguments of methods requiring java.lang.String (usual method overloading rules apply). Still, in the current version of JEL it is impossible to cast methods of java.lang.String on such objects. That is x.substring(1) is a syntax error (unless x itself has the .substring(int) method). This deficiency can be addressed in future. Error detection and reporting Expressions are made by human, and making errors is the natural property of humans, consequently, JEL has to be aware of that. There are two places, where errors can appear. First are the compilation errors, which are thrown in the form of gnu.jel.CompilationException by the gnu.jel.Evaluator.compile. These errors signal about syntax problems in the entered expressions, wrong function names, illegal types combinations, but NOT about illegal values of arguments of functions. The second source of errors is the compiled code itself, Throwables, thrown out of gnu.jel.CompiledExpression.evaluate are primarily due to the invalid values of function arguments. Compilation errors are easy to process. Normally, you should surround compilation by the try { // ... compilation catch (CompilationException e) { // ... process and report the error } block. Caught gnu.jel.CompilationException can be interrogated, then, on the subject of WHERE error has occurred (getCol) and WHAT was the error (getMessage). This information should then be presented to user. It is wise to use information about error column to position the cursor automatically to the erroneous place in the expression. Errors of the second type are appearing during the function evaluation and can not be so nicely dealt with by JEL. They depend on the actual library, supplied to the compiler. For example methods of java.lang.Math do not generate any checked exceptions at all (still, Errors are possible), but you may connect library, of functions throwing exceptions. As a general rule : exceptions thrown by functions from the library are thrown from evaluate method Making things faster In the above text the result of the computation, returned by evaluate was always an object. While this is very flexible it is not very fast. Objects have to be allocated on heap and garbage collected. When the result of computation is a value of one of Java primitive types it can be desirable to retrieve it without creation of the object. This can be done (since the version 0.2 of JEL) with evaluateXX() family of calls (see gnu.jel.CompiledExpression. There is an evaluateXX() method for each Java primitive type, if you know what type expression has you can just call the corresponding method. If you do not know the type of the compiled expression you can query it using getType. Be warned, that the call to wrong evaluateXX method will result in exception. Another tricky point is that JEL always selects smallest data type for constant representation. Namely, expression "1" has type byte and not int, thus in most cases you will have to query the type, and only then, call the proper evaluateXX method. It is anyway possible to eliminate type checks at evaluation time completely. There is a version of compile method in gnu.jel.Evaluator, which allows to fix the type of the result. It directs the compiler to perform the widening conversion to the given type, before returning the result. For example: if you fix the type to be int (passing java.lang.Integer.TYPE as an argument to compile) all expressions (such as "1", "2+5", "2*2") will be evaluated by evaluate_int method of the compiled expression. Also, the attempt to evaluate "1+2L" will be rejected by compiler, asking to insert the explicit narrowing conversion (such as "(int)(1+2L)"). Serialization of compiled expressions There used to be a specialized serialization interface in JEL up to version 0.8.3. The need for such interface was dictated by the fact that JEL allowed to use constants of arbitrary reference types in expressions, which is not supported directly by the Java class file format. Starting with version 0.9 this feature was removed and now JEL generates ordinary Java class files. To store compiled expressions into a file just grab their code with gnu.jel.Evaluator.compileBits. The code is returned as a byte array which is easy to save/restore. Then, the expression can be instantiated using gnu.jel.ImageLoader with the code byte[] image; // ... code to read the JEL-generated class file into the "image" ... CompiledExpression expression=(CompiledExpression)(ImageLoader.load(image)).newInstance(); or, alternatively, by compiling your source against generated class file. Note that in this version of JEL all generated classes have the name "dump" and are in the root package. If there will be such need in future the Evaluator interface can be extended to assign user-supplied names for new expressions. Limitations of JEL There is one serious limitation, which should be mentioned. Actually it is not a JEL limitation but rather a limitation of the typical Java run-time To load compiled expressions into the Java virtual machine memory JEL uses a custom java.lang.ClassLoader. While there is nothing wrong with that, setting up a classLoader is a privileged operation in Java. This means either JEL should run in a Java application (there are no security restrictions on Java applications), or , if JEL is distributed in some custom applet the applet should be signed. Summarizing remarks I hope you found JEL useful. Don't hesitate to contact me if there are any problems with JEL, please, report BUGS, suggest tests, send me your patches,... There are still many improvements to be done. Most current information about JEL should be available at http://www.fti.dn.ua/JEL/. JEL is the "free software" and is distributed to you under terms of GNU General Public License. Find the precise terms of the license in the file ./COPYING in the root of this distribution. Please, contact the author directly if you'd like JEL to be commercially licensed to you on a different terms. GNU Free Documentation License Version 1.3, 3 November 2008 Copyright © 2000, 2001, 2002, 2007, 2008 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. 0. PREAMBLE The purpose of this License is to make a manual, textbook, or other functional and useful document “free” in the sense of freedom: to assure everyone the effective freedom to copy and redistribute it, with or without modifying it, either commercially or noncommercially. Secondarily, this License preserves for the author and publisher a way to get credit for their work, while not being considered responsible for modifications made by others. This License is a kind of “copyleft”, which means that derivative works of the document must themselves be free in the same sense. It complements the GNU General Public License, which is a copyleft license designed for free software. We have designed this License in order to use it for manuals for free software, because free software needs free documentation: a free program should come with manuals providing the same freedoms that the software does. But this License is not limited to software manuals; it can be used for any textual work, regardless of subject matter or whether it is published as a printed book. We recommend this License principally for works whose purpose is instruction or reference. 1. APPLICABILITY AND DEFINITIONS This License applies to any manual or other work, in any medium, that contains a notice placed by the copyright holder saying it can be distributed under the terms of this License. Such a notice grants a world-wide, royalty-free license, unlimited in duration, to use that work under the conditions stated herein. The “Document”, below, refers to any such manual or work. Any member of the public is a licensee, and is addressed as “you”. You accept the license if you copy, modify or distribute the work in a way requiring permission under copyright law. A “Modified Version” of the Document means any work containing the Document or a portion of it, either copied verbatim, or with modifications and/or translated into another language. A “Secondary Section” is a named appendix or a front-matter section of the Document that deals exclusively with the relationship of the publishers or authors of the Document to the Document’s overall subject (or to related matters) and contains nothing that could fall directly within that overall subject. (Thus, if the Document is in part a textbook of mathematics, a Secondary Section may not explain any mathematics.) The relationship could be a matter of historical connection with the subject or with related matters, or of legal, commercial, philosophical, ethical or political position regarding them. The “Invariant Sections” are certain Secondary Sections whose titles are designated, as being those of Invariant Sections, in the notice that says that the Document is released under this License. If a section does not fit the above definition of Secondary then it is not allowed to be designated as Invariant. The Document may contain zero Invariant Sections. If the Document does not identify any Invariant Sections then there are none. The “Cover Texts” are certain short passages of text that are listed, as Front-Cover Texts or Back-Cover Texts, in the notice that says that the Document is released under this License. A Front-Cover Text may be at most 5 words, and a Back-Cover Text may be at most 25 words. A “Transparent” copy of the Document means a machine-readable copy, represented in a format whose specification is available to the general public, that is suitable for revising the document straightforwardly with generic text editors or (for images composed of pixels) generic paint programs or (for drawings) some widely available drawing editor, and that is suitable for input to text formatters or for automatic translation to a variety of formats suitable for input to text formatters. A copy made in an otherwise Transparent file format whose markup, or absence of markup, has been arranged to thwart or discourage subsequent modification by readers is not Transparent. An image format is not Transparent if used for any substantial amount of text. A copy that is not “Transparent” is called “Opaque”. Examples of suitable formats for Transparent copies include plain ASCII without markup, Texinfo input format, LaTeX input format, SGML or XML using a publicly available DTD, and standard-conforming simple HTML, PostScript or PDF designed for human modification. Examples of transparent image formats include PNG, XCF and JPG. Opaque formats include proprietary formats that can be read and edited only by proprietary word processors, SGML or XML for which the DTD and/or processing tools are not generally available, and the machine-generated HTML, PostScript or PDF produced by some word processors for output purposes only. The “Title Page” means, for a printed book, the title page itself, plus such following pages as are needed to hold, legibly, the material this License requires to appear in the title page. For works in formats which do not have any title page as such, “Title Page” means the text near the most prominent appearance of the work’s title, preceding the beginning of the body of the text. The “publisher” means any person or entity that distributes copies of the Document to the public. A section “Entitled XYZ” means a named subunit of the Document whose title either is precisely XYZ or contains XYZ in parentheses following text that translates XYZ in another language. (Here XYZ stands for a specific section name mentioned below, such as “Acknowledgements”, “Dedications”, “Endorsements”, or “History”.) To “Preserve the Title” of such a section when you modify the Document means that it remains a section “Entitled XYZ” according to this definition. The Document may include Warranty Disclaimers next to the notice which states that this License applies to the Document. These Warranty Disclaimers are considered to be included by reference in this License, but only as regards disclaiming warranties: any other implication that these Warranty Disclaimers may have is void and has no effect on the meaning of this License. 2. VERBATIM COPYING You may copy and distribute the Document in any medium, either commercially or noncommercially, provided that this License, the copyright notices, and the license notice saying this License applies to the Document are reproduced in all copies, and that you add no other conditions whatsoever to those of this License. You may not use technical measures to obstruct or control the reading or further copying of the copies you make or distribute. However, you may accept compensation in exchange for copies. If you distribute a large enough number of copies you must also follow the conditions in section 3. You may also lend copies, under the same conditions stated above, and you may publicly display copies. 3. COPYING IN QUANTITY If you publish printed copies (or copies in media that commonly have printed covers) of the Document, numbering more than 100, and the Document’s license notice requires Cover Texts, you must enclose the copies in covers that carry, clearly and legibly, all these Cover Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on the back cover. Both covers must also clearly and legibly identify you as the publisher of these copies. The front cover must present the full title with all words of the title equally prominent and visible. You may add other material on the covers in addition. Copying with changes limited to the covers, as long as they preserve the title of the Document and satisfy these conditions, can be treated as verbatim copying in other respects. If the required texts for either cover are too voluminous to fit legibly, you should put the first ones listed (as many as fit reasonably) on the actual cover, and continue the rest onto adjacent pages. If you publish or distribute Opaque copies of the Document numbering more than 100, you must either include a machine-readable Transparent copy along with each Opaque copy, or state in or with each Opaque copy a computer-network location from which the general network-using public has access to download using public-standard network protocols a complete Transparent copy of the Document, free of added material. If you use the latter option, you must take reasonably prudent steps, when you begin distribution of Opaque copies in quantity, to ensure that this Transparent copy will remain thus accessible at the stated location until at least one year after the last time you distribute an Opaque copy (directly or through your agents or retailers) of that edition to the public. It is requested, but not required, that you contact the authors of the Document well before redistributing any large number of copies, to give them a chance to provide you with an updated version of the Document. 4. MODIFICATIONS You may copy and distribute a Modified Version of the Document under the conditions of sections 2 and 3 above, provided that you release the Modified Version under precisely this License, with the Modified Version filling the role of the Document, thus licensing distribution and modification of the Modified Version to whoever possesses a copy of it. In addition, you must do these things in the Modified Version: Use in the Title Page (and on the covers, if any) a title distinct from that of the Document, and from those of previous versions (which should, if there were any, be listed in the History section of the Document). You may use the same title as a previous version if the original publisher of that version gives permission. List on the Title Page, as authors, one or more persons or entities responsible for authorship of the modifications in the Modified Version, together with at least five of the principal authors of the Document (all of its principal authors, if it has fewer than five), unless they release you from this requirement. State on the Title page the name of the publisher of the Modified Version, as the publisher. Preserve all the copyright notices of the Document. Add an appropriate copyright notice for your modifications adjacent to the other copyright notices. Include, immediately after the copyright notices, a license notice giving the public permission to use the Modified Version under the terms of this License, in the form shown in the Addendum below. Preserve in that license notice the full lists of Invariant Sections and required Cover Texts given in the Document’s license notice. Include an unaltered copy of this License. Preserve the section Entitled “History”, Preserve its Title, and add to it an item stating at least the title, year, new authors, and publisher of the Modified Version as given on the Title Page. If there is no section Entitled “History” in the Document, create one stating the title, year, authors, and publisher of the Document as given on its Title Page, then add an item describing the Modified Version as stated in the previous sentence. Preserve the network location, if any, given in the Document for public access to a Transparent copy of the Document, and likewise the network locations given in the Document for previous versions it was based on. These may be placed in the “History” section. You may omit a network location for a work that was published at least four years before the Document itself, or if the original publisher of the version it refers to gives permission. For any section Entitled “Acknowledgements” or “Dedications”, Preserve the Title of the section, and preserve in the section all the substance and tone of each of the contributor acknowledgements and/or dedications given therein. Preserve all the Invariant Sections of the Document, unaltered in their text and in their titles. Section numbers or the equivalent are not considered part of the section titles. Delete any section Entitled “Endorsements”. Such a section may not be included in the Modified Version. Do not retitle any existing section to be Entitled “Endorsements” or to conflict in title with any Invariant Section. Preserve any Warranty Disclaimers. If the Modified Version includes new front-matter sections or appendices that qualify as Secondary Sections and contain no material copied from the Document, you may at your option designate some or all of these sections as invariant. To do this, add their titles to the list of Invariant Sections in the Modified Version’s license notice. These titles must be distinct from any other section titles. You may add a section Entitled “Endorsements”, provided it contains nothing but endorsements of your Modified Version by various parties — for example, statements of peer review or that the text has been approved by an organization as the authoritative definition of a standard. You may add a passage of up to five words as a Front-Cover Text, and a passage of up to 25 words as a Back-Cover Text, to the end of the list of Cover Texts in the Modified Version. Only one passage of Front-Cover Text and one of Back-Cover Text may be added by (or through arrangements made by) any one entity. If the Document already includes a cover text for the same cover, previously added by you or by arrangement made by the same entity you are acting on behalf of, you may not add another; but you may replace the old one, on explicit permission from the previous publisher that added the old one. The author(s) and publisher(s) of the Document do not by this License give permission to use their names for publicity for or to assert or imply endorsement of any Modified Version. 5. COMBINING DOCUMENTS You may combine the Document with other documents released under this License, under the terms defined in section 4 above for modified versions, provided that you include in the combination all of the Invariant Sections of all of the original documents, unmodified, and list them all as Invariant Sections of your combined work in its license notice, and that you preserve all their Warranty Disclaimers. The combined work need only contain one copy of this License, and multiple identical Invariant Sections may be replaced with a single copy. If there are multiple Invariant Sections with the same name but different contents, make the title of each such section unique by adding at the end of it, in parentheses, the name of the original author or publisher of that section if known, or else a unique number. Make the same adjustment to the section titles in the list of Invariant Sections in the license notice of the combined work. In the combination, you must combine any sections Entitled “History” in the various original documents, forming one section Entitled “History”; likewise combine any sections Entitled “Acknowledgements”, and any sections Entitled “Dedications”. You must delete all sections Entitled “Endorsements”. 6. COLLECTIONS OF DOCUMENTS You may make a collection consisting of the Document and other documents released under this License, and replace the individual copies of this License in the various documents with a single copy that is included in the collection, provided that you follow the rules of this License for verbatim copying of each of the documents in all other respects. You may extract a single document from such a collection, and distribute it individually under this License, provided you insert a copy of this License into the extracted document, and follow this License in all other respects regarding verbatim copying of that document. 7. AGGREGATION WITH INDEPENDENT WORKS A compilation of the Document or its derivatives with other separate and independent documents or works, in or on a volume of a storage or distribution medium, is called an “aggregate” if the copyright resulting from the compilation is not used to limit the legal rights of the compilation’s users beyond what the individual works permit. When the Document is included in an aggregate, this License does not apply to the other works in the aggregate which are not themselves derivative works of the Document. If the Cover Text requirement of section 3 is applicable to these copies of the Document, then if the Document is less than one half of the entire aggregate, the Document’s Cover Texts may be placed on covers that bracket the Document within the aggregate, or the electronic equivalent of covers if the Document is in electronic form. Otherwise they must appear on printed covers that bracket the whole aggregate. 8. TRANSLATION Translation is considered a kind of modification, so you may distribute translations of the Document under the terms of section 4. Replacing Invariant Sections with translations requires special permission from their copyright holders, but you may include translations of some or all Invariant Sections in addition to the original versions of these Invariant Sections. You may include a translation of this License, and all the license notices in the Document, and any Warranty Disclaimers, provided that you also include the original English version of this License and the original versions of those notices and disclaimers. In case of a disagreement between the translation and the original version of this License or a notice or disclaimer, the original version will prevail. If a section in the Document is Entitled “Acknowledgements”, “Dedications”, or “History”, the requirement (section 4) to Preserve its Title (section 1) will typically require changing the actual title. 9. TERMINATION You may not copy, modify, sublicense, or distribute the Document except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, or distribute it is void, and will automatically terminate your rights under this License. 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, receipt of a copy of some or all of the same material does not give you any rights to use it. 10. FUTURE REVISIONS OF THIS LICENSE The Free Software Foundation may publish new, revised versions of the GNU Free Documentation 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. See Copyleft. Each version of the License is given a distinguishing version number. If the Document specifies that a particular numbered version of this License “or any later version” applies to it, you have the option of following the terms and conditions either of that specified version or of any later version that has been published (not as a draft) by the Free Software Foundation. If the Document does not specify a version number of this License, you may choose any version ever published (not as a draft) by the Free Software Foundation. If the Document specifies that a proxy can decide which future versions of this License can be used, that proxy’s public statement of acceptance of a version permanently authorizes you to choose that version for the Document. 11. RELICENSING “Massive Multiauthor Collaboration Site” (or “MMC Site”) means any World Wide Web server that publishes copyrightable works and also provides prominent facilities for anybody to edit those works. A public wiki that anybody can edit is an example of such a server. A “Massive Multiauthor Collaboration” (or “MMC”) contained in the site means any set of copyrightable works thus published on the MMC site. “CC-BY-SA” means the Creative Commons Attribution-Share Alike 3.0 license published by Creative Commons Corporation, a not-for-profit corporation with a principal place of business in San Francisco, California, as well as future copyleft versions of that license published by that same organization. “Incorporate” means to publish or republish a Document, in whole or in part, as part of another Document. An MMC is “eligible for relicensing” if it is licensed under this License, and if all works that were first published under this License somewhere other than this MMC, and subsequently incorporated in whole or in part into the MMC, (1) had no cover texts or invariant sections, and (2) were thus incorporated prior to November 1, 2008. The operator of an MMC Site may republish an MMC contained in the site under CC-BY-SA on the same site at any time before August 1, 2009, provided the MMC is eligible for relicensing. ADDENDUM: How to use this License for your documents To use this License in a document you have written, include a copy of the License in the document and put the following copyright and license notices just after the title page: Copyright © YEAR YOUR NAME Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled “GNU Free Documentation License”. If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts, replace the “with… Texts.” line with this: with the Invariant Sections being LIST THEIR TITLES, with the Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST. If you have Invariant Sections without Cover Texts, or some other combination of the three, merge those two alternatives to suit the situation. If your document contains nontrivial examples of program code, we recommend releasing these examples in parallel under your choice of free software license, such as the GNU General Public License, to permit their use in free software.
source/src/docs/README.testbed0000644000175000017500000000055112714113765015104 0ustar olesolesThis is a JEL test bed for Your pleasure. Feel free to modify it and play with other expressions. TO PLAY 1) set the CLASSPATH UNIX (bash):> export CLASSPATH=$CLASSPATH:/lib/jel.jar:. where is the directory where JEL is installed 2) compile :> javac YourTestBed 3) run :> java YourTestBed 4) modify, add more expressions 5) go to 2 source/src/docs/RELNOTES0000644000175000017500000000200412714113765013744 0ustar olesoles NEW FEATURES in version 2.1.1. 1. Better error messages for numerical literal overflow. Unlike the previous versions, which simply claimed that an unexpected character is encountered when numerical literals were too large to fit in various data types, this version returns a fully customizable error messages in a number of such cases. 2. Automatic boxing of the primitive types (and JEL reflection types). JEL now automatically wraps the primitive types into the corresponding Java reflection objects. Thus, it is now possible to call the function func(Integer i) via the expression "func(1)". Note that in this case two conversions are actually performed: 1) from byte to int (which is evaluated at compile time); 2) from int to java.lang.Integer (which takes place at run time). Still, it is advisable to use the primitive types in your expressions as much as possible for the best performance. 3. Minor spelling fixes. May 9 2016 Konstantin L. Metlov. source/src/docs/html/0000755000175000017500000000000012714113765013536 5ustar olesolessource/src/docs/html/manual.html0000644000175000017500000022751012714113765015710 0ustar olesoles Java Expressions Library

Java Expressions Library

Dr. Konstantin L. Metlov

Licensing

Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the Appendix.


Chapter 1. About this manual

This manual is mostly examples-based. It starts with two simple step-by-step examples (showing how to deal with static and dynamic libraries), which should give enough information for basic JEL usage (but don't forget to read the rest of this manual to learn how to get the top performance from JEL). Additional information can be found in API documentation.

Chapter 2. JEL design goals

The main design goal was to create light weight expression compiler generating extremely fast code. The main emphasis is the code execution time and not the compilation time (it is nevertheless small). The other goal was to make JEL language to be very close to Java language with direct access to all built-in Java data types and functions.

Chapter 3. Features

  • Support for all Java data types (boolean, byte, char, short, long, int, float, double, arrays, references)

  • Octal (0456) and hexadecimal (0x1FFF) literals.

  • Support for all Java arithmetic operators: + (add),- (subtract), * (multiply), / (divide), % (remainder), & (bitwise and),| (bitwise or), ^ (bitwise xor),~ (bitwise complement), << (left shift), >> (right signed shift), >>> (right unsigned shift); on most of supported data types according to Java Language Specification (JLS)

  • Comparison operators (==,!=,<,>=,>,<=) as defined by Java Language Specification (JLS).

  • dot (".") operator on objects ("abc".length()==3).

  • dot (".") operator on objects ("abc".length()==3).

  • Boolean logical operators (&&,||,!) with lazy evaluation (i.e. in the expression false&&complexBooleanFunction() the function is never called).

  • Conditionals (true?2:3 = 2)

  • Direct access to methods and fields of Java objects.

  • Method overloading according to Java Language Specification.

  • Support for methods with variable number of arguments (varargs), which is enabled for all methods, accepting array as their last argument.

  • Dynamic variables interface allowing to add variables to JEL namespace without supplying the class file defining them.

  • Automatic unwrapping of designated objects to Java primitive types.

  • Support for strings. Objects of class java.lang.String can be directly entered into expressions using double quotes, also the standard Java escape codes are parsed. Example : "a string\n\015".

  • String concatenation ("a"+2+(2>3)+object = "a2false"+object.toString()).

  • User definable string comparison using usual relational operators "<", "<=", ">", ">=", "==", "!=", which uses locale by default.

  • User-controllable object down-casting using "(class.name)var" syntax. It is possible to assign names to classes in JEL expressions to be different from their real Java class names.

  • Constants folding, extended (by default, but can be controlled) to static methods (which are automatically called at compile time) and static fields (which are considered constants).

  • High performance of generated code.

Chapter 4. How to use JEL.

In this section a simple example of a program using JEL is given, and explained with references to more detailed sections of this manual. The example program evaluates the expression given on its command line (similar program exists in the distribution under the name ./samples/Calculator.java), let's follow it step by step.

    public static void main(String[] args) {
    
    // Assemble the expression
    StringBuffer expr_sb=new StringBuffer();
    for(int i=0;i<args.length;i++) {
      expr_sb.append(args[i]);
      expr_sb.append(' ');
      };
    String expr=expr_sb.toString();
  

This first part of the program is not related to JEL. It's purpose is to assemble the expression, possibly, containing spaces into the single line. This has to be done, because shells tend to tokenize parameters but we don't need it here.

    // Set up the library
    Class[] staticLib=new Class[1];
    try {
      staticLib[0]=Class.forName("java.lang.Math");
    } catch(ClassNotFoundException e) {
      // Can't be ;)) ...... in java ... ;)
    };
    Library lib=new Library(staticLib,null,null,null,null);
    try {
    lib.markStateDependent("random",null);
    } catch (NoSuchMethodException e) {
      // Can't be also
    };
  

This piece of code establishes the namespace for use in JEL compiled expressions. The gnu.jel.Library object maintains this namespace.

There can be two types of names in the Library : static and virtual (dynamic).

Methods and variables of the first class are assumed (by default) to be dependent only on their arguments i.e. not to save any information from call to call (they are "stateless")... Examples are mathematical functions like sin, cos, log, constants E, PI in java.lang.Math. For such methods (fields) it does not matter how many times (when) they will be called (their value will be taken) the result will always be the same provided arguments (if they are present) are the same. Stateless methods will be evaluated by JEL at compile time if their arguments are constants (known at compile time). To define set of static functions(fields) it is needed to pass the array of Class objects, defining those functions, as the first parameter of the library constructor (see example above). Note ONLY STATIC functions of the Classes, passed in the first argument of the gnu.jel.Library constructor will be defined in the namespace. By default all static functions are considered "stateless" by JEL.

However, some static functions still save their state (in static variables) in between calls. Thus they return different results, depending on when (how many times) they are is called even if their arguments are the same. If such function is evaluated at compile time, we have troubles, because it will be evaluated only once during expression lifetime and it's state dependence will be lost. Typical example of the static function, having a state is java.lang.Math.random. JEL has special mechanism, provided by gnu.jel.Library class to mark static functions as state dependent. (see the above example to find out how it was done for the java.lang.Math.random)

The virtual functions, which are explicitly state dependent, will be discussed later in this document. The example we currently consider does not use them. However, virtual functions are, actually, most important to JEL because expression, containing all stateless functions, is a constant, it will be completely evaluated at compile time, there is absolutely no sense to evaluate such expression repeatedly (this is what JEL was designed for). Still we shall continue with this simple example as the following code is mostly independent of whether we use virtual functions or not...

    // Compile
    CompiledExpression expr_c=null;
    try {
      expr_c=Evaluator.compile(expr,lib);
    } catch (CompilationException ce) {
      System.err.print("–––COMPILATION ERROR :");
      System.err.println(ce.getMessage());
      System.err.print("                       ");
      System.err.println(expr);
      int column=ce.getColumn(); // Column, where error was found
      for(int i=0;i<column+23-1;i++) System.err.print(' ');
      System.err.println('^');
    };

This chunk of code is for the expression compilation. The crucial line is the call to Evaluator.compile, it is the point, where expression gets transformed into Java bytecode, loaded into the Java Virtual Machine using JEL ClassLoader and returned to caller as an instance of the subclass of gnu.jel.CompiledExpression. Typical user of JEL is not required to know what magic is going on inside of Evaluator.compile(...). Other code in this chunk is for the error reporting and will be discussed in the specialized section Error detection and reporting below.

      if (expr_c !=null) {
      
      // Evaluate (Can do it now any number of times FAST !!!)
      Number result=null;
      try {
	result=(Number)expr_c.evaluate(null);
      } catch (Throwable e) {
	System.err.println("Exception emerged from JEL compiled"+
			   " code (IT'S OK) :");
	System.err.print(e);
      };
  

This code does the evaluation of the expression. It is done by calling the evaluate method of the JEL compiled class, it is defined abstract in gnu.jel.CompiledExpression but is redefined in the class compiled by JEL. The argument of this method is discussed in the section on virtual functions below. If only static functions are present in the library it is safe to pass the null pointer as the argument to evaluate.

Result of the evaluate method is always an object. JEL converts primitive numeric types into instances of corresponding Java reflection classes (read the section Making things faster to find out how to avoid this conversion). For example, a value of primitive type long will be returned as an instance of java.lang.Long class (int maps to java.lang.Integer, float to java.lang.Float, etc.). If result is an arbitrary Java object it is returned as the reference to that object.

The

try ... catch

clause around the call to evaluate will be enforced by the Java compiler. It is required as errors can appear during evaluation. The general rule is: syntax, types incompatibility and function resolution errors will be reported at compile time (as thrown instance of gnu.jel.CompilationException), while the errors in the values of numbers will be reported at the execution time. For example expression "1/0" will generate no error at compile time (nevertheless it is the constant expression and its evaluation is attempted), but at the time of calling execute you will get a java.lang.ArithmeticError (division by zero) as it should be.

      // Print result
      if (result==null) 
	System.out.println("void");
      else
	System.out.println(result.toString());
   };
};

This last piece of code will print the result. And is concluding our brief tour of the JEL usage.

Chapter 5. Using libraries

The namespace of JEL expressions is represented by gnu.jel.Library class. Its constructor:

Library(Class[] staticLib, Class[] dynamicLib,
Class[] dotClasses, DVMap  resolver,
Hashtable cnmap)

has five arguments. Their purposes are following:

staticLib

enumerates classes whose static methods are exported to JEL namespace and become usable from within expressions. Such methods do not require this pointer supplied to them at execution time. More details

dynamicLib

enumerates classes whose virtual methods are exported. These methods require the references to the corresponding classes (this pointers) supplied to the expression at run-time. This is done using the Class[]> argument of CompiledExpression's evaluate method. More details

dotClasses

controls access for the dot (".") operator on classes. More details

resolver

Dynamic variables interface. Allows to add new variables to the expressions names without supplying the class files defining them. More details

cnmap

Maps the class names usable inside JEL expressions for non-primitive type casts into the Java classes More details

The details on usage of each of these arguments are given in a separate sections below.

The working example using all current functionality of JEL namespace is given in the examples/YourTestBed directory in the distribution. You'll want to check it after reading this section.

Exporting static methods of classes to JEL namespace.

The array of references to classes (java.lang.Class) whose public static methods and fields are to be exported should be passed as the first argument of the library constructor (staticLib). The public static fields and methods of all these classes are merged together into the JEL namespace. The non-public or non-static members of staticLib classes are ignored.

Methods overloading is supported and works also across classes (because the JEL namespace works similarly to the namespace defined in a single Java class). For example, if a class C1 contains the method public static C1.func(int) and a class C2 contains the method public static C2.func(double) and both these classes are passed as elements of the staticLib array. Then, the JEL expression "func(1)" calls C1.func(int) and the expression "func(1.0)" calls C2.func(double). It also means that methods and fields of all classes supplied to the Library are subject to the same constraints as members of a single Java class.

Moreover, because JEL allows to call methods with no arguments omitting the empty brackets (that is "func()" and "func" are equivalent) there should be no fields and methods with no arguments having the same names in all classes presented to the Library constructor.

To check whether the set of classes you gave to the library constructor satisfies all required constraints run your program against the debug version of JEL library (jel_g.jar). Then, potential problems will be reported to you on the standard output.

Exporting virtual methods of classes to JEL namespace.

The second argument of the library constructor (dynamicLib) works similarly to the first one. Except that only public virtual members are taken from the listed classes. These members are merged into the namespace created from classes from the staticLib. The rules for methods overloading are the same as for classes listed in the first argument of library constructor. Also, the overloading is working across the classes listed in both first and second arguments of the Library constructor.

The crucial difference in the handling of classes listed in the dynamicLib and the staticLib comes from the fact that virtual members of dynamicLib require this reference to the instance of the object of their defining class be supplied at run-time. Thus, if C1 contains the virtual method public func(double x) its invocation actually requires two arguments, one is x and the other is the reference to the instance of class C1.

References to the instances of classes of the dynamicLib array are supplied at the execution time to the argument of the evaluate(Object[] context) method of gnu.jel.CompiledExpression. The elements of the context array should be instances of classes listed in dynamicLib array at compile time and there should be one-to-one correspondence between them. For example, if

dynamicLib[0]=com.mycompany.MyClass.class)

, the corresponding entry in the context array, context[0], must be a reference to the instance of com.mycompany.MyClass.

Formally, for every i, it should be possible to cast the object in the context[i] into the class, supplied in the dynamicLib[i] array of the Library constructor, otherwise ClassCastException will be thrown from evaluate.

Let's walk through the example, which calculates function of the single variable many times and uses virtual method calls. This example will consist of two classes : a user written class (providing access to the variable) and the main class compiling and evaluating expressions. First start with the variable provider:

public class VariableProvider {
  public double xvar;
  
  public double x() {return xvar;};
};

This class is trivial, it just defines the function, returning the value of the variable x.

In the main class (see the first JEL example for headers) the code, constructing the library will be replaced with:

    // Set up library
    Class[] staticLib=new Class[1];
    try {
      staticLib[0]=Class.forName("java.lang.Math");
    } catch(ClassNotFoundException e) {
      // Can't be ;)) ...... in java ... ;)
    };

    Class[] dynamicLib=new Class[1];
    VariableProvider variables=new VariableProvider();
    Object[] context=new Object[1];
    context[0]=variables;
    dynamicLib[0]=variables.getClass();
    
    Library lib=new Library(staticLib,dynamicLib,null,null,null);
    try {
    lib.markStateDependent("random",null);
    } catch (NoSuchMethodException e) {
      // Can't be also
    };

Absent in the static example, the additional code creates the VariableProvider and assigns its reference to an element of context array (to be passed to the evaluate method of the compiled expression). Also, now the dynamicLib array as not null and contains the reference to the VariableProvider class.

The code for compilation is exactly the same as in the example for static functions, except we have additional function x and the variable xvar defined for use inside the compiled expressions. JEL has the special notation for the functions, having no arguments, namely, brackets in "x()" can be omitted to be "x". This allows to compile now ( with the above defined library) the expressions like "sin(x)", "exp(x*x)", "pow(sin(x),2)+pow(cos(x),2)"...

The code for evaluation of an expression having virtual functions is replaced with:

      if (expr_c !=null) {
    
        try {
           for(int i=0;i<100;i++) {
              variables.xvar=i;      // <- Value of the variable
              System.out.println(expr_c.evaluate(context));
                               //^^^^^^^^^^^^^^^ evaluating 100 times
           };
        } catch (Throwable e) {
	   System.err.println("Exception emerged from JEL compiled"+
		              " code (IT'S OK) :");
           System.err.print(e);
        };
    };

Note the two major differences: 1. we have explicitly assigned the value to the variable; 2. the array of object references (consisting of one element in this example) is passed to the evaluate method. This piece of code will evaluate expressions for x=0..99 with step 1.

This concludes our dynamic library example. Try to modify the ./Calculator.java sample yourself to allow compilation of virtual functions as described above.

Variable number of arguments support.

Since the version 2.0.3 JEL supports calling methods with variable number of arguments. Moreover, because the information about the variable arguments declaration is not available via Java reflection, this support extends to all methods, having the array last argument. For example, if two following functions are declared in the library classes (static or dynamic)

       public int sum (int[] args);
       public double powersum(double power, double[] args);

it is possible to use them in the expressions as "sum(1)", "sum(1,2)", "powersum(2,1,2,3)", etc... The argument array will be created automatically by the compiler in these cases. The methods with variable number of arguments are subject to the same method overloading rules, automatic argument type conversions and constants folding as other methods.

Enabling the dot operator on objects.

The third argument of gnu.jel.Library constructor enumerates classes which are available for dot operator within the expression. If this parameter is null JEL would not allow to use the dot operator at all. If it is an array of the length zero (e.g. new Class[0]) JEL will open access to public methods of ALL objects encountered in the expression. From the security point of view allowing access to all objects can be dangerous, that is why there is a third case of non-zero length array explicitly enumerating classes allowing the dot operator on them.

Once the dot operator is allowed on a class, it is possible to call all its public methods using the syntax ".method(arg1,arg2,...)" in any context where this class appears in an expression.

Dynamic variables interface.

All methods of exporting names into JEL namespace described up to this point relied on the Java class files for actual description of methods names and parameters. However, sometimes it is required to add a new variable to JEL namespace at run-time.

One of the solutions would be to generate a new class file (e.g. using JEL) and supply it as a first or second argument of the library constructor. Unfortunately this can be quite cumbersome and time consuming.

The other solution can be to define a family of methods in JEL namespace

YYY getXXXProperty(String name)

for each possible variable types, where YYY is the class representing the property type and XXX is the name of the type. Then, supposing we have methods

  double getDoubleProperty(String name); // YYY=double XXX=Double
  String getStringProperty(String name); // YYY=java.lang.String XXX=String

in the JEL namespace (either static or dynamic), the variables with arbitrary names can be entered into expression using the syntax

getStringProperty("x") +
  (getDoubleProperty("y")+1.0)

This way has two drawbacks: 1) user has to remember the type of the variable (to call the appropriate getXXX() method); 2) a lot to type.

Since the version 0.9.3 JEL provides the way to solve both these problems. To do that the fourth argument (resolver) of the library constructor is used. This argument supplies the reference to the subclass of gnu.jel.DVMap, and is used by JEL to resolve the dynamic variable names. The gnu.jel.DVMap has an abstract method

public String getTypeName(String  name)

which returns XXX (see above) for a given variable name, or null if no such variable is defined. Note that for resolver to work the family of methods

YYY getXXXProperty(String name)

must still be present in JEL namespace (e.g. as members of one of dynamicLib[] classes).

Then, supposing

resolver.getTypeName("x")=="String" &&
resolver.getTypeName("y")=="Double"

the expression "x+(y+1.0)" will be automatically converted by JEL into

getStringProperty("x")+(getDoubleProperty("y")+1.0)

and compiled. Thus, user does not have to remember the variable types, typing is reduced and the existence of variables can be checked at the compile time.

JEL also supports a hierarchical structure of variables. This means the dot (".") symbol can be present in the dynamic variable names. For example if

resolver.getTypeName("x")!=null && 
resolver.getTypeName("x.f1")=="String" && 
resolver.getTypeName("x.f2")=="Double"

the expression "x.f1+(x.f2+1.0)" will be compiled by JEL as

getStringProperty("x.f1")+(getDoubleProperty("x.f2")+1.0)

and (combined with dot operator) the expression "x.f1.length()" will result in the length of the string getString("x1.f1").

Notice in the last example that if one wants to have defined the dynamic variable "x.y" the variable "x" must also be the dynamic variable (resolver.getTypeName("x")!=null).

If there is conflict between the dynamic variable name and other name in JEL namespace the dynamic variable has a priority.

Since JEL 0.9.9 it is possible to translate the names of dynamic variables from strings into the constants of Java primitive types. This is done using non-identity DVMap.translate method. The translation helps to improve performance in some cases.

Consider the following example. Suppose the underlying storage for dynamic variables is an array (or Vector), so that the value of the variable can be obtained by an integer index into that array (like numbered columns in a spreadsheet). Next, assume you still want to refer to the variables by names (e.g. you allowed user to assign names to the columns). Now, if the first column is named "x" and is of Double type, an expression "x", using dynamic variables interface with identity translation will be compiled into getDoubleProperty("x"). It means the translation of the string "x" into the column number 1 will have to be performed at run-time each time the expression is evaluated. Considering that Java strings are immutable, this may incur a substantial performance penalty.

The performance can be improved if the translate method of DVMap is overridden by the following:

public Object translate(String name) {
   if (name.equals("x")) return new Integer(1);
   return name;
   };

This is already a non-identity translation. With such DVMap the expression "x" will be compiled by JEL into getDoubleProperty(1), note that it is getDoubleProperty(int) method, which is called. This way the mapping of the variable name into the variable index is performed at compile-time, while at run-time the index is readily available. By defining the appropriate translations the dynamic variable lookup can be split in a user-controlled way between the expression compilation and execution stages to achieve the best performance.

The translate method is allowed to return only instances of Java reflection classes wrapping the primitive types (java.lang.Integer, java.lang.Double, etc), or strings (otherwise an exception will emerge at compile-time). This is because only these types of objects can be stored in the Java class files directly. Also, it is responsibility of the caller to ensure that JEL namespace contains getXXXProperty methods with all the necessary argument types, corresponding to the translations defined in DVMap. For identity translations only getXXXProperty methods accepting strings are necessary.

Objects down-casting.

The cnmap argument of gnu.jel.Library constructor, allows to enable the non-primitive type casts in JEL compiled expressions. If cnmap!=null it must be java.util.Hashtable with java.lang.Class objects as elements and java.lang.String objects as keys. When the object cast "(non_primitive_type_name) var" is encountered in the expression, "the non_primitive_type_name" string is looked in the cnmap hashtable and the cast to the corresponding class is generated by JEL. The absence of the name in the hashtable produces the compile-time error. It is possible for keys in cnmap to contain "." (dot) symbols in them.

Chapter 6. Automatic unwrapping of objects to primitive types.

This problem appears mostly when one uses dynamic variables, but may also arise in other cases. Suppose a reference to the object of the class Weight (representing a weight of a certain item) appeared in the expression. It is clear that Weight is always represented by a floating point number (although it may have other properties, like units). If the class Weight has the method

public double getValue()

the value of weight can be accessed in expressions using syntax w.getValue(), supposing the variable w has type Weight.

To save typing (since version 0.9.3 of JEL) one may have the class Weight implement gnu.jel.reflect.Double interface. Then, the aforementioned getValue method will be called automatically by JEL (or object w will be "unwrapped" to primitive type). This unwrapping will be performed automatically when needed: one can have expressions "w+1.0" meaning "w.getValue()+1" and "w.getUnits()" both valid (in the second case w is not "unwrapped").

There are gnu.jel.reflect.* interfaces for all Java primitive types. To use the automatic unwrapping one just needs to make his classes to implement one of these interfaces.

There is a similar mechanism for strings (since version 0.9.6) and a corresponding empty interface gnu.jel.reflect.String to denote objects automatically convertible to java.lang.String by means of their .toString() method. For example, if x is of a class implementing gnu.jel.reflect.String interface the expression x+"a" will be compiled into x.toString()+"a" (otherwise this expression produces a error message). The objects automatically convertible to strings can also be supplied as arguments of methods requiring java.lang.String (usual method overloading rules apply). Still, in the current version of JEL it is impossible to cast methods of java.lang.String on such objects. That is x.substring(1) is a syntax error (unless x itself has the .substring(int) method). This deficiency can be addressed in future.

Chapter 7. Error detection and reporting

Expressions are made by human, and making errors is the natural property of humans, consequently, JEL has to be aware of that.

There are two places, where errors can appear. First are the compilation errors, which are thrown in the form of gnu.jel.CompilationException by the gnu.jel.Evaluator.compile. These errors signal about syntax problems in the entered expressions, wrong function names, illegal types combinations, but NOT about illegal values of arguments of functions. The second source of errors is the compiled code itself, Throwables, thrown out of gnu.jel.CompiledExpression.evaluate are primarily due to the invalid values of function arguments.

Compilation errors are easy to process. Normally, you should surround compilation by the

   try {
      // ... compilation
   catch (CompilationException e) {
      // ... process and report the error
   }

block. Caught gnu.jel.CompilationException can be interrogated, then, on the subject of WHERE error has occurred (getCol) and WHAT was the error (getMessage). This information should then be presented to user. It is wise to use information about error column to position the cursor automatically to the erroneous place in the expression.

Errors of the second type are appearing during the function evaluation and can not be so nicely dealt with by JEL. They depend on the actual library, supplied to the compiler. For example methods of java.lang.Math do not generate any checked exceptions at all (still, Errors are possible), but you may connect library, of functions throwing exceptions. As a general rule : exceptions thrown by functions from the library are thrown from evaluate method

Chapter 8. Making things faster

In the above text the result of the computation, returned by evaluate was always an object. While this is very flexible it is not very fast. Objects have to be allocated on heap and garbage collected. When the result of computation is a value of one of Java primitive types it can be desirable to retrieve it without creation of the object. This can be done (since the version 0.2 of JEL) with evaluateXX() family of calls (see gnu.jel.CompiledExpression. There is an evaluateXX() method for each Java primitive type, if you know what type expression has you can just call the corresponding method.

If you do not know the type of the compiled expression you can query it using getType. Be warned, that the call to wrong evaluateXX method will result in exception. Another tricky point is that JEL always selects smallest data type for constant representation. Namely, expression "1" has type byte and not int, thus in most cases you will have to query the type, and only then, call the proper evaluateXX method.

It is anyway possible to eliminate type checks at evaluation time completely. There is a version of compile method in gnu.jel.Evaluator, which allows to fix the type of the result. It directs the compiler to perform the widening conversion to the given type, before returning the result. For example: if you fix the type to be int (passing java.lang.Integer.TYPE as an argument to compile) all expressions (such as "1", "2+5", "2*2") will be evaluated by evaluate_int method of the compiled expression. Also, the attempt to evaluate "1+2L" will be rejected by compiler, asking to insert the explicit narrowing conversion (such as "(int)(1+2L)").

Chapter 9. Serialization of compiled expressions

There used to be a specialized serialization interface in JEL up to version 0.8.3. The need for such interface was dictated by the fact that JEL allowed to use constants of arbitrary reference types in expressions, which is not supported directly by the Java class file format. Starting with version 0.9 this feature was removed and now JEL generates ordinary Java class files.

To store compiled expressions into a file just grab their code with gnu.jel.Evaluator.compileBits. The code is returned as a byte array which is easy to save/restore. Then, the expression can be instantiated using gnu.jel.ImageLoader with the code

byte[] image; 
// ... code to read the JEL-generated class file into the "image" ...
CompiledExpression expression=(CompiledExpression)(ImageLoader.load(image)).newInstance();

or, alternatively, by compiling your source against generated class file. Note that in this version of JEL all generated classes have the name "dump" and are in the root package. If there will be such need in future the Evaluator interface can be extended to assign user-supplied names for new expressions.

Chapter 10. Limitations of JEL

There is one serious limitation, which should be mentioned. Actually it is not a JEL limitation but rather a limitation of the typical Java run-time

To load compiled expressions into the Java virtual machine memory JEL uses a custom java.lang.ClassLoader. While there is nothing wrong with that, setting up a classLoader is a privileged operation in Java. This means either JEL should run in a Java application (there are no security restrictions on Java applications), or , if JEL is distributed in some custom applet the applet should be signed.

Chapter 11. Summarizing remarks

I hope you found JEL useful. Don't hesitate to contact me if there are any problems with JEL, please, report BUGS, suggest tests, send me your patches,... There are still many improvements to be done.

Most current information about JEL should be available at http://www.fti.dn.ua/JEL/.

JEL is the "free software" and is distributed to you under terms of GNU General Public License. Find the precise terms of the license in the file ./COPYING in the root of this distribution.

Please, contact the author directly if you'd like JEL to be commercially licensed to you on a different terms.

Appendix A. GNU Free Documentation License

Version 1.3, 3 November 2008

Copyright © 2000, 2001, 2002, 2007, 2008 Free Software Foundation, Inc.

Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.

0. PREAMBLE

The purpose of this License is to make a manual, textbook, or other functional and useful document “free” in the sense of freedom: to assure everyone the effective freedom to copy and redistribute it, with or without modifying it, either commercially or noncommercially. Secondarily, this License preserves for the author and publisher a way to get credit for their work, while not being considered responsible for modifications made by others.

This License is a kind of “copyleft”, which means that derivative works of the document must themselves be free in the same sense. It complements the GNU General Public License, which is a copyleft license designed for free software.

We have designed this License in order to use it for manuals for free software, because free software needs free documentation: a free program should come with manuals providing the same freedoms that the software does. But this License is not limited to software manuals; it can be used for any textual work, regardless of subject matter or whether it is published as a printed book. We recommend this License principally for works whose purpose is instruction or reference.

1. APPLICABILITY AND DEFINITIONS

This License applies to any manual or other work, in any medium, that contains a notice placed by the copyright holder saying it can be distributed under the terms of this License. Such a notice grants a world-wide, royalty-free license, unlimited in duration, to use that work under the conditions stated herein. The “Document”, below, refers to any such manual or work. Any member of the public is a licensee, and is addressed as “you”. You accept the license if you copy, modify or distribute the work in a way requiring permission under copyright law.

A “Modified Version” of the Document means any work containing the Document or a portion of it, either copied verbatim, or with modifications and/or translated into another language.

A “Secondary Section” is a named appendix or a front-matter section of the Document that deals exclusively with the relationship of the publishers or authors of the Document to the Document’s overall subject (or to related matters) and contains nothing that could fall directly within that overall subject. (Thus, if the Document is in part a textbook of mathematics, a Secondary Section may not explain any mathematics.) The relationship could be a matter of historical connection with the subject or with related matters, or of legal, commercial, philosophical, ethical or political position regarding them.

The “Invariant Sections” are certain Secondary Sections whose titles are designated, as being those of Invariant Sections, in the notice that says that the Document is released under this License. If a section does not fit the above definition of Secondary then it is not allowed to be designated as Invariant. The Document may contain zero Invariant Sections. If the Document does not identify any Invariant Sections then there are none.

The “Cover Texts” are certain short passages of text that are listed, as Front-Cover Texts or Back-Cover Texts, in the notice that says that the Document is released under this License. A Front-Cover Text may be at most 5 words, and a Back-Cover Text may be at most 25 words.

A “Transparent” copy of the Document means a machine-readable copy, represented in a format whose specification is available to the general public, that is suitable for revising the document straightforwardly with generic text editors or (for images composed of pixels) generic paint programs or (for drawings) some widely available drawing editor, and that is suitable for input to text formatters or for automatic translation to a variety of formats suitable for input to text formatters. A copy made in an otherwise Transparent file format whose markup, or absence of markup, has been arranged to thwart or discourage subsequent modification by readers is not Transparent. An image format is not Transparent if used for any substantial amount of text. A copy that is not “Transparent” is called “Opaque”.

Examples of suitable formats for Transparent copies include plain ASCII without markup, Texinfo input format, LaTeX input format, SGML or XML using a publicly available DTD, and standard-conforming simple HTML, PostScript or PDF designed for human modification. Examples of transparent image formats include PNG, XCF and JPG. Opaque formats include proprietary formats that can be read and edited only by proprietary word processors, SGML or XML for which the DTD and/or processing tools are not generally available, and the machine-generated HTML, PostScript or PDF produced by some word processors for output purposes only.

The “Title Page” means, for a printed book, the title page itself, plus such following pages as are needed to hold, legibly, the material this License requires to appear in the title page. For works in formats which do not have any title page as such, “Title Page” means the text near the most prominent appearance of the work’s title, preceding the beginning of the body of the text.

The “publisher” means any person or entity that distributes copies of the Document to the public.

A section “Entitled XYZ” means a named subunit of the Document whose title either is precisely XYZ or contains XYZ in parentheses following text that translates XYZ in another language. (Here XYZ stands for a specific section name mentioned below, such as “Acknowledgements”, “Dedications”, “Endorsements”, or “History”.) To “Preserve the Title” of such a section when you modify the Document means that it remains a section “Entitled XYZ” according to this definition.

The Document may include Warranty Disclaimers next to the notice which states that this License applies to the Document. These Warranty Disclaimers are considered to be included by reference in this License, but only as regards disclaiming warranties: any other implication that these Warranty Disclaimers may have is void and has no effect on the meaning of this License.

2. VERBATIM COPYING

You may copy and distribute the Document in any medium, either commercially or noncommercially, provided that this License, the copyright notices, and the license notice saying this License applies to the Document are reproduced in all copies, and that you add no other conditions whatsoever to those of this License. You may not use technical measures to obstruct or control the reading or further copying of the copies you make or distribute. However, you may accept compensation in exchange for copies. If you distribute a large enough number of copies you must also follow the conditions in section 3.

You may also lend copies, under the same conditions stated above, and you may publicly display copies.

3. COPYING IN QUANTITY

If you publish printed copies (or copies in media that commonly have printed covers) of the Document, numbering more than 100, and the Document’s license notice requires Cover Texts, you must enclose the copies in covers that carry, clearly and legibly, all these Cover Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on the back cover. Both covers must also clearly and legibly identify you as the publisher of these copies. The front cover must present the full title with all words of the title equally prominent and visible. You may add other material on the covers in addition. Copying with changes limited to the covers, as long as they preserve the title of the Document and satisfy these conditions, can be treated as verbatim copying in other respects.

If the required texts for either cover are too voluminous to fit legibly, you should put the first ones listed (as many as fit reasonably) on the actual cover, and continue the rest onto adjacent pages.

If you publish or distribute Opaque copies of the Document numbering more than 100, you must either include a machine-readable Transparent copy along with each Opaque copy, or state in or with each Opaque copy a computer-network location from which the general network-using public has access to download using public-standard network protocols a complete Transparent copy of the Document, free of added material. If you use the latter option, you must take reasonably prudent steps, when you begin distribution of Opaque copies in quantity, to ensure that this Transparent copy will remain thus accessible at the stated location until at least one year after the last time you distribute an Opaque copy (directly or through your agents or retailers) of that edition to the public.

It is requested, but not required, that you contact the authors of the Document well before redistributing any large number of copies, to give them a chance to provide you with an updated version of the Document.

4. MODIFICATIONS

You may copy and distribute a Modified Version of the Document under the conditions of sections 2 and 3 above, provided that you release the Modified Version under precisely this License, with the Modified Version filling the role of the Document, thus licensing distribution and modification of the Modified Version to whoever possesses a copy of it. In addition, you must do these things in the Modified Version:

  1. Use in the Title Page (and on the covers, if any) a title distinct from that of the Document, and from those of previous versions (which should, if there were any, be listed in the History section of the Document). You may use the same title as a previous version if the original publisher of that version gives permission.
  2. List on the Title Page, as authors, one or more persons or entities responsible for authorship of the modifications in the Modified Version, together with at least five of the principal authors of the Document (all of its principal authors, if it has fewer than five), unless they release you from this requirement.
  3. State on the Title page the name of the publisher of the Modified Version, as the publisher.
  4. Preserve all the copyright notices of the Document.
  5. Add an appropriate copyright notice for your modifications adjacent to the other copyright notices.
  6. Include, immediately after the copyright notices, a license notice giving the public permission to use the Modified Version under the terms of this License, in the form shown in the Addendum below.
  7. Preserve in that license notice the full lists of Invariant Sections and required Cover Texts given in the Document’s license notice.
  8. Include an unaltered copy of this License.
  9. Preserve the section Entitled “History”, Preserve its Title, and add to it an item stating at least the title, year, new authors, and publisher of the Modified Version as given on the Title Page. If there is no section Entitled “History” in the Document, create one stating the title, year, authors, and publisher of the Document as given on its Title Page, then add an item describing the Modified Version as stated in the previous sentence.
  10. Preserve the network location, if any, given in the Document for public access to a Transparent copy of the Document, and likewise the network locations given in the Document for previous versions it was based on. These may be placed in the “History” section. You may omit a network location for a work that was published at least four years before the Document itself, or if the original publisher of the version it refers to gives permission.
  11. For any section Entitled “Acknowledgements” or “Dedications”, Preserve the Title of the section, and preserve in the section all the substance and tone of each of the contributor acknowledgements and/or dedications given therein.
  12. Preserve all the Invariant Sections of the Document, unaltered in their text and in their titles. Section numbers or the equivalent are not considered part of the section titles.
  13. Delete any section Entitled “Endorsements”. Such a section may not be included in the Modified Version.
  14. Do not retitle any existing section to be Entitled “Endorsements” or to conflict in title with any Invariant Section.
  15. Preserve any Warranty Disclaimers.

If the Modified Version includes new front-matter sections or appendices that qualify as Secondary Sections and contain no material copied from the Document, you may at your option designate some or all of these sections as invariant. To do this, add their titles to the list of Invariant Sections in the Modified Version’s license notice. These titles must be distinct from any other section titles.

You may add a section Entitled “Endorsements”, provided it contains nothing but endorsements of your Modified Version by various parties — for example, statements of peer review or that the text has been approved by an organization as the authoritative definition of a standard.

You may add a passage of up to five words as a Front-Cover Text, and a passage of up to 25 words as a Back-Cover Text, to the end of the list of Cover Texts in the Modified Version. Only one passage of Front-Cover Text and one of Back-Cover Text may be added by (or through arrangements made by) any one entity. If the Document already includes a cover text for the same cover, previously added by you or by arrangement made by the same entity you are acting on behalf of, you may not add another; but you may replace the old one, on explicit permission from the previous publisher that added the old one.

The author(s) and publisher(s) of the Document do not by this License give permission to use their names for publicity for or to assert or imply endorsement of any Modified Version.

5. COMBINING DOCUMENTS

You may combine the Document with other documents released under this License, under the terms defined in section 4 above for modified versions, provided that you include in the combination all of the Invariant Sections of all of the original documents, unmodified, and list them all as Invariant Sections of your combined work in its license notice, and that you preserve all their Warranty Disclaimers.

The combined work need only contain one copy of this License, and multiple identical Invariant Sections may be replaced with a single copy. If there are multiple Invariant Sections with the same name but different contents, make the title of each such section unique by adding at the end of it, in parentheses, the name of the original author or publisher of that section if known, or else a unique number. Make the same adjustment to the section titles in the list of Invariant Sections in the license notice of the combined work.

In the combination, you must combine any sections Entitled “History” in the various original documents, forming one section Entitled “History”; likewise combine any sections Entitled “Acknowledgements”, and any sections Entitled “Dedications”. You must delete all sections Entitled “Endorsements”.

6. COLLECTIONS OF DOCUMENTS

You may make a collection consisting of the Document and other documents released under this License, and replace the individual copies of this License in the various documents with a single copy that is included in the collection, provided that you follow the rules of this License for verbatim copying of each of the documents in all other respects.

You may extract a single document from such a collection, and distribute it individually under this License, provided you insert a copy of this License into the extracted document, and follow this License in all other respects regarding verbatim copying of that document.

7. AGGREGATION WITH INDEPENDENT WORKS

A compilation of the Document or its derivatives with other separate and independent documents or works, in or on a volume of a storage or distribution medium, is called an “aggregate” if the copyright resulting from the compilation is not used to limit the legal rights of the compilation’s users beyond what the individual works permit. When the Document is included in an aggregate, this License does not apply to the other works in the aggregate which are not themselves derivative works of the Document.

If the Cover Text requirement of section 3 is applicable to these copies of the Document, then if the Document is less than one half of the entire aggregate, the Document’s Cover Texts may be placed on covers that bracket the Document within the aggregate, or the electronic equivalent of covers if the Document is in electronic form. Otherwise they must appear on printed covers that bracket the whole aggregate.

8. TRANSLATION

Translation is considered a kind of modification, so you may distribute translations of the Document under the terms of section 4. Replacing Invariant Sections with translations requires special permission from their copyright holders, but you may include translations of some or all Invariant Sections in addition to the original versions of these Invariant Sections. You may include a translation of this License, and all the license notices in the Document, and any Warranty Disclaimers, provided that you also include the original English version of this License and the original versions of those notices and disclaimers. In case of a disagreement between the translation and the original version of this License or a notice or disclaimer, the original version will prevail.

If a section in the Document is Entitled “Acknowledgements”, “Dedications”, or “History”, the requirement (section 4) to Preserve its Title (section 1) will typically require changing the actual title.

9. TERMINATION

You may not copy, modify, sublicense, or distribute the Document except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, or distribute it is void, and will automatically terminate your rights under this License.

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, receipt of a copy of some or all of the same material does not give you any rights to use it.

10. FUTURE REVISIONS OF THIS LICENSE

The Free Software Foundation may publish new, revised versions of the GNU Free Documentation 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. See Copyleft.

Each version of the License is given a distinguishing version number. If the Document specifies that a particular numbered version of this License “or any later version” applies to it, you have the option of following the terms and conditions either of that specified version or of any later version that has been published (not as a draft) by the Free Software Foundation. If the Document does not specify a version number of this License, you may choose any version ever published (not as a draft) by the Free Software Foundation. If the Document specifies that a proxy can decide which future versions of this License can be used, that proxy’s public statement of acceptance of a version permanently authorizes you to choose that version for the Document.

11. RELICENSING

“Massive Multiauthor Collaboration Site” (or “MMC Site”) means any World Wide Web server that publishes copyrightable works and also provides prominent facilities for anybody to edit those works. A public wiki that anybody can edit is an example of such a server. A “Massive Multiauthor Collaboration” (or “MMC”) contained in the site means any set of copyrightable works thus published on the MMC site.

“CC-BY-SA” means the Creative Commons Attribution-Share Alike 3.0 license published by Creative Commons Corporation, a not-for-profit corporation with a principal place of business in San Francisco, California, as well as future copyleft versions of that license published by that same organization.

“Incorporate” means to publish or republish a Document, in whole or in part, as part of another Document.

An MMC is “eligible for relicensing” if it is licensed under this License, and if all works that were first published under this License somewhere other than this MMC, and subsequently incorporated in whole or in part into the MMC, (1) had no cover texts or invariant sections, and (2) were thus incorporated prior to November 1, 2008.

The operator of an MMC Site may republish an MMC contained in the site under CC-BY-SA on the same site at any time before August 1, 2009, provided the MMC is eligible for relicensing.

ADDENDUM: How to use this License for your documents

To use this License in a document you have written, include a copy of the License in the document and put the following copyright and license notices just after the title page:

Copyright © YEAR YOUR NAME

Permission is granted to copy, distribute and/or modify this document under the
terms of the GNU Free Documentation License, Version 1.3 or any later version
published by the Free Software Foundation; with no Invariant Sections, no
Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in
the section entitled “GNU Free Documentation License”.

If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts, replace the “with… Texts.” line with this:

with the Invariant Sections being LIST THEIR TITLES, with the Front-Cover Texts
being LIST, and with the Back-Cover Texts being LIST.

If you have Invariant Sections without Cover Texts, or some other combination of the three, merge those two alternatives to suit the situation.

If your document contains nontrivial examples of program code, we recommend releasing these examples in parallel under your choice of free software license, such as the GNU General Public License, to permit their use in free software.

source/src/docs/html/EC.html0000644000175000017500000001211212714113765014710 0ustar olesoles BNF for EC.jj

BNF for EC.jj

NON-TERMINALS

expression ::= conditional ( <EOF> )
conditional ::= lor ( "?" conditional ":" conditional )?
lor ::= land ( <LOR> land )*
land ::= bor ( <LAND> bor )*
bor ::= bxor ( <OR> bxor )*
bxor ::= band ( <XOR> band )*
band ::= equality ( <AND> equality )*
equality ::= relation ( ( <EQ> | <NE> ) relation )*
relation ::= shift ( ( <LT> | <GE> | <GT> | <LE> ) shift )*
shift ::= sum ( ( <LS> | <RS> | <RUS> ) sum )*
sum ::= term ( ( <PLUS> | <MINUS> ) term )*
term ::= unary ( ( <MULTIPLY> | <DIVIDE> | <REMAINDER> ) unary )*
unary ::= ( <BWCOMPL> | <LOGCOMPL> | <MINUS> ) unary
| "(" <ID> ( "." <ID> )* ")" element
| element
element ::= <TRUE>
| <FALSE>
| ( ( literal | "(" conditional ")" | invocation ) ( <DOT> invocation )* )
invocation ::= <ID> ( "(" ( conditional ( "," conditional )* )? ")" )? ( "[" conditional "]" )*
literal ::= <INTEGER_LITERAL>
| <FLOATING_POINT_LITERAL>
| <CHARACTER_LITERAL>
| <STRING_LITERAL>
source/src/docs/README.testsuite0000644000175000017500000000212612714113765015503 0ustar olesolesThis is the testsuite for JEL. It contains many expressions (>15000), testing various aspects of the compiler. Apart from being useful in JEL development, this test suite may help the users to test compati- bility of JEL with their version of JVM (in case it is a non-standard one, or after a major Java specification update). Please run the testsuite jar file from the current directory in JEL distribution like this: java -jar tests.jar Testsuite depends on ../../source/third-party/junit.jar and tests JEL classes in ../../lib/jel.jar. If you need to test the debug version of the library (e.g. for a better diagnostics after jel.jar testing have failed), you will need to specify the class path and the main class manually like this: java -cp tests.jar:../../source/third-party/junit.jar:../../lib/jel_g.jar gnu.jel.JELTestSuite More tests in form of patches or wishes are always WELCOME !!! Copyright (C) 2009 Konstantin L. Metlov This file is licensed to you under the terms of GNU Free Documentation License as given in the appendix of JEL Manual. source/src/docs/COPYING0000644000175000017500000010451312714113765013631 0ustar olesoles 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 . source/src/docs/README.calculator0000644000175000017500000000376712714113765015617 0ustar olesolesHow to run the JEL calculator. Calculator is one of the simpliest (and FIRST) JEL based programs. It takes the expression as it's input, evaluates it once and prints the result. The sample command line to invoke the calculator on Windows is jre -cp ".;../../lib/jel.jar" Calculator "2*2" on Linux this will be java -cp ".:../../lib/jel.jar" Calculator "2*2" Both these commans should print the answer 4 promptly in their respec- tive environments. You can use functions, of java.lang.Math in your expressions. Expressions to try : "2*2", "pow(sin(1),2)+pow(sin(3),2)", "exp(log(55))", "exp(log(55F))", or any other.... Please report BUGS to metlov@fti.dn.ua. Notes : 1. Some shells try to interpret parts of expressions themselves when they are not quoted. For example expression "2|2" can not be properly executed in bash without quotes. Be sure to quote expressions if Your shell requires it. 2. This example does not demonstrate actual power of JEL as expression is evaluated only once. Then, compiling it becomes the waste of resources. Have this in mind, please. 3. The same as the first note. For the simple programs (as Calculator) You can achieve faster performance by DISABLING the JIT compiler in Your VM. This is because only single expression is to be compiled most methods in the compiler are executed only once. Be informed, that the classical(not HotSpot) JIT compiles methods when they are actually called. There is certain overhead connected with JIT compilation, and if most methods are going to be executed once better performance can be achieved by DISABLING jit. In the long run, of course, JVM with JIT outperforms JVM without it. Try to compare the runtime of jre -cp ".;../../lib/jel.jar" Calculator "2*2" and jre -nojit -cp ".;../../lib/jel.jar" Calculator "2*2" to see which is faster. Copyright (C) 2016 Konstantin L. Metlov This file is licensed to you under the terms of GNU Free Documentation License as given in the appendix of JEL Manual. source/src/tests/0000755000175000017500000000000012714113765013004 5ustar olesolessource/src/tests/gnu/0000755000175000017500000000000012714113765013575 5ustar olesolessource/src/tests/gnu/jel/0000755000175000017500000000000012714113765014347 5ustar olesolessource/src/tests/gnu/jel/IntegralStaticTest.java0000644000175000017500000003252512714113765020776 0ustar olesoles/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * This file is part of the Java Expressions Library (JEL). * For more information about JEL visit : http://fti.dn.ua/JEL/ * * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2006, 2007, 2009 Konstantin L. Metlov * * 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 . */ package gnu.jel; import gnu.jel.tests.*; import java.io.PrintStream; import java.util.Stack; public class IntegralStaticTest extends TestingUtils { public IntegralStaticTest(String name) { super(name); } Library lib; public void setUp() throws Exception { Class[] staticLib=new Class[2]; Class[] dotAllowedOn=new Class[1]; staticLib[0]=Class.forName("java.lang.Math"); VariableProvider tvp=new VariableProvider(); staticLib[1]=tvp.getClass(); dotAllowedOn[0]=Class.forName("java.lang.String"); lib=new Library(staticLib,null,dotAllowedOn,null,null); lib.markStateDependent("random",null); } public void testExpr1() throws Throwable { simExpression("2*2",new Integer(4),null,null,lib,null); } public void testExpr2() throws Throwable { simExpression("2L*2L",new Long(4),null,null,lib,null); } public void testExpr3() throws Throwable { simExpression("2.0*2.0",new Double(4.0),null,null,lib,null); } public void testExpr4() throws Throwable { simExpression("2*2+3*3",new Integer(13),null,null,lib,null); } public void testExpr5() throws Throwable { simExpression("2/2+3/3",new Integer(2),null,null,lib,null); } public void testExpr6() throws Throwable { simExpression("2%2+3%3",new Integer(0),null,null,lib,null); } public void testExpr7() throws Throwable { simExpression("2*2-3*3",new Integer(-5),null,null,lib,null); } public void testExpr8() throws Throwable { simExpression("2/2-3/3",new Integer(0),null,null,lib,null); } public void testExpr9() throws Throwable { simExpression("2%2-3%3",new Integer(0),null,null,lib,null); } public void testExpr10() throws Throwable { simExpression("2.0F*2.0F",new Float(4.0F),null,null,lib,null); } public void testExpr11() throws Throwable { simExpression("sin(1)",new Double(Math.sin(1.0)),null,null,lib,null); } public void testExpr12() throws Throwable { simExpression("pow(sin(1),2)+pow(cos(1),2)",new Double(1.0),null,null, lib,null); } public void testExpr13() throws Throwable { simExpression("min(1+2*2,(1+2)*2)",new Integer(5),null,null,lib,null); } public void testExpr14() throws Throwable { simExpression("7+4-6",new Double(5.0),Double.TYPE,null,lib,null); } public void testExpr15() throws Throwable { simExpression("true&&false||false&&true||false",Boolean.FALSE, null,null,lib,null); } public void testExpr16() throws Throwable { simExpression("(1<<2L==4)&&(-1>>5==-1)&&(-1>>>1==0x7FFFFFFF)", Boolean.TRUE,null,null,lib,null); } public void testExpr17() throws Throwable { simExpression("(-1>>>1==0x5FFFFFFF)", Boolean.FALSE,null,null,lib,null); } public void testExpr18() throws Throwable { simExpression("(-1L>>>1L==0x7FFFFFFFFFFFFFFFL)", Boolean.TRUE,null,null,lib,null); } public void testExpr19() throws Throwable { simExpression("1+2>2==true", Boolean.TRUE,null,null,lib,null); } public void testExpr20() throws Throwable { simExpression("true?false:true?true:false", Boolean.FALSE,null,null,lib,null); } public void testExpr21() throws Throwable { simExpression("false?true:true?false:true", Boolean.FALSE,null,null,lib,null); } public void testExpr22() throws Throwable { simExpression("(1==1)&&(max(~bool2int(1<=2),~bool2int(2>=3))!=-1)", Boolean.FALSE,null,null,lib,null); } public void testExpr23() throws Throwable { simExpression("(-1==-1)&&(max(~(1<=2?1:0),~(2>=3?1:0))!=-1)", Boolean.FALSE,null,null,lib,null); } public void testExpr24() throws Throwable { simExpression("!((!true)&&(!true))", Boolean.TRUE,null,null,lib,null); } public void testExpr25() throws Throwable { simExpression("!(!(false&&false&&false)&&!false)", Boolean.FALSE,null,null,lib,null); } public void testExpr26() throws Throwable { simExpression("(!(5+1>5)?1:2)==2", Boolean.TRUE,null,null,lib,null); } public void testExpr27() throws Throwable { simFullLogic("!(!(_a&&_b&&_c)&&!_d)",4,lib,null,false); } public void testExpr28() throws Throwable { simFullLogic("_a&&_b&&_c||_d",4,lib,null,false); } public void testExpr29() throws Throwable { simFullLogic("_a&&(_b&&(_c||_d))",4,lib,null,false); } public void testExpr30() throws Throwable { simFullLogic("_a&&((_b&&_c)||_d)",4,lib,null,false); } public void testExpr31() throws Throwable { simFullLogic("(_a&&_b)||!(_c&&_d)||_e",5,lib,null,false); } public void testExpr32() throws Throwable { simFullLogic("_a&&((_b&&(!(_c&&_d)||_e))||_f)",6,lib,null,false); } public void testExpr33() throws Throwable { simFullLogic("_a&&(!(_b&&(!(_c&&_d)||_e))||!_f)",6,lib,null,false); } public void testExpr34() throws Throwable { simFullLogic("_a&(!(_b&(!(_c&_d)|_e))|!_f)",6,lib,null,false); } public void testExpr35() throws Throwable { simFullLogic("_a?_b||_c||_d:_e&&_f",6,lib,null,false); } public void testExpr36() throws Throwable { simFullLogic("(_a==_b)&&(max(~bool2int(1<=2&&_c||_d),~bool2int(2>=3&&_e||_f))!=-1)",6,lib,null,false); } public void testExpr37() throws Throwable { simFullLogic("_a?_b:_c?_d:_e",5,lib,null,false); } public void testExpr38() throws Throwable { simExpression("\"aa\"+\"bb\"+\"cc\"", "aabbcc",null,null,lib,null); } public void testExpr39() throws Throwable { simExpression("\"str\"+true+1+20L+6.0F+7.0D", "strtrue1206.07.0",null,null,lib,null); } public void testExpr40() throws Throwable { simExpression("\"str\"+(2+3)","str5",null,null,lib,null); } public void testExpr41() throws Throwable { simExpression("((~(~((((1+2-2)*2/2)^55)^55)))|1&2)==1", Boolean.TRUE,null,null,lib,null); } public void testExpr42() throws Throwable { simExpression("((~(~((((1L+2L-2L)*2L/2L)^55L)^55L)))|1L&2L)==1L", Boolean.TRUE,null,null,lib,null); } public void testExpr43() throws Throwable { simExpression("((10/3)*3+10%3)==10", Boolean.TRUE,null,null,lib,null); } public void testExpr44() throws Throwable { simExpression("((10L/3)*3+10%3L)==10L", Boolean.TRUE,null,null,lib,null); } public void testExpr45() throws Throwable { simExpression("((1>5?0:10F)/3)*3+10F%3", new Float(11.0F),null,null,lib,null); } public void testExpr46() throws Throwable { simExpression("((1>5?0:10D)/3)*3+10D%3", new Double(11.0),null,null,lib,null); } public void testExpr47() throws Throwable { simExpression("round(((10-5)==5?(6.0-((8==8)?5.0:1))*2.0:1.0+"+ "2.0-1.0)/2.0)==1", Boolean.TRUE,null,null,lib,null); } public void testExpr48() throws Throwable { simExpression("true?\"a\"+\"b\":\"c\"","ab",null,null,lib,null); } public void testExpr49() throws Throwable { simExpression("true?\"a\"+\"b\":\"c\"+\"d\"","ab",null,null,lib,null); } public void testExpr50() throws Throwable { simExpression("true?\"ab\":\"c\"+\"d\"","ab",null,null,lib,null); } public void testExpr51() throws Throwable { simExpression("false?\"a\"+\"b\":\"c\"+\"d\"","cd",null,null,lib,null); } public void testExpr52() throws Throwable { simExpression("false?\"ab\":\"c\"+\"d\"","cd",null,null,lib,null); } public void testExpr53() throws Throwable { simExpression("false?\"ab\":\"cd\"","cd",null,null,lib,null); } public void testExpr54() throws Throwable { simExpression("false?\"ab\":\"cd\"","cd",null,null,lib,null); } public void testExpr55() throws Throwable { simExpression("(false?\"a\"+\"b\":\"c\"+\"d\")+\"e\"","cde", null,null,lib,null); } public void testExpr56() throws Throwable { simExpression("\"e\"+(false?\"a\"+\"b\":\"c\"+\"d\")","ecd", null,null,lib,null); } // Tests if NaN (floating point "not a number") handling conforms to JLS public void testNaNExt() throws Throwable { simExpression("(1>NaNd)",Boolean.FALSE,null,null,lib,null); simExpression("(1=NaNd)",Boolean.FALSE,null,null,lib,null); simExpression("(1<=NaNd)",Boolean.FALSE,null,null,lib,null); simExpression("(1==NaNd)",Boolean.FALSE,null,null,lib,null); simExpression("!(1!=NaNd)",Boolean.FALSE,null,null,lib,null); simExpression("(NaNd>1)",Boolean.FALSE,null,null,lib,null); simExpression("(NaNd<1)",Boolean.FALSE,null,null,lib,null); simExpression("(NaNd>=1)",Boolean.FALSE,null,null,lib,null); simExpression("(NaNd<=1)",Boolean.FALSE,null,null,lib,null); simExpression("(NaNd==1)",Boolean.FALSE,null,null,lib,null); simExpression("!(NaNd!=1)",Boolean.FALSE,null,null,lib,null); simExpression("(1>NaNf)",Boolean.FALSE,null,null,lib,null); simExpression("(1=NaNf)",Boolean.FALSE,null,null,lib,null); simExpression("(1<=NaNf)",Boolean.FALSE,null,null,lib,null); simExpression("(1==NaNf)",Boolean.FALSE,null,null,lib,null); simExpression("!(1!=NaNf)",Boolean.FALSE,null,null,lib,null); simExpression("(NaNf>1)",Boolean.FALSE,null,null,lib,null); simExpression("(NaNf<1)",Boolean.FALSE,null,null,lib,null); simExpression("(NaNf>=1)",Boolean.FALSE,null,null,lib,null); simExpression("(NaNf<=1)",Boolean.FALSE,null,null,lib,null); simExpression("(NaNf==1)",Boolean.FALSE,null,null,lib,null); simExpression("!(NaNf!=1)",Boolean.FALSE,null,null,lib,null); }; public void testNaNCondensed() throws Throwable { // In fact, next four tests are equivalent to the above ones, // but there was a problem with them and to solve it I had // to separate tests (making the above thing). I decided not // to remove the above since ... well... it makes testsuite runs // more impressive ;))) simExpression("(NaNd>1)||(NaNd<1)||(NaNd>=1)||(NaNd<=1)||"+ "(NaNd==1)||!(NaNd!=1)", Boolean.FALSE,null,null,lib,null); simExpression("(1>NaNd)||(1=NaNd)||(1<=NaNd)||"+ "(1==NaNd)||!(1!=NaNd)", Boolean.FALSE,null,null,lib,null); simExpression("(NaNf>1)||(NaNf<1)||(NaNf>=1)||(NaNf<=1)||"+ "(NaNf==1)||!(NaNf!=1)", Boolean.FALSE,null,null,lib,null); simExpression("(1>NaNf)||(1=NaNf)||(1<=NaNf)||"+ "(1==NaNf)||!(1!=NaNf)", Boolean.FALSE,null,null,lib,null); }; public void testExpr57() throws Throwable { simExpression("\"aaaca\".indexOf('c')+1==4 && "+ "(1>2?\"cc\":\"aaaca\").indexOf('c')+1==4", Boolean.TRUE,null,null,lib,null); } public void testExpr58() throws Throwable { simExpression("round((float)4)", new Integer(4),null,null,lib,null); } public void testExpr59() throws Throwable { simExpression("(int)4.0", new Integer(4),null,null,lib,null); } public void testExpr60() throws Throwable { simExpression("-(int)234", new Integer(-234),null,null,lib,null); } public void testExpr61() throws Throwable { simExpression("-(short)(-(int)234)", new Integer(234),null,null,lib,null); } public void testExpr62() throws Throwable { simExpression("!(boolean)(true)", Boolean.FALSE,null,null,lib,null); } public void testExpr63() throws Throwable { simExpression("7+(int)4-(int)6.0+1-(int)round((double)((float)((long)1+0)+0)+0)", new Integer(5),null,null,lib,null); } public void testExpr64() throws Throwable { simExpression("~0",new Integer(-1),null,null,lib,null); } public void testExpr65() throws Throwable { simExpression("~0",new Integer(-1),null,null,lib,null); } public void testExpr66() throws Throwable { simExpression("(\"abbb\"+\"ccc\"+'d'+(1>2?\"e\":\"d\")).substring(1)", "bbbcccdd",null,null,lib,null); } public void testExpr67() throws Throwable { simExpression("\"abbb\".substring(1).equals(\"bbb\")||false", Boolean.TRUE,null,null,lib,null); } public void testExpr68() throws Throwable { simExpression("\"abbb\"+'d'","abbbd",null,null,lib,null); } }; source/src/tests/gnu/jel/LibraryTest.java0000644000175000017500000000765712714113765017475 0ustar olesoles/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * This file is part of the Java Expressions Library (JEL). * For more information about JEL visit : http://fti.dn.ua/JEL/ * * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2006, 2007, 2009 Konstantin L. Metlov * * 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 . */ package gnu.jel; import junit.framework.TestCase; import java.io.StringReader; import java.lang.reflect.Member; public class LibraryTest extends TestCase { public LibraryTest(String name) { super(name); } Library ll; Class math; public void setUp() throws Exception { math=Class.forName("java.lang.Math"); Class[] sl=new Class[1]; sl[0]=math; ll=new Library(sl,null,null,null,null); } public void tearDown() throws Exception { } public void testRoundDBL() throws Exception { Class[] par=new Class[1]; par[0]=Double.TYPE; Member mf=ll.getMember(null,"round",par); assertTrue((mf!=null) && (mf.equals(math.getMethod("round",par)))); } public void testRoundFLT() throws Exception { Class[] par=new Class[1]; par[0]=Float.TYPE; Member mf=ll.getMember(null,"round",par); assertTrue((mf!=null) && (mf.equals(math.getMethod("round",par)))); } public void testRoundINT() throws Exception { // test that on invocation "rount(int)" the closest is // "round(float)" Class[] par=new Class[1]; par[0]=Float.TYPE; Member mf=ll.getMember(null,"round",par); Class[] par1=new Class[1]; par1[0]=Float.TYPE; assertTrue((mf!=null) && (mf.equals(math.getMethod("round",par1)))); } public void testAbsINT() throws Exception { Class[] par=new Class[1]; par[0]=Integer.TYPE; Member mf=ll.getMember(null,"abs",par); Class[] par1=new Class[1]; par1[0]=Integer.TYPE; assertTrue((mf!=null) && (mf.equals(math.getMethod("abs",par1)))); } public void testAbsBYTE() throws Exception { Class[] par=new Class[1]; par[0]=Byte.TYPE; Member mf=ll.getMember(null,"abs",par); Class[] par1=new Class[1]; par1[0]=Integer.TYPE; // closest is "abs(int)" assertTrue((mf!=null) && (mf.equals(math.getMethod("abs",par1)))); } public void testAbsCHAR() throws Exception { Class[] par=new Class[1]; par[0]=Character.TYPE; Member mf=ll.getMember(null,"abs",par); Class[] par1=new Class[1]; par1[0]=Integer.TYPE; // closest is "abs(int)" assertTrue((mf!=null) && (mf.equals(math.getMethod("abs",par1)))); } public void testMinINT_FLOAT() throws Exception { // "min(int,float)" -> "min(float,float)" Class[] par=new Class[2]; par[0]=Integer.TYPE; par[1]=Float.TYPE; Member mf=ll.getMember(null,"min",par); Class[] par1=new Class[2]; par1[0]=Float.TYPE; par1[1]=Float.TYPE; assertTrue((mf!=null) && (mf.equals(math.getMethod("min",par1)))); } public void testPI() throws Exception { Class[] par=new Class[0]; Member f=ll.getMember(null,"PI",par); assertTrue((f!=null) && (f.getName().equals("PI"))); } public void testStateDep() throws Exception { ll.markStateDependent("random",null); assertTrue(!ll.isStateless(ll.getMember(null,"random",null))); }; } source/src/tests/gnu/jel/IntegralDynamicVariablesTest.java0000644000175000017500000002367512714113765022772 0ustar olesoles/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * This file is part of the Java Expressions Library (JEL). * For more information about JEL visit : http://fti.dn.ua/JEL/ * * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2006, 2007, 2009 Konstantin L. Metlov * * 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 . */ package gnu.jel; import gnu.jel.tests.*; import java.io.PrintStream; import java.util.Stack; public class IntegralDynamicVariablesTest extends TestingUtils { public IntegralDynamicVariablesTest(String name) { super(name); } Library lib; Object[] rtp; VariableProvider vp; public void setUp() throws Exception { Class[] dynamicLib=new Class[1]; rtp=new Object[1]; vp=new VariableProvider(); Class[] staticLib=new Class[2]; staticLib[0]=Class.forName("java.lang.Math"); // next line makes also static functions from VariablePrivider available staticLib[1]=vp.getClass(); vp.xvar=5.0; vp.strVar="strVar"; rtp[0]=vp; dynamicLib[0]=vp.getClass(); Class[] dotLib=new Class[5]; dotLib[0]=Class.forName("java.lang.String"); dotLib[1]=Class.forName("java.lang.Double"); dotLib[2]=Class.forName("gnu.jel.reflect.Double"); dotLib[3]=IntegerObject.class; dotLib[4]=DoubleObject.class; lib=new Library(staticLib,dynamicLib,dotLib,vp,null); vp.addProperty("p1","p1value"); vp.addProperty("p1.s1","p1s1value"); vp.addProperty("p1.s2","p1s2value"); vp.addProperty("p1.d1",VariableProvider.makeJELDoubleObject(1.0)); vp.addProperty("p1.s2.ss1","p1s2ss1value"); vp.addProperty("p1.b1t",VariableProvider.makeJELBooleanObject(true)); vp.addProperty("p1.b1f",VariableProvider.makeJELBooleanObject(false)); } public void test1() throws Throwable { simExpression("p1", "p1value", null, rtp, lib,null); } public void test2() throws Throwable { simExpression("p1.s1", "p1s1value", null, rtp, lib,null); } public void test3() throws Throwable { simExpression("p1.s2", "p1s2value", null, rtp, lib,null); } public void test4() throws Throwable { simExpression("p1.s2.ss1","p1s2ss1value", null, rtp, lib,null); } public void test5() throws Throwable { simExpression("p1.d1.aMethod()", new Integer(1), null, rtp, lib,null); } public void test6() throws Throwable { simExpression("p1.s2.length()", new Integer(9), null, rtp, lib,null); } public void test7() throws Throwable { simExpression("p1+(p1.d1+p1.s2.length()+1)", "p1value11.0", null, rtp, lib,null); } public void test8() throws Throwable { simExpression("round(p1.d1)", new Long(1), null, rtp, lib,null); } public void test9() throws Throwable { simExpression("round(makeDoubleObject(p1.d1))", new Long(1), null, rtp, lib,null); } public void test10() throws Throwable { simExpression("\"abc\".compareTo(\"\"+makeDoubleObject(p1.d1))>0", Boolean.TRUE, Boolean.TYPE,rtp, lib,null); } public void test11() throws Throwable { simExpression("\"abc\".compareTo((2>round(makeDoubleObject(p1.d1))?"+ "\"\":\"a\")+"+ "makeDoubleObject(p1.d1))>0", Boolean.TRUE, null,rtp, lib,null); } public void test12() throws Throwable { simExpression("p1.d1>0", new Boolean(true), null, rtp, lib,null); } public void test13() throws Throwable { simExpression("p1.d1>0?p1.d1:3.0", new Double(1.0), null, rtp, lib,null); } public void test14() throws Throwable { simExpression("p1.b1t", new Boolean(true), Boolean.TYPE, rtp, lib,null); } public void test15() throws Throwable { simExpression("(boolean)p1.b1t", new Boolean(true), null, rtp, lib,null); } public void test16() throws Throwable { simExpression("p1.b1t?1:0", new Byte((byte)1), null, rtp, lib,null); } public void test17() throws Throwable { simExpression("aarr[1][0]", new Double(3.0), null, rtp, lib,null); } public void test18() throws Throwable { simExpression("aarrDouble[1][0].doubleValue()", new Double(3.0), null, rtp, lib,null); } public void test19() throws Throwable { simExpression("aarrDouble[1][0]", new Double(3.0), null, rtp, lib,null); } public void test20() throws Throwable { simExpression("\"\"+aarr[1][0]","3.0", null, rtp, lib,null); } public void test21() throws Throwable { simExpression("\"\"+aarrDouble[1][0]","3.0", null, rtp, lib,null); } public void test22() throws Throwable { simExpression("\"\"+aarrDouble[1][0].doubleValue", "3.0", null, rtp, lib,null); } public void test23() throws Throwable { simExpression("\"\"+\"\"+aarr[1][0]","3.0", null, rtp, lib,null); } public void test24() throws Throwable { simExpression("\"a\"+\"b\"+aarr[1][0]+\"c\"","ab3.0c", null, rtp, lib,null); } public void test25() throws Throwable { simExpression("\"a\"==\"b\"",Boolean.FALSE, null, rtp, lib,null); } public void test26() throws Throwable { simExpression("\"a\"==\"a\"",Boolean.TRUE, null, rtp, lib,null); } public void test27() throws Throwable { simExpression("\"a\"!=\"b\"",Boolean.TRUE, null, rtp, lib,null); } public void test28() throws Throwable { simExpression("\"a\"!=\"a\"",Boolean.FALSE, null, rtp, lib,null); } public void test29() throws Throwable { simExpression("!(\"a\"!=\"b\")",Boolean.FALSE, null, rtp, lib,null); } public void test30() throws Throwable { simExpression("!(\"a\"==\"a\")",Boolean.FALSE, null, rtp, lib,null); } public void test31() throws Throwable { simExpression("\"a\"+\"b\"==\"ab\"",Boolean.TRUE, null, rtp, lib,null); } public void test32() throws Throwable { simExpression("\"a\"+\"b\"!=\"ab\"",Boolean.FALSE, null, rtp, lib,null); } public void test33() throws Throwable { simExpression("\"a\"+\"b\"==\"a\"+\"b\"",Boolean.TRUE, null, rtp, lib,null); } public void test34() throws Throwable { simExpression("!(\"a\"+\"b\"!=\"a\"+\"b\")",Boolean.TRUE, null, rtp, lib,null); } public void test35() throws Throwable { simExpression("\"a\"<\"b\"",Boolean.TRUE, null, rtp, lib,null); } public void test36() throws Throwable { simExpression("\"a\"<=\"b\"",Boolean.TRUE, null, rtp, lib,null); } public void test37() throws Throwable { simExpression("\"a\">=\"b\"",Boolean.FALSE, null, rtp, lib,null); } public void test38() throws Throwable { simExpression("\"a\">\"b\"",Boolean.FALSE, null, rtp, lib,null); } public void test39() throws Throwable { simExpression("\"b\"<\"a\"",Boolean.FALSE, null, rtp, lib,null); } public void test40() throws Throwable { simExpression("\"b\"<=\"a\"",Boolean.FALSE, null, rtp, lib,null); } public void test41() throws Throwable { simExpression("\"b\">=\"a\"",Boolean.TRUE, null, rtp, lib,null); } public void test42() throws Throwable { simExpression("\"b\">\"a\"",Boolean.TRUE, null, rtp, lib,null); } public void test43() throws Throwable { simExpression("\"a\"<\"a\"",Boolean.FALSE, null, rtp, lib,null); } public void test44() throws Throwable { simExpression("\"a\">\"a\"",Boolean.FALSE, null, rtp, lib,null); } public void test45() throws Throwable { simExpression("\"a\"<=\"a\"",Boolean.TRUE, null, rtp, lib,null); } public void test46() throws Throwable { simExpression("\"a\">=\"a\"",Boolean.TRUE, null, rtp, lib,null); } public void test47() throws Throwable { simExpression("\"3.0\"==\"\"+aarrDouble[1][0]",Boolean.TRUE, null, rtp, lib,null); } public void test48() throws Throwable { simExpression("\"\"==anObject",Boolean.FALSE,null, rtp, lib,null); } public void test49() throws Throwable { simExpression("anObject==anObject",Boolean.TRUE,null, rtp, lib,null); } public void test50() throws Throwable { simExpression("anObject!=anObject",Boolean.FALSE,null, rtp, lib,null); } public void test51() throws Throwable { simExpression("!(anObject==anObject)",Boolean.FALSE,null, rtp, lib,null); } public void test52() throws Throwable { vp.addProperty("\u3050\u3051","Hiragana"); simExpression("\u3050\u3051+\"-works\"", "Hiragana-works", null, rtp, lib,null); } public void test53() throws Throwable { vp.addProperty("\u3106\u3107","Bopomofo"); simExpression("\u3106\u3107+\"-works\"", "Bopomofo-works", null, rtp, lib,null); } public void test54() throws Throwable { // test unicode escape parsing in string literals simExpression("\"\\u31aE\\u3107\"+\"-works\"", "\u31aE\u3107-works", null, rtp, lib,null); } public void test55() throws Throwable { // test unicode escape parsing in char literals simExpression("\"\"+\'\\u31aE\'+\"-works\"", "\u31aE-works", null, rtp, lib,null); } public void test56() throws Throwable { simExpression("_T_g", "_U_g",null, rtp, lib,null); } public void test57() throws Throwable { simExpression("_T_j", "_U_j",null, rtp, lib,null); } public void test58() throws Throwable { simExpression("_T_j+_T_g", "_U_j_U_g",null, rtp, lib,null); } public void test59() throws Throwable { //-------- FOR JULIA DUNPHY double[] atemp={1.0,2.0}; vp.addProperty("A",atemp); simExpression("A[0]+3.0", new Double(4.0), null, rtp, lib,null); }; }; source/src/tests/gnu/jel/ClassFileTest.java0000644000175000017500000000626512714113765017730 0ustar olesoles/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * This file is part of the Java Expressions Library (JEL). * For more information about JEL visit : http://fti.dn.ua/JEL/ * * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2006, 2007, 2009 Konstantin L. Metlov * * 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 . */ package gnu.jel; import junit.framework.TestCase; import java.io.StringReader; import java.lang.reflect.Method; public class ClassFileTest extends TestCase { public ClassFileTest(String name) { super(name); } ClassFile cf; public void setUp() throws Exception { LocalField[] lf=new LocalField[1]; // private Object[] e; lf[0]=new LocalField(0x0002,(new Object[0]).getClass(),"e",null); cf = new ClassFile(0x0001,"dump",(new Object()).getClass(),null,lf); } public void tearDown() throws Exception { } public void testAdd2UTF() throws Exception { String s1="some string"; assertEquals(cf.getUTFIndex(s1), cf.getUTFIndex(s1)); } public void testAdd2Long() throws Exception { assertEquals(cf.getIndex(new Long(15),5), cf.getIndex(new Long(15),5)); } public void testAdd2Int() throws Exception { assertEquals(cf.getIndex(new Integer(15),4), cf.getIndex(new Integer(15),4)); } public void testAdd2Float() throws Exception { assertEquals(cf.getIndex(new Float(15.0f),6), cf.getIndex(new Float(15.0f),6)); } public void testAdd2Double() throws Exception { assertEquals(cf.getIndex(new Double(15.0),7), cf.getIndex(new Double(15.0),7)); } public void testAdd2Str() throws Exception { String s1="some string"; assertEquals(cf.getUTFIndex(s1), cf.getUTFIndex(s1)); String s2="some other string"; assertEquals(cf.getIndex(s2,8), cf.getIndex(s2,8)); assertEquals(cf.getIndex(s1,8), cf.getIndex(s1,8)); } public void testAdd2Cls() throws Exception { assertEquals(cf.getIndex(cf.getClass(),9), cf.getIndex(cf.getClass(),9)); } public void testAdd2Mth() throws Exception { Class[] params=new Class[1]; Method a_method; params[0]=Class.forName("gnu.jel.ClassFile"); a_method=this.getClass().getMethod("dumpImage",params); assertEquals(cf.getIndex(a_method,10), cf.getIndex(a_method,10)); } public static void dumpImage(ClassFile cf) throws Exception { java.io.FileOutputStream fos= new java.io.FileOutputStream("dump.class"); fos.write(cf.getImage()); fos.close(); }; } source/src/tests/gnu/jel/IntegralExceptionsPassingTest.java0000644000175000017500000000364712714113765023220 0ustar olesoles/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * This file is part of the Java Expressions Library (JEL). * For more information about JEL visit : http://fti.dn.ua/JEL/ * * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2006, 2007, 2009 Konstantin L. Metlov * * 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 . */ package gnu.jel; import gnu.jel.tests.*; import java.io.PrintStream; import java.util.Stack; public class IntegralExceptionsPassingTest extends TestingUtils { public IntegralExceptionsPassingTest(String name) { super(name); } Library lib; Object[] rtp; VariableProvider vp; public void setUp() throws Exception { Class[] dynamicLib=new Class[1]; rtp=new Object[1]; vp=new VariableProvider(); Class[] staticLib=new Class[2]; staticLib[0]=Class.forName("java.lang.Math"); // next line makes also static functions from VariablePrivider available staticLib[1]=vp.getClass(); vp.xvar=5.0; vp.strVar="strVar"; rtp[0]=vp; dynamicLib[0]=vp.getClass(); lib=new Library(staticLib,dynamicLib,null,null,null); } public void test1() throws Throwable { simExpression("(1+6)/(2+2-4)",null,null,rtp,lib,null); } public void test2() throws Throwable { simExpression("throw_arg_eq_4(6-2)",null,null,rtp,lib,null); } }; source/src/tests/gnu/jel/TestingUtils.java0000644000175000017500000004070612714113765017657 0ustar olesoles/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * This file is part of the Java Expressions Library (JEL). * For more information about JEL visit : http://fti.dn.ua/JEL/ * * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2006, 2007, 2009 Konstantin L. Metlov * * 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 . */ package gnu.jel; import junit.framework.TestCase; import java.io.PrintStream; import java.util.Stack; public class TestingUtils extends TestCase { public TestingUtils(String name) { super(name); } protected static void simError(String expr,Class fixType, Library lib, int errcol, PrintStream o) throws Exception { if (o!=null) { o.print("*** : \""); o.print(expr); o.println('"'); }; CompilationException ce=null; try { OP op=Evaluator.parse(expr,lib,fixType); } catch (CompilationException e) { ce=e; }; assertTrue("No error detected, but should be",ce!=null); int column=ce.getColumn(); // Column, where error was found if (o!=null) { o.print(" "); for(int i=0;i>>i & 0x00000001)>0?true:false); StringBuffer cexpr=new StringBuffer(); for (int i=0;i fixType, Object[] runtimeParameters, Library lib, PrintStream o ) throws Throwable { boolean voideval=false; if (tobe==java.lang.Void.TYPE) { tobe=null; voideval=true; }; if (o!=null) { o.print("*** : \""); o.print(expr); if (tobe != null) { o.print("\" = "); if (tobe==java.lang.Void.TYPE) o.println("[VOID]"); else o.println(tobe); } else o.println("\" Should throw an exception at run time."); } OP op=null; try { op=Evaluator.parse(expr,lib,fixType); } catch (CompilationException ce) { if (o!=null) { o.print("--- COMPILATION ERROR :"); o.println(ce.getMessage()); o.print(" "); o.println(expr); int column=ce.getColumn(); // Column, where error was found for(int i=0;i compile_type=null; try { byte[] image=Evaluator.getImage(op); CompiledExpression expr_c= (CompiledExpression)(ImageLoader.load(image)).newInstance(); compile_type=expr_c.getTypeC(); // Execute several times to enable JIT compilation. // Some JITs compile methods if they are run more than once for(int acounter=0;acounter<20;acounter++) { result=expr_c.evaluate(runtimeParameters); }; } catch (Throwable e) { if ((tobe==null) && !voideval) { if (o!=null) { o.println("EXPECTED EXCEPTION."); o.print(" ");o.println(e.getMessage()); }; } else { o.println("Exception emerged during compilation/evaluation."); o.print(" ");e.printStackTrace(); throw e; // rethrow to signal error }; }; if (tobe!=null) { assertNotNull("NO RESULT", result); if (o!=null) { o.print(" ="); o.print(result); }; assertEquals(tobe, result); if (!compile_type.isInstance(result)) { if (o!=null) { o.println(""); o.println("WRONG COMPILE-TYPE !!!"); }; assertTrue("Wrong type of function result.", false); } else { if (o!=null) o.print("[!ETM got=\""+result.getClass()+"\" expected=\""+ compile_type+"\"]"); }; if (o!=null) o.println(""); } else { if (voideval) assertEquals(compile_type, Class.forName("java.lang.Void")); else assertNull(result); if (o!=null) { if (result!=null) o.println(" ="+result.toString()); else o.println("NO RESULT"); }; }; if (iteration==0) try { op=new OPload(op,op.eval()); } catch (Exception exc) { }; }; }; public static String toStr(OP o) { if (o instanceof OPload) { OPload op=(OPload)o; if (op.resID==8) return "\""+op.what+"\""; return op.what.toString()+(op.resID>9?'L':"ZBCSIJFDLV".charAt(op.resID)); }; if (o instanceof OPbinary) { String[] opSymbols={ "+","-","*","/","%","&","|","^","==","!=","<",">=", ">","<=","<<",">>",">>>","&&","||","{}",".+."}; OPbinary op=(OPbinary)o; return toStr(op.chi[0])+opSymbols[op.code]+toStr(op.chi[1]); }; if (o instanceof OPunary) { String[] opSymbols={"--","~","!","","(Z)","(B)", "(C)","(S)","(I)","(J)", "(F)","(D)","(L)","(POP)","->TSB","->STR"}; OPunary op=(OPunary)o; return opSymbols[op.code]+toStr(op.chi[0]); }; if (o instanceof OPcall) { OPcall op=(OPcall)o; if (op.m==null) return "{"+op.nplv+"}"; else { StringBuffer res=new StringBuffer(op.m.getName()); res.append('('); for (int i=0;i0) res.append(","); res.append(toStr(op.chi[i])); }; res.append(')'); return res.toString(); } }; if (o instanceof OPcondtnl) { OPcondtnl op=(OPcondtnl)o; StringBuffer res=new StringBuffer(); if (op.chi[1]!=null) res.append('('); res.append(toStr(op.chi[0])); if (op.chi[1]!=null) { res.append('?'); res.append(toStr(op.chi[1])); res.append(':'); res.append(toStr(op.chi[2])); res.append(')'); } return res.toString(); }; return "<<<<>>>"; }; // Tests a given binary operation on all primitive types protected static void testUnaryPrimitive(int code,int npbc, Library lib, Object[] context, long resVal, PrintStream o, String[] prefixes, String[] suffixes) throws Throwable { String[] typeNames={"Boolean","Byte","Character","Short","Integer", "Long","Float","Double"}; String[] opSymbols={"-","~","!"}; Object[] typeConstants={ new java.lang.Boolean(true), new java.lang.Byte((byte)1), new java.lang.Character((char)1), new java.lang.Short((short)1), new java.lang.Integer(1), new java.lang.Long(1), new java.lang.Float((float)1.0), new java.lang.Double(1.0)}; int npbcActual=0; for(int i=0;i<8;i++) { // determine the result type independently int resID=-1; try { Stack paramOPs=new Stack(); paramOPs.push(new OPload(typeConstants[i])); paramOPs.push(new OPunary(paramOPs,code)); resID=paramOPs.peek().resID; npbcActual++; } catch (CompilationException exc) { }; Object res=null; if (resID>=0) { // result exists test it // construct the resulting object switch (resID) { case 0: res=new java.lang.Boolean(resVal>0?true:false); break; case 1: res=new java.lang.Byte((byte)resVal); break; case 2: res=new java.lang.Character((char)resVal); break; case 3: res=new java.lang.Short((short)resVal); break; case 4: res=new java.lang.Integer((int)resVal); break; case 5: res=new java.lang.Long(resVal); break; case 6: res=new java.lang.Float((float)resVal); break; case 7: res=new java.lang.Double((double)resVal); break; default: assertTrue("The result of unary operation is not primitive", false); }; }; for(int k=0;k=", ">","<=","<<",">>",">>>","&&","||","{}",".+."}; Object[] typeConstants={ new java.lang.Boolean(true), new java.lang.Byte((byte)1), new java.lang.Character((char)1), new java.lang.Short((short)1), new java.lang.Integer(1), new java.lang.Long(1), new java.lang.Float((float)1.0), new java.lang.Double(1.0)}; int npbcActual=0; for(int i=0;i<8;i++) for(int j=0;j<8;j++) { // determine the result type independently int resID=-1; try { Stack paramOPs=new Stack(); paramOPs.push(new OPload(typeConstants[i])); paramOPs.push(new OPload(typeConstants[j])); paramOPs.push(new OPbinary(paramOPs,code)); resID=paramOPs.peek().resID; npbcActual++; } catch (CompilationException exc) { }; Object res=null; if (resID>=0) { // result exists test it // construct the resulting object switch (resID) { case 0: res=new java.lang.Boolean(resVal>0?true:false); break; case 1: res=new java.lang.Byte((byte)resVal); break; case 2: res=new java.lang.Character((char)resVal); break; case 3: res=new java.lang.Short((short)resVal); break; case 4: res=new java.lang.Integer(resVal); break; case 5: res=new java.lang.Long(resVal); break; case 6: res=new java.lang.Float(resVal); break; case 7: res=new java.lang.Double(resVal); break; default: assertTrue("The result of binary operation is not primitive", false); }; }; for(int k=0;k. */ package gnu.jel; import gnu.jel.tests.*; import java.io.PrintStream; import java.util.Stack; public class IntegralReferencesWideningTest extends TestingUtils { public IntegralReferencesWideningTest(String name) { super(name); } Library lib; Object[] rtp; VariableProvider vp; public void setUp() throws Exception { Class[] dynamicLib=new Class[1]; rtp=new Object[1]; vp=new VariableProvider(); Class[] staticLib=new Class[2]; staticLib[0]=Class.forName("java.lang.Math"); // next line makes also static functions from VariablePrivider available staticLib[1]=vp.getClass(); vp.xvar=5.0; vp.strVar="strVar"; rtp[0]=vp; dynamicLib[0]=vp.getClass(); Class[] dotLib=new Class[5]; dotLib[0]=Class.forName("java.lang.String"); dotLib[1]=Class.forName("java.lang.Double"); dotLib[2]=Class.forName("gnu.jel.reflect.Double"); dotLib[3]=IntegerObject.class; dotLib[4]=DoubleObject.class; lib=new Library(staticLib,dynamicLib,dotLib,vp,null); vp.addProperty("p1","p1value"); vp.addProperty("p1.s1","p1s1value"); vp.addProperty("p1.s2","p1s2value"); vp.addProperty("p1.d1",VariableProvider.makeJELDoubleObject(1.0)); vp.addProperty("p1.s2.ss1","p1s2ss1value"); vp.addProperty("p1.b1t",VariableProvider.makeJELBooleanObject(true)); vp.addProperty("p1.b1f",VariableProvider.makeJELBooleanObject(false)); } public void test1() throws Throwable { simExpression("convertNumberToInt(makeDoubleObject(5.0))",new Integer(5), null, rtp, lib,null); } public void test2() throws Throwable { simExpression("convertNumberToInt(arrIntegerObj[0])",new Integer(1), null, rtp, lib,null); } public void test3() throws Throwable { simExpression("convertNumberToDouble(arrIntegerObj[0])", new Double(1.0), null, rtp, lib,null); } public void test4() throws Throwable { simExpression("convertNumberToDouble(makeDoubleObject(5.0))", new Double(5.0), null, rtp, lib,null); } public void test5() throws Throwable { simExpression("convertNumberToDouble(makeDoubleObject(5.0))", new Double(5.0), null, rtp, lib,null); } public void test6() throws Throwable { simExpression("addNumbersDbl(makeDoubleObject(5.0),arrIntegerObj[0])", new Double(6.0), null, rtp, lib,null); } public void test7() throws Throwable { simExpression("addNumbersInt(makeDoubleObject(5.0),arrIntegerObj[0])", new Integer(6), null, rtp, lib,null); } public void test8() throws Throwable { simExpression("isNullDouble(getDoubleNull())", Boolean.TRUE, null, rtp, lib,null); } public void test9() throws Throwable { simExpression("isNullDouble(makeDoubleObject(5.0))", Boolean.FALSE, null, rtp, lib,null); } }; source/src/tests/gnu/jel/IntegralErrorTest.java0000644000175000017500000000772012714113765020637 0ustar olesoles/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * This file is part of the Java Expressions Library (JEL). * For more information about JEL visit : http://fti.dn.ua/JEL/ * * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2006, 2007, 2009 Konstantin L. Metlov * * 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 . */ package gnu.jel; import junit.framework.TestCase; //import gnu.jel.generated.EC; //import gnu.jel.generated.ParseException; //import gnu.jel.generated.TokenMgrError; import java.io.PrintStream; import java.util.Stack; import gnu.jel.tests.VariableProvider; public class IntegralErrorTest extends TestingUtils { public IntegralErrorTest(String name) { super(name); } Library lib; public void setUp() throws Exception { Class[] staticLib=new Class[2]; staticLib[0]=Class.forName("java.lang.Math"); VariableProvider tvp=new VariableProvider(); staticLib[1]=tvp.getClass(); Class[] dotAllowedOn=new Class[1]; dotAllowedOn[0]=Class.forName("java.lang.String"); lib=new Library(staticLib,null,dotAllowedOn,null,null); lib.markStateDependent("random",null); } public void tearDown() throws Exception { } public void testErr1() throws Exception { simError("",null,lib,0,null); } public void testErr2() throws Exception { simError(" ",null,lib,1,null); } public void testErr3() throws Exception { simError("tru",null,lib,1,null); } public void testErr4() throws Exception { simError("1=",null,lib,2,null); } public void testErr5() throws Exception { simError("1=",null,lib,2,null); } public void testErr6() throws Exception { simError("1=2",null,lib,3,null); } public void testErr7() throws Exception { simError("1.0-+1.0",null,lib,6,null); } public void testErr8() throws Exception { simError("1.0&1.0",null,lib,4,null); } public void testErr9() throws Exception { simError("-",null,lib,1,null); } public void testErr10() throws Exception { simError("0x56+0xXX",null,lib,8,null); } public void testErr11() throws Exception { simError("Sin(x)",null,lib,5,null); } public void testErr12() throws Exception { simError("Sin(6)",null,lib,1,null); } public void testErr13() throws Exception { simError("sin(' ')",null,lib,1,null); } // simError("'a'+'b'",null,lib,4,null); // <- now perfectly legal public void testErr14() throws Exception { simError("1+sin(1,6)",null,lib,3,null); } public void testErr15() throws Exception { simError("2147483649L+2147483649",null,lib,22,null); } public void testErr16() throws Exception { simError("01234567+08+5",null,lib,12,null); } public void testErr17() throws Exception { simError("0.5+0#4",null,lib,6,null); } public void testErr18() throws Exception { simError("0.5+1",Integer.TYPE,lib,5,null); } public void testErr19() throws Exception { simError("0.5+(floatp)0.4D",null,lib,6,null); } public void testErr20() throws Exception { simError("0.5+(boolean)0.4D",null,lib,6,null); } public void testErr21() throws Exception { simError("23?1:2",null,lib,3,null); } public void testErr22() throws Exception { simError("true?\" \":' '",null,lib,5,null); } public void testErr23() throws Exception { simError("true?\" \":makeDoubleObject(1.0)",null,lib,5,null); } }; source/src/tests/gnu/jel/JELTestSuite.java0000644000175000017500000000426712714113765017507 0ustar olesoles/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * This file is part of the Java Expressions Library (JEL). * For more information about JEL visit : http://fti.dn.ua/JEL/ * * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2006, 2007, 2009 Konstantin L. Metlov * * 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 . */ package gnu.jel; import junit.framework.Test; import junit.framework.TestSuite; public class JELTestSuite { public static Test suite() { TestSuite suite = new TestSuite(); suite.addTestSuite(IntegerStackTest.class); suite.addTestSuite(LibraryTest.class); suite.addTestSuite(LibraryDotOPTest.class); suite.addTestSuite(ParserTest.class); suite.addTestSuite(ClassFileTest.class); suite.addTestSuite(ClassFileExprTest.class); suite.addTestSuite(IntegralDotOperatorTest.class); suite.addTestSuite(IntegralDowncastingTest.class); suite.addTestSuite(IntegralDynamicVariablesTest.class); suite.addTestSuite(IntegralErrorTest.class); suite.addTestSuite(IntegralExceptionsPassingTest.class); suite.addTestSuite(IntegralPrimitiveOPsTest.class); suite.addTestSuite(IntegralReferencesWideningTest.class); suite.addTestSuite(IntegralStaticTest.class); suite.addTestSuite(IntegralVarARRTest.class); suite.addTestSuite(IntegralVirtualTest.class); suite.addTestSuite(IntegralVarargsTest.class); /* ALERT: Don't forget to add new testsuites here before release */ return suite; } /** * Runs the test suite using the textual runner. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } } source/src/tests/gnu/jel/IntegralVirtualTest.java0000644000175000017500000000755012714113765021175 0ustar olesoles/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * This file is part of the Java Expressions Library (JEL). * For more information about JEL visit : http://fti.dn.ua/JEL/ * * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2006, 2007, 2009 Konstantin L. Metlov * * 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 . */ package gnu.jel; import gnu.jel.tests.*; import java.io.PrintStream; import java.util.Stack; public class IntegralVirtualTest extends TestingUtils { public IntegralVirtualTest(String name) { super(name); } Library lib; Object[] rtp; public void setUp() throws Exception { Class[] dynamicLib=new Class[1]; rtp=new Object[1]; VariableProvider vp=new VariableProvider(); Class[] staticLib=new Class[2]; staticLib[0]=Class.forName("java.lang.Math"); // next line makes also static functions from VariablePrivider available staticLib[1]=vp.getClass(); vp.xvar=5.0; vp.strVar="strVar"; rtp[0]=vp; dynamicLib[0]=vp.getClass(); lib=new Library(staticLib,dynamicLib,null,null,null); } public void test1() throws Throwable { simExpression("sin(x/5)",new Double(Math.sin(1.0)),null,rtp,lib,null); } public void test2() throws Throwable { simExpression("255+5+7+9-x",new Double(255+7+9),null,rtp,lib,null); } public void test3() throws Throwable { simExpression("-x+255+5+7+9",new Double(255+7+9),null,rtp,lib,null); } public void test4() throws Throwable { simExpression("-x+(255+5+7+9)",new Double(255+7+9),null,rtp,lib,null); } public void test5() throws Throwable { simExpression("5*x-66",new Double(25-66),Double.TYPE,rtp,lib,null); } public void test6() throws Throwable { simExpression("7+(int)4-(int)6.0+(int)x-(int)round((double)((float)((long)x+1)+2)+3)+6", new Integer(5),null,rtp,lib,null); } public void test7() throws Throwable { simExpression("x",new Double(5.0),null,rtp,lib,null); } public void test8() throws Throwable { simExpression("(x)",new Double(5.0),null,rtp,lib,null); } public void test9() throws Throwable { simExpression("(-x)",new Double(-5.0),null,rtp,lib,null); } public void test10() throws Throwable { simExpression("(x())",new Double(5.0),null,rtp,lib,null); } public void test11() throws Throwable { simExpression("xS<4.0",Boolean.FALSE,null,rtp,lib,null); } public void test12() throws Throwable { simExpression("xXS<4.0",Boolean.FALSE,null,rtp,lib,null); } public void test13() throws Throwable { simExpression("x<4.0",Boolean.FALSE,null,rtp,lib,null); } public void test14() throws Throwable { simExpression("xX<4.0",Boolean.FALSE,null,rtp,lib,null); } public void test15() throws Throwable { simExpression("xS<4.0",Boolean.FALSE,Boolean.TYPE,rtp,lib,null); } public void test16() throws Throwable { simExpression("xXS<4.0",Boolean.FALSE,Boolean.TYPE,rtp,lib,null); } public void test17() throws Throwable { simExpression("x<4.0",Boolean.FALSE,Boolean.TYPE,rtp,lib,null); } public void test18() throws Throwable { simExpression("xX<4.0",Boolean.FALSE,Boolean.TYPE,rtp,lib,null); } public void test19() throws Throwable { simExpression("voidf(\"test\")",Void.TYPE,null,rtp,lib,null); } }; source/src/tests/gnu/jel/IntegralDowncastingTest.java0000644000175000017500000001471612714113765022031 0ustar olesoles/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * This file is part of the Java Expressions Library (JEL). * For more information about JEL visit : http://fti.dn.ua/JEL/ * * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2006, 2007, 2009 Konstantin L. Metlov * * 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 . */ package gnu.jel; import gnu.jel.tests.*; import java.io.PrintStream; import java.util.Stack; public class IntegralDowncastingTest extends TestingUtils { public IntegralDowncastingTest(String name) { super(name); } Library lib; Object[] rtp; VariableProvider vp; Class[] staticLib; Class[] dynamicLib; java.util.HashMap> allowedCasts; public void setUp() throws Exception { dynamicLib=new Class[1]; rtp=new Object[1]; vp=new VariableProvider(); staticLib=new Class[2]; staticLib[0]=Class.forName("java.lang.Math"); // next line makes also static functions from VariablePrivider available staticLib[1]=vp.getClass(); vp.xvar=5.0; vp.strVar="strVar"; rtp[0]=vp; dynamicLib[0]=vp.getClass(); Class[] dotLib=new Class[5]; dotLib[0]=Class.forName("java.lang.String"); dotLib[1]=Class.forName("java.lang.Double"); dotLib[2]=Class.forName("gnu.jel.reflect.Double"); dotLib[3]=IntegerObject.class; dotLib[4]=DoubleObject.class; vp.addProperty("p1","p1value"); vp.addProperty("p1.s1","p1s1value"); vp.addProperty("p1.s2","p1s2value"); vp.addProperty("p1.d1",VariableProvider.makeJELDoubleObject(1.0)); vp.addProperty("p1.s2.ss1","p1s2ss1value"); vp.addProperty("p1.b1t",VariableProvider.makeJELBooleanObject(true)); vp.addProperty("p1.b1f",VariableProvider.makeJELBooleanObject(false)); allowedCasts=new java.util.HashMap>(); allowedCasts.put("String",String.class); allowedCasts.put("Object",Object.class); allowedCasts.put("Double",java.lang.Double.class); lib=new Library(staticLib,dynamicLib,dotLib,vp,allowedCasts); } public void test1() throws Throwable { simExpression("(Double)((Object)valDoubleObj)",new Double(1.0), null, rtp, lib,null); } public void test2() throws Throwable { simExpression("((String)((Object)\"abc\")).length",new Integer(3), null, rtp, lib,null); } public void test3() throws Throwable { // as per Kumar Pandya's request allowedCasts.put("a1.a2.Strin",String.class); allowedCasts.put("a2.a3.Objec",Object.class); allowedCasts.put("a3.a4.Doubl",java.lang.Double.class); simExpression("(a3.a4.Doubl)((a2.a3.Objec)valDoubleObj)",new Double(1.0), null, rtp, lib,null); simExpression("((a1.a2.Strin)((a2.a3.Objec)\"abc\")).length",new Integer(3), null, rtp, lib,null); } public void test4() throws Throwable { // Test case for a bug submitted by Dave Ekhaus for(int i=0;i<8;i++) { Class[] newDynamicLib=new Class[dynamicLib.length+1]; Object[] newRTP=new Object[rtp.length+1]; System.arraycopy(dynamicLib,0,newDynamicLib,0,dynamicLib.length); System.arraycopy(rtp,0,newRTP,0,rtp.length); switch(i) { case 0: newRTP[newRTP.length-1]=VariableProvider.makeJELBooleanObject(false); break; case 1: newRTP[newRTP.length-1]=VariableProvider.makeJELByteObject((byte)55); break; case 2: newRTP[newRTP.length-1]=VariableProvider.makeJELCharacterObject(' '); break; case 3: newRTP[newRTP.length-1]= VariableProvider.makeJELShortObject((short)55); break; case 4: newRTP[newRTP.length-1]=VariableProvider.makeJELIntegerObject(55); break; case 5: newRTP[newRTP.length-1]=VariableProvider.makeJELLongObject(55); break; case 6: newRTP[newRTP.length-1]=VariableProvider.makeJELFloatObject(55); break; case 7: newRTP[newRTP.length-1]=VariableProvider.makeJELDoubleObject(55); break; default: }; newDynamicLib[newDynamicLib.length-1]= newRTP[newRTP.length-1].getClass(); Library lib1=new Library(staticLib,newDynamicLib,new Class[0],vp,null); simExpression("aMethod", new Integer(1),null,newRTP,lib1,null); }; } public void test5() throws Throwable { // Check transmittance of unwrappable objects String[] typeNames={"Boolean","Byte","Character","Short","Integer", "Long","Float","Double"}; for(int k=0;k<8;k++) { String fname="val"+typeNames[k]+"JELObj"; Object res=null; try { res=VariableProvider.class.getField(fname).get(vp); } catch(Exception e) { System.out.println(e); System.exit(1); }; simExpression(fname,res,null,rtp,lib,null); }; }; public void test6() throws Throwable { simExpression("valString",new StringObject("strObj"), null, rtp, lib, null); } public void test7() throws Throwable { simExpression("valString+\"_ttt\"","strObj_ttt", null, rtp, lib, null); } public void test8() throws Throwable { simExpression("\"ttt_\"+valString+\"_ttt\"","ttt_strObj_ttt", null, rtp, lib, null); } public void test9() throws Throwable { simExpression("append_ttt(\"strObj\")+\"_ttt\"","strObj_ttt_ttt", null, rtp, lib, null); } public void test10() throws Throwable { simExpression("append_ttt(valString)+\"_ttt\"","strObj_ttt_ttt", null, rtp, lib, null); } public void test11() throws Throwable { simExpression("methodOnInt(valInteger)",new Integer(1), null, rtp, lib, null); } public void test12() throws Throwable { simExpression("methodOnInt(valIntegerJELObj)",new Integer(2), null, rtp, lib, null); } }; source/src/tests/gnu/jel/IntegralPrimitiveOPsTest.java0000644000175000017500000001107412714113765022135 0ustar olesoles/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * This file is part of the Java Expressions Library (JEL). * For more information about JEL visit : http://fti.dn.ua/JEL/ * * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2006, 2007, 2009 Konstantin L. Metlov * * 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 . */ package gnu.jel; import gnu.jel.tests.*; import java.io.PrintStream; import java.util.Stack; public class IntegralPrimitiveOPsTest extends TestingUtils { public IntegralPrimitiveOPsTest(String name) { super(name); } Library lib; Object[] rtp; VariableProvider vp; Class[] staticLib; Class[] dynamicLib; java.util.HashMap> allowedCasts; public void setUp() throws Exception { dynamicLib=new Class[1]; rtp=new Object[1]; vp=new VariableProvider(); staticLib=new Class[2]; staticLib[0]=Class.forName("java.lang.Math"); // next line makes also static functions from VariablePrivider available staticLib[1]=vp.getClass(); vp.xvar=5.0; vp.strVar="strVar"; rtp[0]=vp; dynamicLib[0]=vp.getClass(); Class[] dotLib=new Class[5]; dotLib[0]=Class.forName("java.lang.String"); dotLib[1]=Class.forName("java.lang.Double"); dotLib[2]=Class.forName("gnu.jel.reflect.Double"); dotLib[3]=IntegerObject.class; dotLib[4]=DoubleObject.class; vp.addProperty("p1","p1value"); vp.addProperty("p1.s1","p1s1value"); vp.addProperty("p1.s2","p1s2value"); vp.addProperty("p1.d1",VariableProvider.makeJELDoubleObject(1.0)); vp.addProperty("p1.s2.ss1","p1s2ss1value"); vp.addProperty("p1.b1t",VariableProvider.makeJELBooleanObject(true)); vp.addProperty("p1.b1f",VariableProvider.makeJELBooleanObject(false)); allowedCasts=new java.util.HashMap>(); allowedCasts.put("String",String.class); allowedCasts.put("Object",Object.class); allowedCasts.put("Double",java.lang.Double.class); lib=new Library(staticLib,dynamicLib,dotLib,vp,allowedCasts); } public void test1() throws Throwable { for(int k=0;k<2;k++) { String[][] prefixes={{"val","val","val"},{"arr","arr","arr"}}; String[][] suffixes={{"","Obj","JELObj"},{"[0]","Obj[0]","JELObj[0]"}}; testUnaryPrimitive(0,6,lib,rtp,-1,null,prefixes[k],suffixes[k]); // - testUnaryPrimitive(1,5,lib,rtp,0xFFFFFFFFFFFFFFFEL,null, prefixes[k],suffixes[k]); // ~ testUnaryPrimitive(2,1,lib,rtp,0,null,prefixes[k],suffixes[k]); // ! testBinaryPrimitive(0,45,lib,rtp,2,null,prefixes[k],suffixes[k]); // + testBinaryPrimitive(1,45,lib,rtp,0,null,prefixes[k],suffixes[k]); // - testBinaryPrimitive(2,45,lib,rtp,1,null,prefixes[k],suffixes[k]); // * testBinaryPrimitive(3,45,lib,rtp,1,null,prefixes[k],suffixes[k]); // / testBinaryPrimitive(4,45,lib,rtp,0,null,prefixes[k],suffixes[k]); // % testBinaryPrimitive(5,26,lib,rtp,1,null,prefixes[k],suffixes[k]); // & testBinaryPrimitive(6,26,lib,rtp,1,null,prefixes[k],suffixes[k]); // | testBinaryPrimitive(7,26,lib,rtp,0,null,prefixes[k],suffixes[k]); // ^ testBinaryPrimitive(8,46,lib,rtp,1,null,prefixes[k],suffixes[k]); // == testBinaryPrimitive(9,46,lib,rtp,0,null,prefixes[k],suffixes[k]); // != testBinaryPrimitive(10,45,lib,rtp,0,null,prefixes[k],suffixes[k]); // < testBinaryPrimitive(11,45,lib,rtp,1,null,prefixes[k],suffixes[k]); // >= testBinaryPrimitive(12,45,lib,rtp,0,null,prefixes[k],suffixes[k]); // > testBinaryPrimitive(13,45,lib,rtp,1,null,prefixes[k],suffixes[k]); // <= testBinaryPrimitive(14,25,lib,rtp,2,null,prefixes[k],suffixes[k]); // << testBinaryPrimitive(15,25,lib,rtp,0,null,prefixes[k],suffixes[k]); // >> testBinaryPrimitive(16,25,lib,rtp,0,null,prefixes[k],suffixes[k]); // >>> testBinaryPrimitive(17,1,lib,rtp,1,null,prefixes[k],suffixes[k]); // && testBinaryPrimitive(18,1,lib,rtp,1,null,prefixes[k],suffixes[k]); // || }; } }; source/src/tests/gnu/jel/tests/0000755000175000017500000000000012714113765015511 5ustar olesolessource/src/tests/gnu/jel/tests/ShortObject.java0000644000175000017500000000226412714113765020606 0ustar olesoles/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * This file is part of the Java Expressions Library (JEL). * For more information about JEL visit : http://fti.dn.ua/JEL/ * * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2006, 2007, 2009 Konstantin L. Metlov * * 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 . */ package gnu.jel.tests; public class ShortObject implements gnu.jel.reflect.Short { short val; public ShortObject(short val) { this.val=val; }; public short getValue() { return val; }; public int aMethod() { return 1; }; }; source/src/tests/gnu/jel/tests/BooleanObject.java0000644000175000017500000000230012714113765021055 0ustar olesoles/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * This file is part of the Java Expressions Library (JEL). * For more information about JEL visit : http://fti.dn.ua/JEL/ * * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2006, 2007, 2009 Konstantin L. Metlov * * 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 . */ package gnu.jel.tests; public class BooleanObject implements gnu.jel.reflect.Boolean { boolean val; public BooleanObject(boolean val) { this.val=val; }; public boolean getValue() { return val; }; public int aMethod() { return 1; }; }; source/src/tests/gnu/jel/tests/ByteObject.java0000644000175000017500000000225412714113765020411 0ustar olesoles/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * This file is part of the Java Expressions Library (JEL). * For more information about JEL visit : http://fti.dn.ua/JEL/ * * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2006, 2007, 2009 Konstantin L. Metlov * * 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 . */ package gnu.jel.tests; public class ByteObject implements gnu.jel.reflect.Byte { byte val; public ByteObject(byte val) { this.val=val; }; public byte getValue() { return val; }; public int aMethod() { return 1; }; }; source/src/tests/gnu/jel/tests/LongObject.java0000644000175000017500000000225612714113765020407 0ustar olesoles/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * This file is part of the Java Expressions Library (JEL). * For more information about JEL visit : http://fti.dn.ua/JEL/ * * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2006, 2007, 2009 Konstantin L. Metlov * * 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 . */ package gnu.jel.tests; public class LongObject implements gnu.jel.reflect.Long { long val; public LongObject(long val) { this.val=val; }; public long getValue() { return val; }; public int aMethod() { return 1; }; }; source/src/tests/gnu/jel/tests/FloatObject.java0000644000175000017500000000226412714113765020554 0ustar olesoles/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * This file is part of the Java Expressions Library (JEL). * For more information about JEL visit : http://fti.dn.ua/JEL/ * * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2006, 2007, 2009 Konstantin L. Metlov * * 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 . */ package gnu.jel.tests; public class FloatObject implements gnu.jel.reflect.Float { float val; public FloatObject(float val) { this.val=val; }; public float getValue() { return val; }; public int aMethod() { return 1; }; }; source/src/tests/gnu/jel/tests/StringObject.java0000644000175000017500000000251612714113765020755 0ustar olesoles/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * This file is part of the Java Expressions Library (JEL). * For more information about JEL visit : http://fti.dn.ua/JEL/ * * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2006, 2007, 2009 Konstantin L. Metlov * * 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 . */ package gnu.jel.tests; public class StringObject implements gnu.jel.reflect.String { String val; public StringObject(String val) { this.val=val; }; public int aMethod() { return 1; }; public boolean equals(Object obj) { if (!(obj instanceof StringObject)) return false; return val.equals(((StringObject)obj).val); }; public String toString() { return val; }; }; source/src/tests/gnu/jel/tests/VariableProvider.java0000644000175000017500000002407212714113765021621 0ustar olesoles/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * This file is part of the Java Expressions Library (JEL). * For more information about JEL visit : http://fti.dn.ua/JEL/ * * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2006, 2007, 2009 Konstantin L. Metlov * * 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 . */ package gnu.jel.tests; public class VariableProvider extends gnu.jel.DVMap { public Object anObject=new Object(); public double xvar; public String strVar; public double x() {return xvar;}; public static double xS() {return 5.3;}; public java.lang.Double xX() {return new java.lang.Double(xvar);}; public static java.lang.Double xXS() {return new java.lang.Double(5.3);}; // void testing func public void voidf(String s) { return; }; // --- Dynamic variables testing section private java.util.Hashtable properties= new java.util.Hashtable(); public gnu.jel.reflect.Double getDoubleProperty(String name) { return (gnu.jel.reflect.Double) properties.get(name); }; public DoubleObject getTSDoubleProperty(String name) { return (DoubleObject) properties.get(name); }; public gnu.jel.reflect.Boolean getBooleanProperty(String name) { return (gnu.jel.reflect.Boolean) properties.get(name); }; public String getStringProperty(String name) { return (String) properties.get(name); }; public void addProperty(String name, Object value) { properties.put(name,value); }; public String getTypeName(String name) { // this is for testing translated names if (name.startsWith("_T_")) return "String"; Object val=properties.get(name); if (val==null) return null; if (val instanceof String) return "String"; if (val.getClass()==DoubleObject.class) return "TSDouble"; if (val instanceof gnu.jel.reflect.Double) return "Double"; if (val instanceof gnu.jel.reflect.Boolean) return "Boolean"; //-------- FOR JULIA DUNPHY if (val instanceof double[]) return "DoubleArr"; //======== FOR JULIA DUNPHY return null; }; //-------- FOR JULIA DUNPHY public double[] getDoubleArrProperty(String name) { return (double[]) properties.get(name); }; //======== FOR JULIA DUNPHY // --- END OF (Dynamic variables testing section) public gnu.jel.reflect.Double[] arrDoubleJELObj1={ new DoubleObject(1.0), new DoubleObject(2.0) }; public double[] arr; public double[][] aarr={{1.0,2.0},{3.0,4.0}}; public java.lang.Double[][] aarrDouble={{new Double(1.0),new Double(2.0)}, {new Double(3.0),new Double(4.0)}}; public gnu.jel.reflect.Integer intObj; public gnu.jel.reflect.Byte byteObj; public static final double[] arrs={1.0,2.0,3.0}; public VariableProvider() { arr=new double[3]; arr[0]=4.0; arr[1]=5.0; arr[2]=6.0; intObj=new IntegerObject(555); byteObj=new ByteObject((byte)2); }; public static int throw_arg_eq_4(int x) throws Exception { if (x==4) throw new Exception("An exception from testsuite."); return 0; }; public static int bool2int(boolean b) { if (b) return 1; else return 0; }; public static float NaNf() { return Float.NaN; }; public static double NaNd() { return Double.NaN; }; public static Double makeDoubleObject(double d) { return new Double(d); }; public boolean[] arrBoolean={true}; public byte[] arrByte={(byte)1}; public char[] arrCharacter={(char)1}; public short[] arrShort={(short)1}; public int[] arrInteger={1}; public long[] arrLong={1}; public float[] arrFloat={(float)1.0}; public double[] arrDouble={1.0}; public java.lang.Boolean[] arrBooleanObj={new java.lang.Boolean(true)}; public java.lang.Byte[] arrByteObj={new java.lang.Byte((byte)1)}; public java.lang.Character[] arrCharacterObj= {new java.lang.Character((char)1)}; public java.lang.Short[] arrShortObj={new java.lang.Short((short)1)}; public java.lang.Integer[] arrIntegerObj={new java.lang.Integer(1)}; public java.lang.Long[] arrLongObj={new java.lang.Long(1)}; public java.lang.Float[] arrFloatObj={new java.lang.Float((float)1.0)}; public java.lang.Double[] arrDoubleObj={new java.lang.Double(1.0)}; public gnu.jel.reflect.Boolean[] arrBooleanJELObj={new BooleanObject(true)}; public gnu.jel.reflect.Byte[] arrByteJELObj={new ByteObject((byte)1)}; public gnu.jel.reflect.Character[] arrCharacterJELObj= {new CharacterObject((char)1)}; public gnu.jel.reflect.Short[] arrShortJELObj={new ShortObject((short)1)}; public gnu.jel.reflect.Integer[] arrIntegerJELObj={new IntegerObject(1)}; public gnu.jel.reflect.Long[] arrLongJELObj={new LongObject(1)}; public gnu.jel.reflect.Float[] arrFloatJELObj={new FloatObject((float)1.0)}; public gnu.jel.reflect.Double[] arrDoubleJELObj={new DoubleObject(1.0)}; public boolean valBoolean=true; public byte valByte=(byte)1; public char valCharacter=(char)1; public short valShort=(short)1; public int valInteger=1; public long valLong=1; public float valFloat=(float)1.0; public double valDouble=1.0; public StringObject valString=new StringObject("strObj"); public java.lang.Boolean valBooleanObj=new java.lang.Boolean(true); public java.lang.Byte valByteObj=new java.lang.Byte((byte)1); public java.lang.Character valCharacterObj=new java.lang.Character((char)1); public java.lang.Short valShortObj=new java.lang.Short((short)1); public java.lang.Integer valIntegerObj=new java.lang.Integer(1); public java.lang.Long valLongObj=new java.lang.Long(1); public java.lang.Float valFloatObj=new java.lang.Float((float)1.0); public java.lang.Double valDoubleObj=new java.lang.Double(1.0); public gnu.jel.reflect.Boolean valBooleanJELObj=new BooleanObject(true); public gnu.jel.reflect.Byte valByteJELObj=new ByteObject((byte)1); public gnu.jel.reflect.Character valCharacterJELObj=new CharacterObject((char)1); public gnu.jel.reflect.Short valShortJELObj=new ShortObject((short)1); public gnu.jel.reflect.Integer valIntegerJELObj=new IntegerObject(1); public gnu.jel.reflect.Long valLongJELObj=new LongObject(1); public gnu.jel.reflect.Float valFloatJELObj=new FloatObject((float)1.0); public gnu.jel.reflect.Double valDoubleJELObj=new DoubleObject(1.0); public static boolean isNullDouble(java.lang.Double d) { return d==null; }; public static java.lang.Double getDoubleNull() { return null; }; public static int convertNumberToInt(Number n) { return n.intValue(); }; public static int addNumbersInt(Number n1,Number n2) { return n1.intValue()+n2.intValue(); }; public static double convertNumberToDouble(Number n) { return n.doubleValue(); }; public static double addNumbersDbl(Number n1,Number n2) { return n1.doubleValue()+n2.doubleValue(); }; public static gnu.jel.reflect.Boolean makeJELBooleanObject(boolean b) { return new BooleanObject(b); }; public static gnu.jel.reflect.Byte makeJELByteObject(byte v) { return new ByteObject(v); }; public static gnu.jel.reflect.Character makeJELCharacterObject(char v) { return new CharacterObject(v); }; public static gnu.jel.reflect.Short makeJELShortObject(short v) { return new ShortObject(v); }; public static IntegerObject makeJELIntegerObject(int v) { return new IntegerObject(v); }; public static gnu.jel.reflect.Long makeJELLongObject(long v) { return new LongObject(v); }; public static gnu.jel.reflect.Float makeJELFloatObject(float v) { return new FloatObject(v); }; public static gnu.jel.reflect.Double makeJELDoubleObject(double d) { return new DoubleObject(d); }; // next two methods test overloading of unwrappable types public static int methodOnInt(int i) { return i; }; public static int methodOnInt(gnu.jel.reflect.Integer iobj) { return iobj.getValue()+1; }; public static String append_ttt(String str) { return str+"_ttt"; }; public Object translate(String name) { if (name.startsWith("_T_")) { // this is for testing translated names return new Integer(name.charAt(3)-'a'); } else return name; }; public String getStringProperty(int num) { char lett=(char)('a'+num); return "_U_"+lett; }; // varargs testing functions public static int sum(int[] args) { int s=0; for (int i=0;i. */ package gnu.jel.tests; public class DoubleObject implements gnu.jel.reflect.Double { double val; public DoubleObject(double val) { this.val=val; }; public double getValue() { return val; }; public int aMethod() { return 1; }; }; source/src/tests/gnu/jel/tests/CharacterObject.java0000644000175000017500000000227512714113765021405 0ustar olesoles/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * This file is part of the Java Expressions Library (JEL). * For more information about JEL visit : http://fti.dn.ua/JEL/ * * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2006, 2007, 2009 Konstantin L. Metlov * * 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 . */ package gnu.jel.tests; public class CharacterObject implements gnu.jel.reflect.Character { char val; public CharacterObject(char val) { this.val=val; }; public char getValue() { return val; }; public int aMethod() { return 1; }; }; source/src/tests/gnu/jel/tests/IntegerObject.java0000644000175000017500000000237412714113765021106 0ustar olesoles/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * This file is part of the Java Expressions Library (JEL). * For more information about JEL visit : http://fti.dn.ua/JEL/ * * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2006, 2007, 2009 Konstantin L. Metlov * * 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 . */ package gnu.jel.tests; public class IntegerObject implements gnu.jel.reflect.Integer { int val; public IntegerObject(int val) { this.val=val; }; public int getValue() { return val; }; public int aMethod() { return 1; }; public String getStringProperty(String name) { return name; }; }; source/src/tests/gnu/jel/IntegralBoxUnboxTest.java0000644000175000017500000000577312714113765021320 0ustar olesoles/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * This file is part of the Java Expressions Library (JEL). * * (c) 1998 -- 2016 by Konstantin L. Metlov * * JEL is Distributed under the terms of GNU General Public License. * This code comes with ABSOLUTELY NO WARRANTY. * For license details see COPYING file in this directory. */ package gnu.jel; import gnu.jel.tests.*; import java.io.PrintStream; import java.util.Stack; public class IntegralBoxUnboxTest extends TestingUtils { public IntegralBoxUnboxTest(String name) { super(name); } Library lib; Object[] rtp; VariableProvider vp; public void setUp() throws Exception { Class[] dynamicLib=new Class[1]; rtp=new Object[1]; vp=new VariableProvider(); Class[] staticLib=new Class[2]; staticLib[0]=Class.forName("java.lang.Math"); // next line makes also static functions from VariablePrivider available staticLib[1]=vp.getClass(); vp.xvar=5.0; vp.strVar="strVar"; rtp[0]=vp; dynamicLib[0]=vp.getClass(); lib=new Library(staticLib,dynamicLib,null,null,null); } public void test1() throws Throwable { simExpression("Not(false)",new Boolean(true),null,rtp,lib,null); } public void test2() throws Throwable { simExpression("NextByte(1)",new Byte((byte)2),null,rtp,lib,null); } public void test3() throws Throwable { simExpression("NextChar('A')",new Character('B'),null,rtp,lib,null); } public void test4() throws Throwable { simExpression("NextShort(2)",new Short((short)3),null,rtp,lib,null); } public void test5() throws Throwable { simExpression("NextInteger(3)",new Integer(4),null,rtp,lib,null); } public void test6() throws Throwable { simExpression("NextLong(4)",new Long(5),null,rtp,lib,null); } public void test7() throws Throwable { simExpression("NextFloat((float)5.0)",new Float(6.0),null,rtp,lib,null); } public void test8() throws Throwable { simExpression("NextDouble(6.0)",new Double(7.0),null,rtp,lib,null); } public void test9() throws Throwable { simExpression("NextInteger(2+3)",new Integer(6),null,rtp,lib,null); } public void test10() throws Throwable { simExpression("NextLong(makeJELLongObject(4))",new Long(5),null,rtp,lib,null); } public void test11() throws Throwable { simExpression("NextInteger(makeJELIntegerObject(3))",new Integer(4),null,rtp,lib,null); } public void test12() throws Throwable { simExpression("NextInteger(makeJELIntegerObject(3)+1)",new Integer(5),null,rtp,lib,null); } public void test13() throws Throwable { simExpression("NextInteger(makeJELIntegerObject(makeJELIntegerObject(3)+1))", new Integer(5),null,rtp,lib,null); } public void test14() throws Throwable { simExpression("addNumbersInt(2,3)", new Integer(5),null,rtp,lib,null); } public void test15() throws Throwable { simExpression("addNumbersDbl(2,3.5)", new Double(5.5),null,rtp,lib,null); } }; source/src/tests/gnu/jel/IntegralDotOperatorTest.java0000644000175000017500000001024612714113765022005 0ustar olesoles/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * This file is part of the Java Expressions Library (JEL). * For more information about JEL visit : http://fti.dn.ua/JEL/ * * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2006, 2007, 2009 Konstantin L. Metlov * * 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 . */ package gnu.jel; import gnu.jel.tests.*; import java.io.PrintStream; import java.util.Stack; public class IntegralDotOperatorTest extends TestingUtils { public IntegralDotOperatorTest(String name) { super(name); } Library lib; Object[] rtp; VariableProvider vp; public void setUp() throws Exception { Class[] dynamicLib=new Class[1]; rtp=new Object[1]; vp=new VariableProvider(); Class[] staticLib=new Class[2]; staticLib[0]=Class.forName("java.lang.Math"); // next line makes also static functions from VariablePrivider available staticLib[1]=vp.getClass(); vp.xvar=5.0; vp.strVar="strVar"; rtp[0]=vp; dynamicLib[0]=vp.getClass(); Class[] dotLib=new Class[5]; dotLib[0]=Class.forName("java.lang.String"); dotLib[1]=Class.forName("java.lang.Double"); dotLib[2]=Class.forName("gnu.jel.reflect.Double"); dotLib[3]=IntegerObject.class; dotLib[4]=DoubleObject.class; lib=new Library(staticLib,dynamicLib,dotLib,null,null); } public void test1() throws Throwable { simExpression("(\"abc\").length()", new Integer(3), null, rtp, lib,null); } public void test2() throws Throwable { simExpression("\"abc\".length()", new Integer(3), null, rtp, lib,null); } public void test3() throws Throwable { simExpression("strVar.length()", new Integer(6), null, rtp, lib,null); } public void test4() throws Throwable { simExpression("\"abc\".endsWith(\"bc\")", Boolean.TRUE, null, rtp, lib,null); } public void test5() throws Throwable { simExpression("\"abc\".compareTo(\"bc\")", new Integer(-1), null, rtp, lib,null); } public void test6() throws Throwable { simExpression("\"abcdbc\".indexOf(\"bc\")", new Integer(1), null, rtp, lib,null); } public void test7() throws Throwable { simExpression("\"abcdbc\".indexOf(\"abc\".substring(1),2)", new Integer(4), null, rtp, lib,null); } public void test8() throws Throwable { simError("\"abc\".nomethod()",null,lib,7,null); } public void test9() throws Throwable { simError("\"abc\".length(666)",null,lib,7,null); } public void test10() throws Throwable { simError("2.0.doubleValue()",null,lib,4,null); } public void test11() throws Throwable { simExpression("intObj+1", new Integer(556), null, rtp, lib,null); } public void test12() throws Throwable { simExpression("(int)intObj", new Integer(555), null, rtp, lib,null); } public void test13() throws Throwable { simExpression("arr[intObj-554]", new Double(5.0), null, rtp, lib,null); } public void test14() throws Throwable { simExpression("arr[max(intObj-554,0)]", new Double(5.0), null, rtp, lib,null); } public void test15() throws Throwable { simExpression("arr[max(intObj,0)-554]", new Double(5.0), null, rtp, lib,null); } public void test16() throws Throwable { simExpression("arr[byteObj]", new Double(6.0), null, rtp, lib,null); } public void test17() throws Throwable { simExpression("byteObj+1.0", new Double(3.0), null, rtp, lib,null); } public void test18() throws Throwable { simExpression("arrDoubleJELObj1[0].getValue()+"+ "arrDoubleJELObj1[1].getValue()", new Double(3.0), null, rtp, lib,null); } }; source/src/tests/gnu/jel/IntegralVarargsTest.java0000644000175000017500000000361412714113765021151 0ustar olesoles/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * $Id: TestSuite.java,v 1.47 2004/03/16 15:51:25 metlov Exp $ * * This file is part of the Java Expressions Library (JEL). * * (c) 1998 -- 2016 by Konstantin L. Metlov * * JEL is Distributed under the terms of GNU General Public License. * This code comes with ABSOLUTELY NO WARRANTY. * For license details see COPYING file in this directory. */ package gnu.jel; import gnu.jel.tests.*; import java.io.PrintStream; import java.util.Stack; public class IntegralVarargsTest extends TestingUtils { public IntegralVarargsTest(String name) { super(name); } Library lib; Object[] rtp; VariableProvider vp; public void setUp() throws Exception { Class[] dynamicLib=new Class[1]; rtp=new Object[1]; vp=new VariableProvider(); Class[] staticLib=new Class[2]; staticLib[0]=Class.forName("java.lang.Math"); // next line makes also static functions from VariablePrivider available staticLib[1]=vp.getClass(); vp.xvar=5.0; vp.strVar="strVar"; rtp[0]=vp; dynamicLib[0]=vp.getClass(); lib=new Library(staticLib,dynamicLib,null,null,null); } public void test1() throws Throwable { simExpression("sum(arrInteger)",new Integer(1),Integer.TYPE,rtp,lib,null); } public void test2() throws Throwable { simExpression("sum(1)",new Integer(1),Integer.TYPE,rtp,lib,null); } public void test3() throws Throwable { simExpression("sum(1,2)",new Integer(3),Integer.TYPE,rtp,lib,null); } public void test4() throws Throwable { simExpression("powersum(1,arrDouble)",new Double(1),Double.TYPE,rtp,lib,null); } public void test5() throws Throwable { simExpression("powersum(1,1)",new Double(1),Double.TYPE,rtp,lib,null); } public void test6() throws Throwable { simExpression("powersum(2,1,2)",new Double(5),Double.TYPE,rtp,lib,null); } }; source/src/tests/gnu/jel/IntegerStackTest.java0000644000175000017500000000473212714113765020443 0ustar olesoles/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * This file is part of the Java Expressions Library (JEL). * For more information about JEL visit : http://fti.dn.ua/JEL/ * * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2006, 2007, 2009 Konstantin L. Metlov * * 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 . */ package gnu.jel; import junit.framework.TestCase; import java.io.StringReader; import java.lang.reflect.Method; public class IntegerStackTest extends TestCase { public IntegerStackTest(String name) { super(name); } public void setUp() throws Exception { } public void tearDown() throws Exception { } public void testPush() throws Exception { IntegerStack is=new IntegerStack(1); is.push(10); assertTrue(true); } public void testPeekPop() throws Exception { IntegerStack is=new IntegerStack(1); is.push(10); assertEquals(10,is.peek()); assertEquals(10,is.pop()); } public void testP3PeekP3() throws Exception { IntegerStack is=new IntegerStack(1); is.push(10); is.push(11); assertEquals(11,is.peek()); is.push(12); assertEquals(12,is.peek()); assertEquals(12,is.pop()); assertEquals(11,is.pop()); assertEquals(10,is.pop()); assertEquals(0,is.size()); } public void testSwap() throws Exception { IntegerStack is1 = new IntegerStack(1); is1.push(10); is1.push(11); is1.push(12); is1.push(13); IntegerStack is2 = new IntegerStack(1); is2.push(0); is2.push(1); is2.push(2); is2.push(3); IntegerStack.swap(is1,3,is2,1); // 10,11,12,3,2,1 // 0,13 assertEquals(1,is1.pop()); assertEquals(2,is1.pop()); assertEquals(3,is1.pop()); assertEquals(12,is1.pop()); assertEquals(11,is1.pop()); assertEquals(10,is1.pop()); assertEquals(13,is2.pop()); assertEquals(0,is2.pop()); }; } source/src/tests/gnu/jel/ClassFileExprTest.java0000644000175000017500000006351212714113765020565 0ustar olesoles/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * This file is part of the Java Expressions Library (JEL). * For more information about JEL visit : http://fti.dn.ua/JEL/ * * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2006, 2007, 2009 Konstantin L. Metlov * * 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 . */ package gnu.jel; import junit.framework.TestCase; import java.io.StringReader; import java.lang.reflect.Method; import java.lang.reflect.Member; import java.lang.reflect.Constructor; import java.util.Stack; public class ClassFileExprTest extends TestCase { public ClassFileExprTest(String name) { super(name); } ClassFile cf; Library lib; Object[] dynalib; byte[] image; LocalMethod[] eval_methods; ClassFile cf_orig; int retID_patchback; public void setUp() throws Exception { LocalField[] lf=new LocalField[1]; // private Object[] e; lf[0]=new LocalField(0x0002,(new Object[0]).getClass(),"e",null); // cf = new ClassFile(0x0001,"dump",(new Object()).getClass(),null,lf); Class[] stat=new Class[1]; stat[0]=Class.forName("java.lang.Math"); Class[] dyn=new Class[1]; dyn[0]=Class.forName("java.lang.Double"); lib=new Library(stat,dyn,null,null,null); dynalib=new Object[1]; dynalib[0]=new Double(100.0); image=null; final int numPrimitives=10; // up to Void eval_methods=new LocalMethod[numPrimitives]; cf_orig=null; retID_patchback=0; // prepare eval methods Class[] paramsE=new Class[1]; paramsE[0]=(new Object[0]).getClass(); for(int i=0;i cls=OP.specialTypes[i]; if (i!=8) name=name+'_'+cls; else cls=(new Object()).getClass(); eval_methods[i]=new LocalMethod(0x0001,cls,name,paramsE,null); }; // hand-compile a class template Class cmplExpr=Class.forName("gnu.jel.CompiledExpression"); cf=new ClassFile(0x0001,"dump",cmplExpr,null,lf); // public LocalMethod cnstr= new LocalMethod(0x0001,Void.TYPE,"",null,null); cf.newMethod(cnstr,null); cf.code(0x2a); //| aload_0 ;loads "this" cf.noteStk(-1,11); // not important what, it must be a reference Constructor supInit=cmplExpr.getConstructor(new Class[0]); cf.code(0xb7); //| invokespecial cf.writeShort(cf.getIndex(supInit,11)); //| super(); cf.noteStk(11,-1); cf.code(0xb1); //| return void LocalMethod getType= new LocalMethod(0x0001,Integer.TYPE,"getType",null,null); cf.newMethod(getType,null); cf.code(0x10); //| bipush retID_patchback=cf.tsize; cf.code(8); // type placeholder cf.noteStk(-1,4); // note "int" cf.code(0xAC); //| ireturn cf.noteStk(4,-1); // rm "int" cf_orig=cf.clone(); cf.newMethod(eval_methods[8],null); cf.code(0x01); //| aconst_null cf.noteStk(-1,11); // not important what, it must be a reference cf.code(0xB0); //| areturn cf.noteStk(11,-1); image=cf.getImage(); } public void tearDown() throws Exception { } public void testExecTemplate() throws Throwable { CompiledExpression expr= (CompiledExpression)(ImageLoader.load(image)).newInstance(); boolean ok=((expr.getType()==8) && (expr.evaluate(null)==null)); assertTrue(ok); } public void testExpr1() throws Throwable { exprMiniComp("1 (I)",dynalib,lib,new Integer(1), cf_orig,retID_patchback,eval_methods,false); }; public void testExpr2() throws Throwable { exprMiniComp("1 (I)",dynalib,lib,new Integer(1), cf_orig,retID_patchback,eval_methods,false); }; public void testExpr3() throws Throwable { exprMiniComp("1 -- (I)",dynalib,lib,new Integer(-1), cf_orig,retID_patchback,eval_methods,false); }; // Passing constants of primitive types. // this also tests shortcut commands for loading some integer // and floating point constants public void testExpr4() throws Throwable { exprMiniComp("1 --",dynalib,lib,new Integer((byte)-1), cf_orig,retID_patchback,eval_methods,false); }; public void testExpr5() throws Throwable { exprMiniComp("1L --",dynalib,lib,new Long(-1), cf_orig,retID_patchback,eval_methods,false); }; public void testExpr6() throws Throwable { for(byte i=0;i<=6;i++) { exprMiniComp(String.valueOf(i),dynalib,lib,new Byte(i), cf_orig,retID_patchback,eval_methods,false); exprMiniComp(String.valueOf(i)+'L',dynalib,lib,new Long(i), cf_orig,retID_patchback,eval_methods,false); }; }; public void testExpr7() throws Throwable { for(byte i=0;i<=3;i++) { exprMiniComp(String.valueOf(i)+".0F",dynalib,lib,new Float(i), cf_orig,retID_patchback,eval_methods,false); exprMiniComp(String.valueOf(i)+".0",dynalib,lib,new Double(i), cf_orig,retID_patchback,eval_methods,false); }; }; public void testExpr8() throws Throwable { exprMiniComp("true",dynalib,lib,Boolean.TRUE, cf_orig,retID_patchback,eval_methods,false); }; public void testExpr9() throws Throwable { exprMiniComp("false",dynalib,lib,Boolean.FALSE, cf_orig,retID_patchback,eval_methods,false); }; // this tests immediate byte constants loading (1 byte in the code) // and loading through the CP. public void testExpr10() throws Throwable { for(int i=126;i<=128;i++) { exprMiniComp(String.valueOf(i)+" (I)",dynalib,lib,new Integer(i), cf_orig,retID_patchback,eval_methods,false); exprMiniComp(String.valueOf(i)+" -- (I)",dynalib,lib,new Integer(-i), cf_orig,retID_patchback,eval_methods,false); }; }; public void testExpr11() throws Throwable { exprMiniComp("( 1 , 2 , min)",dynalib,lib,new Integer(1), cf_orig,retID_patchback,eval_methods,false); }; public void testExpr12() throws Throwable { exprMiniComp("( ( E) , sin)",dynalib,lib,new Double(Math.sin(Math.E)), cf_orig,retID_patchback,eval_methods,false); }; public void testExpr13() throws Throwable { exprMiniComp("2 , 2 , *",dynalib,lib,new Integer(4), cf_orig,retID_patchback,eval_methods,false); }; public void testExpr14() throws Throwable { exprMiniComp("3 , 2 , * , 1 , -",dynalib,lib,new Integer(5), cf_orig,retID_patchback,eval_methods,false); }; public void testExpr15() throws Throwable { exprMiniComp("3 , 2 , * , 1 , - , 3 , - , 2 , *",dynalib,lib, new Integer(4), cf_orig,retID_patchback,eval_methods,false); }; public void testExpr16() throws Throwable { exprMiniComp("3 , 2 , * , 1 , - , 3 , - , 2 , * , 4 , ==",dynalib,lib, Boolean.TRUE, cf_orig,retID_patchback,eval_methods,false); }; public void testExpr17() throws Throwable { exprMiniComp("\"a\" , \"b\" , + , 4 , + , true , +",dynalib,lib, "ab4true", cf_orig,retID_patchback,eval_methods,false); }; public void testExpr18() throws Throwable { exprMiniComp("2 , 3 , > , 3 , 2 , >= , ||",dynalib,lib, Boolean.TRUE, cf_orig,retID_patchback,eval_methods,false); }; public void testExpr19() throws Throwable { exprMiniComp("( isNaN)",dynalib,lib, Boolean.FALSE, cf_orig,retID_patchback,eval_methods,false); }; public void testExpr20() throws Throwable { exprMiniComp("1 , ( doubleValue) , + , 101 , ==",dynalib,lib, Boolean.TRUE, cf_orig,retID_patchback,eval_methods,false); }; public void testExpr21() throws Throwable { exprMiniComp("( true ? 1 : 2 ) (I)",dynalib,lib, new Integer(1), cf_orig,retID_patchback,eval_methods,false); }; public void testExpr22() throws Throwable { exprMiniComp("( false ? 1 : 2 ) (I)",dynalib,lib, new Integer(2), cf_orig,retID_patchback,eval_methods,false); }; public void testExpr23() throws Throwable { exprMiniComp("( false ? 1 : 2 , 2 , + ) (I)",dynalib,lib, new Integer(4), cf_orig,retID_patchback,eval_methods,false); }; public void testExpr24() throws Throwable { exprMiniComp("( true ? ( 1 , 3 , + , 5 , min) : 2 ) (I)",dynalib,lib, new Integer(4), cf_orig,retID_patchback,eval_methods,false); }; private static void exprMiniComp(String expr, Object[] thisPtrs, Library lib, Object expRes, ClassFile cf_orig, int retID_patchback, LocalMethod[] eval_methods, boolean verbose) throws Throwable { StringBuffer testTitle=new StringBuffer(); { for(int i=0;i9?'L':"ZBCSIJFDLV".charAt(id)); } else if (expRes instanceof String) { testTitle.append('"'); testTitle.append(expRes); testTitle.append('"'); } else testTitle.append(expRes); } // this.setName(testTitle.toString()); Stack paramOPs=new Stack(); IntegerStack paramsStart=new IntegerStack(); // Stack oldLists=new Stack(); IntegerStack branchStack=new IntegerStack(); OP cop; StringReader sr=new StringReader(expr); StringBuffer cToken=new StringBuffer(); int cChar; while ((cChar=sr.read())>0) { // skip whitespace while ((((char)cChar)==' ') && ((cChar=sr.read())>0)); // get the next token cToken.setLength(0); // clear the last token while ((cChar>0) && (((char)cChar)!=' ')) { cToken.append((char) cChar); cChar=sr.read(); }; if (cToken.length()>0) { // single symbol token char cTok=cToken.charAt(0); switch (cTok) { case '~': paramOPs.push(new OPunary(paramOPs,1)); break; case ',': // paramOPs.push(list.getLast()); break; case '(': // can be type conversion or function if (cToken.length()==1) { // function paramsStart.push(paramOPs.size()); } else if (cToken.length()==3) { // type conversion char ttype=cToken.charAt(1); int tid; char[] primitiveCodes= {'Z','B','C','S', 'I','J','F','D','L','V','L', 'L'}; for(tid=0;(tid': if (cToken.length()==1) { paramOPs.push(new OPbinary(paramOPs,11)); } else if ((cToken.length()==2) && (cToken.charAt(1)=='=')) { paramOPs.push(new OPbinary(paramOPs,12)); } else if ((cToken.length()==2) && (cToken.charAt(1)=='>')) { paramOPs.push(new OPbinary(paramOPs,15)); } else if ((cToken.length()==3) && (cToken.charAt(2)=='>')) { paramOPs.push(new OPbinary(paramOPs,16)); } else System.err.println("Wrong > token \""+cTok+"\"."); break; case '&': if (cToken.length()==1) { paramOPs.push(new OPbinary(paramOPs,5)); } else if ((cToken.length()==3) && (cToken.charAt(1)=='&')) { paramOPs.push(new OPbinary(paramOPs,17)); } else System.err.println("Wrong & token \""+cTok+"\"."); break; case '|': if (cToken.length()==1) { paramOPs.push(new OPbinary(paramOPs,6)); } else if ((cToken.length()==2) && (cToken.charAt(1)=='|')) { paramOPs.push(new OPbinary(paramOPs,18)); } else System.err.println("Wrong | token \""+cTok+"\"."); break; case '[': if ((cToken.length()==3) && (cToken.charAt(1)==']')) paramOPs.push(new OPbinary(paramOPs,19)); else System.err.println("Wrong [ token \""+cTok+"\"."); break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': // numbers { String sval=cToken.toString(); if (sval.indexOf('.')>0) { // Floating point literals char lc=Character.toUpperCase(sval.charAt(sval.length()-1)); boolean makeFloat = (lc=='F'); String svalue=sval; if ((lc=='D') || (lc=='F')) { svalue=svalue.substring(0,svalue.length()-1); }; Double value=null; try { value=new Double(svalue); } catch (NumberFormatException e) { System.err.println("Can;t parse \""+svalue+ "\" as a floating point number."); }; Object otl=null; Class otlc=null; if (makeFloat) { otl=new Float(value.floatValue()); otlc=Float.TYPE; } else { otl=value; otlc=Double.TYPE; }; paramOPs.push(new OPload(otl)); } else { // integer literals String svalue=sval.toUpperCase(); long value=0; boolean makelong=svalue.endsWith("L"); if (makelong) svalue=svalue.substring(0,svalue.length()-1); try { if ( svalue.startsWith("0X") ) { // Hexadecimal number svalue=svalue.substring(2); value=Long.parseLong(svalue,16); } else if (svalue.startsWith("0")) { // Octal number value=Long.parseLong(svalue,8); } else { // Decimal number value=Long.parseLong(svalue,10); }; } catch (NumberFormatException e) { System.err.println("Number \""+svalue+ "\" is too large, it does not fit even "+ "into 64 bit long."); // Overflow ? }; Object otl=null; Class otlc=null; if (!makelong) { // Check ranges if (value<=127) { otl=new Byte((byte)value); otlc=Byte.TYPE; } else if (value<=32767) { otl=new Short((short)value); otlc=Short.TYPE; } else if (value<=2147483647) { otl=new Integer((int)value); otlc=Integer.TYPE; } else System.err.println("Integer number \""+svalue+ "\" is too large for type 'int'. Be sure"+ " to add 'L' suffix to use 'long' type."); } else { otl=new Long(value); otlc=Long.TYPE; }; paramOPs.push(new OPload(otl)); }; }; break; case '\'': // char token { String sval=cToken.toString().substring(1,cToken.length()-1); char chr=sval.charAt(0); if (sval.length()!=1) { // escape or number char ec=sval.charAt(1); try { switch (ec) { case 'n': ec='\n'; break; case 't': ec='\t'; break; case 'b': ec='\b'; break; case 'r': ec='\r'; break; case 'f': ec='\f'; break; case '\\': ec='\\'; break; case '\'': ec='\''; break; case '\"': ec='"'; break; default: ec=(char) Integer.parseInt(sval.substring(1),8); }; } catch (NumberFormatException e) { System.err.println("Can;t parse \""+cToken+ "\" as a character literal."); }; chr=ec; }; paramOPs.push(new OPload(new Character(chr))); }; break; case '"': { String sval=cToken.toString().substring(1,cToken.length()-1); StringBuffer unescaped=new StringBuffer(sval.length()); for(int i=0;i='0') && (ec<='7')) { nval=nval<<3+(ec-'0'); i++; }; i--; ec=(char)nval; }; }; unescaped.append(ec); }; paramOPs.push(new OPload(unescaped.toString())); }; break; default: // function names { if (cToken.toString().equals("true") ) paramOPs.push(new OPload(Boolean.TRUE)); else if (cToken.toString().equals("false")) paramOPs.push(new OPload(Boolean.FALSE)); else { // strip bracket from the name cToken.setLength(cToken.length()-1); // collect params int ps=paramsStart.pop(); int np=paramOPs.size()-ps; Class[] params=new Class[np]; OP[] paramsOPs=new OP[np]; for(int i=np-1;i>=0;i--) { paramsOPs[i]=paramOPs.pop(); params[i]=paramsOPs[i].resType; }; // find method Member m=null; try { m=lib.getMember(null,cToken.toString(),params); } catch (CompilationException exc) { System.err.println("Can't find method \""+cToken+"\"."); }; // put "this" pointer in place if ((m.getModifiers() & 0x0008)==0) { // insert loading of "this" pointer paramOPs.push(new OPcall(1, (new Object[0]).getClass())); int classID=lib.getDynamicMethodClassID(m); paramOPs.push(new OPload(new Integer(classID))); paramOPs.push(new OPbinary(paramOPs,19)); }; // restore params & param ops for(int i=0;i9?8:rop.resID; // compute base type (actually // not needed since RET does it alr.) Class retType=rop.resType; // add the "return" instruction paramOPs.push(new OPunary(paramOPs,3)); if (paramOPs.size()!=1) System.err.println("Extra paramOPs left in stack when compiling."); OP program=paramOPs.pop(); // form name String name="evaluate"; if (retID!=8) name=name+'_'+retType; boolean ok=true; for(int i=0;i<2;i++) { if (verbose) System.out.print(toStr(program)); // make class ClassFile cf=cf_orig.clone(); // set return type int otsize=cf.tsize; cf.tsize=retID_patchback; cf.write(retID); cf.tsize=otsize; cf.newMethod(eval_methods[retID],null); program.compile(cf); byte[] image=cf.getImage(); // dumpImage(cf); // load & execute CompiledExpression cexpr= (CompiledExpression)(ImageLoader.load(image)).newInstance(); Object res=cexpr.evaluate(thisPtrs); // compare results boolean localOK=((expRes==null) && (expRes==res)) || (expRes.equals(res)); if (verbose) { System.out.print(" == "); System.out.print(res); System.out.print(" "); if (localOK) System.out.print("ok."); else System.out.print("WRONG !!!"); System.out.println(""); }; ok=ok && localOK; try { program=new OPload(program,program.eval()); } catch (Exception exc) { }; }; assertTrue(testTitle.toString(), ok); // rerun the failed test to get verbose output if (!(ok | verbose)) exprMiniComp(expr, thisPtrs, lib, expRes, cf_orig, retID_patchback, eval_methods, true); }; public static String toStr(OP o) { if (o instanceof OPload) { OPload op=(OPload)o; if (op.resID==8) return "\""+op.what+"\""; return op.what.toString()+(op.resID>9?'L':"ZBCSIJFDLV".charAt(op.resID)); }; if (o instanceof OPbinary) { String[] opSymbols={ "+","-","*","/","%","&","|","^","==","!=","<",">=", ">","<=","<<",">>",">>>","&&","||","{}",".+."}; OPbinary op=(OPbinary)o; return toStr(op.chi[0])+opSymbols[op.code]+toStr(op.chi[1]); }; if (o instanceof OPunary) { String[] opSymbols={"--","~","!","","(Z)","(B)", "(C)","(S)","(I)","(J)", "(F)","(D)","(L)","(POP)","->TSB","->STR"}; OPunary op=(OPunary)o; return opSymbols[op.code]+toStr(op.chi[0]); }; if (o instanceof OPcall) { OPcall op=(OPcall)o; if (op.m==null) return "{"+op.nplv+"}"; else { StringBuffer res=new StringBuffer(op.m.getName()); res.append('('); for (int i=0;i0) res.append(","); res.append(toStr(op.chi[i])); }; res.append(')'); return res.toString(); } }; if (o instanceof OPcondtnl) { OPcondtnl op=(OPcondtnl)o; StringBuffer res=new StringBuffer(); if (op.chi[1]!=null) res.append('('); res.append(toStr(op.chi[0])); if (op.chi[1]!=null) { res.append('?'); res.append(toStr(op.chi[1])); res.append(':'); res.append(toStr(op.chi[2])); res.append(')'); } return res.toString(); }; return "<<<<>>>"; }; public static void dumpImage(ClassFile cf) throws Exception { java.io.FileOutputStream fos= new java.io.FileOutputStream("dump.class"); fos.write(cf.getImage()); fos.close(); }; } source/src/tests/gnu/jel/LibraryDotOPTest.java0000644000175000017500000000463412714113765020373 0ustar olesoles/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * This file is part of the Java Expressions Library (JEL). * For more information about JEL visit : http://fti.dn.ua/JEL/ * * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2006, 2007, 2009 Konstantin L. Metlov * * 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 . */ package gnu.jel; import junit.framework.TestCase; import java.io.StringReader; import java.lang.reflect.Member; public class LibraryDotOPTest extends TestCase { public LibraryDotOPTest(String name) { super(name); } Library ldot; public void setUp() throws Exception { Class[] stl=new Class[1]; Class[] dynl=new Class[1]; Class[] dotl=new Class[2]; stl[0]=Class.forName("java.lang.Math"); dynl[0]=Class.forName("java.util.Random"); dotl[0]=Class.forName("java.util.Hashtable"); dotl[1]=Class.forName("java.util.Vector"); ldot=new Library(stl,dynl,dotl,null,null); } public void tearDown() throws Exception { } public void testHashtableSize() throws Exception { Class[] params=new Class[0]; Class htable=Class.forName("java.util.Hashtable"); Member mf=ldot.getMember(htable,"size",params); assertTrue((mf!=null) && (mf.equals(htable.getMethod("size",params)))); } public void testVectorSize() throws Exception { Class[] params=new Class[0]; Class vctr=Class.forName("java.util.Vector"); Member mf=ldot.getMember(vctr,"size",params); assertTrue((mf!=null) && (mf.equals(vctr.getMethod("size",params)))); } public void testSizeNoLeak() throws Exception { Class[] params=new Class[0]; try { Member mf=ldot.getMember(null,"size",params); assertTrue(false); } catch (CompilationException exc) { assertTrue(true); }; } } source/src/tests/gnu/jel/ParserTest.java0000644000175000017500000002156012714113765017312 0ustar olesoles/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * This file is part of the Java Expressions Library (JEL). * For more information about JEL visit : http://fti.dn.ua/JEL/ * * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2006, 2007, 2009 Konstantin L. Metlov * * 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 . */ package gnu.jel; import junit.framework.TestCase; import java.io.StringReader; import java.lang.reflect.Method; public class ParserTest extends TestCase { public ParserTest(String name) { super(name); } Library lib; public void setUp() throws Exception { lib=new Library(null,null,null,null,null); } public void tearDown() throws Exception { } public void testEOF() throws Exception { Parser tok=new Parser("",lib); tok.nextToken(); assertEquals(-1,tok.type); // it is EOF } public void testOneSymTokens() throws Exception { String stokens="+ - * / % & | \n ^ < > [ ] ~ ! ? : . ( ) ,"; Parser tok=new Parser(stokens,lib); tok.nextToken(); assertEquals(0,tok.type); // read '+' assertEquals(1,tok.ct_column); // it is in 1st column tok.nextToken(); assertEquals(1,tok.type); // read '-' assertEquals(3,tok.ct_column); // it is in 3rd column assertEquals(1,tok.ct_line); // it is in the 1st line tok.nextToken(); assertEquals(2,tok.type); // read '*' assertEquals(6,tok.ct_column); // it is in 6th column String[] part1={"/","%","&","|"}; for (int i=0;i","[","]","~","!","?",":",".","(",")",","}; int[] part2Int ={ 10, 12, 19, 20, 30, 31, 35, 36, 40, 41, 42, 43}; for (int i=0;i=","<=","<<",">>","&&","||",">>>"}; int[] part3Int ={ 8, 9, 11, 13, 14, 15, 17, 18, 16}; for (int i=0;i","!","<","!","&","!","|","!",">", "!",">",">>","!"}; int[] part4Int ={ 31, 31, 31, 12, 31, 10, 31, 5, 31, 6, 31, 12, 31, 12, 15, 31}; for (int i=0;i. */ package gnu.jel; import gnu.jel.tests.*; import java.io.PrintStream; import java.util.Stack; public class IntegralVarARRTest extends TestingUtils { public IntegralVarARRTest(String name) { super(name); } Library lib; Object[] rtp; VariableProvider vp; public void setUp() throws Exception { Class[] dynamicLib=new Class[1]; rtp=new Object[1]; vp=new VariableProvider(); Class[] staticLib=new Class[2]; staticLib[0]=Class.forName("java.lang.Math"); // next line makes also static functions from VariablePrivider available staticLib[1]=vp.getClass(); vp.xvar=5.0; vp.strVar="strVar"; rtp[0]=vp; dynamicLib[0]=vp.getClass(); lib=new Library(staticLib,dynamicLib,null,null,null); } public void test1() throws Throwable { simExpression("5*xvar-66",new Double(25-66),Double.TYPE,rtp,lib,null); } public void test2() throws Throwable { simExpression("5*arr[1]-66",new Double(25-66),Double.TYPE,rtp,lib,null); } public void test3() throws Throwable { simExpression("5*(arrs[1]+arrs[2])-66",new Double(25-66),Double.TYPE,rtp,lib,null); } public void test4() throws Throwable { simExpression("5*(arrs[1]+arrs[(int)round(arr[0]-arrs[2])+1])-66",new Double(25-66),Double.TYPE,rtp,lib,null); } public void test5() throws Throwable { simExpression("arrDoubleJELObj1[0]+arrDoubleJELObj1[1]", new Double(3.0), null, rtp, lib,null); } public void test6() throws Throwable { simExpression("arrDoubleJELObj", vp.arrDoubleJELObj, null, rtp, lib,null); } }; source/src/java/0000755000175000017500000000000012714113765012563 5ustar olesolessource/src/java/DVResolverProvider.java0000644000175000017500000000413112714113765017173 0ustar olesoles/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * This file is part of the Java Expressions Library (JEL). * For more information about JEL visit : http://fti.dn.ua/JEL/ * * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2006, 2007, 2009 Konstantin L. Metlov * * 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 . */ // This class is both used to resolve the dynamic variable names and // to provide their values. These two functions can also be // implemented by two different classes. public class DVResolverProvider extends gnu.jel.DVMap { private java.util.HashMap properties= new java.util.HashMap(); // adds a new property protected void addProperty(String name,Object value) { properties.put(name,value); }; // implements the method of DVResolver interface, // used by the compiler to query about available dynamic // variables public String getTypeName(String name) { Object val=properties.get(name); if (val==null) return null; // dynamic variable does not exist if (val instanceof Data) return "Data"; if (val instanceof String) return "String"; // the type is not supported we say the variable is not defined return null; }; // Next we have those YYY getXXXProperty(String) methods described in // the manual public Data getDataProperty(String name) { return (Data)properties.get(name); }; public String getStringProperty(String name) { return (String)properties.get(name); }; }; source/src/java/GlobalContext.java0000644000175000017500000000217712714113765016202 0ustar olesoles/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * This file is part of the Java Expressions Library (JEL). * For more information about JEL visit : http://fti.dn.ua/JEL/ * * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2006, 2007, 2009 Konstantin L. Metlov * * 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 . */ public class GlobalContext { public double x; public Data d1; public Data d2; public GlobalContext(double x, Data d1, Data d2) { this.x=x; this.d1=d1; this.d2=d2; }; }; source/src/java/YourTestBed.java0000644000175000017500000001100112714113765015630 0ustar olesoles/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * This file is part of the Java Expressions Library (JEL). * For more information about JEL visit : http://fti.dn.ua/JEL/ * * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2006, 2007, 2009 Konstantin L. Metlov * * 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 . */ public class YourTestBed { public static void main(String[] args) throws Throwable { //********************************************************** //**** to use JEL we first have to define the namespace **** // we shall export the static methods of java.lang.Math Class[] stLib=new Class[1]; stLib[0]=java.lang.Math.class; // we shall enable access to methods of two classes Class[] dynLib=new Class[2]; // we export global context fields/methods dynLib[0]=GlobalContext.class; // we export YYY getXXXProperty() methods for dynamic variable access dynLib[1]=DVResolverProvider.class; // this initializes the resolver object DVResolverProvider resolver=new DVResolverProvider(); // we shall allow dot operators on strings and data Class[] dotLib=new Class[2]; dotLib[0]=Data.class; dotLib[1]=java.lang.String.class; // finally, the namespace is defined by constructing the library class gnu.jel.Library lib= new gnu.jel.Library(stLib,dynLib,dotLib,resolver,null); //********************************************************** //******** Now we setup the global context and data ******* Object[] context=new Object[2]; GlobalContext gc=new GlobalContext(0.2,new Data(2),new Data(10)); context[0]=gc; context[1]=resolver; // this pointer for YYY getXXXProperty() methos //********************************************************** //******** We are ready to compile some expressions ******* gnu.jel.CompiledExpression expr; // constant expression expr=gnu.jel.Evaluator.compile("2*2",lib); System.out.println("2*2="+expr.evaluate(context)); // expression accessing the variables expr=gnu.jel.Evaluator.compile("x",lib); System.out.println("x="+expr.evaluate(context)); // three expressions accessing the variables with dot operator expr=gnu.jel.Evaluator.compile("d1.value",lib); System.out.println("d1.value="+expr.evaluate(context)); // expr=gnu.jel.Evaluator.compile("d2.value",lib); System.out.println("d2.value="+expr.evaluate(context)); // expr=gnu.jel.Evaluator.compile("(d1.value+d2.value)*x*10",lib); System.out.println("(d1.value+d2.value)*x*10="+expr.evaluate(context)); // also using static functions expr=gnu.jel.Evaluator.compile("round((d1.value+d2.value)*x*10)",lib); System.out.println("round((d1.value+d2.value)*x*10)="+expr.evaluate(context)); // LET's try dynamic variables // First, we add few _DYNAMICALLY_, this can (and intended to) be // done after the gnu.jel.Library initialization resolver.addProperty("sDvar","str1"); resolver.addProperty("dataDvar",new Data(3)); // now we can access them expr=gnu.jel.Evaluator.compile("sDvar",lib); System.out.println("sDvar="+expr.evaluate(context)); expr=gnu.jel.Evaluator.compile("dataDvar",lib); System.out.println("dataDvar="+expr.evaluate(context)); // it is possible to have hierarchical name space // let's add a second level of hierarchy resolver.addProperty("sDvar.data1",new Data(5)); resolver.addProperty("sDvar.data2",new Data(6)); resolver.addProperty("sDvar.str","This is string"); // we can access these also expr=gnu.jel.Evaluator.compile("sDvar.data1",lib); System.out.println("sDvar.data1="+expr.evaluate(context)); expr=gnu.jel.Evaluator.compile("sDvar.str",lib); System.out.println("sDvar.str="+expr.evaluate(context)); expr=gnu.jel.Evaluator.compile("sDvar.data2",lib); System.out.println("sDvar.data2="+expr.evaluate(context)); // they are ready for calculations expr=gnu.jel.Evaluator.compile("sDvar.data1+sDvar.data2+1",lib); System.out.println("sDvar.data1+sDvar.data2+1="+expr.evaluate(context)); // You can add more expressions here }; }; source/src/java/Data.java0000644000175000017500000000236312714113765014303 0ustar olesoles/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * This file is part of the Java Expressions Library (JEL). * For more information about JEL visit : http://fti.dn.ua/JEL/ * * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2006, 2007, 2009 Konstantin L. Metlov * * 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 . */ public class Data implements gnu.jel.reflect.Double { public double value=10.0; public double squared_value() { return value*value; }; public Data(double value) { this.value=value; }; // implements gnu.jel.reflect.Double interface public double getValue() { return value; }; }; source/src/java/Calculator.java0000644000175000017500000001005412714113765015517 0ustar olesoles/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * This file is part of the Java Expressions Library (JEL). * For more information about JEL visit : http://fti.dn.ua/JEL/ * * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2006, 2007, 2009 Konstantin L. Metlov * * 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 . */ import gnu.jel.Evaluator; import gnu.jel.CompiledExpression; import gnu.jel.Library; import gnu.jel.CompilationException; public class Calculator { static final String[] help= {" This is a simple calculator, based on JEL.", "", " to use this calculator issue the following command :", " java Calculator \"expression\"", "", "Don't forget to use quotes around the expression if Your shell requires", " it. For example \"1&3\" will fail in WinNT cmd without quotes.", " The expression language is intuitively simple. You can use binary ", " operations : '+','-','*','/','%'(remainder),'&'(bitwise and),", " '|'(bitwise or), '^'(bitwise xor) , unary negation '-'. Also all ", " standard static functions of java.lang.Math are at Your disposal.", "Examples of expressions : \"1+1\", \"sin(1)\", \"random()\" .", "", "Of course the use of the compiler (what JEL is actually is) is crazy for ", "calculating expressions only once. This has a HUGE performance loss, but,", "this is just the demo. Enjoy !!!", "", "(c) 2009 by Konstantin L. Metlov (metlov@fti.dn.ua)", " This program is the free software and was distributed to You under", " terms of GNU General Public License. You should have the text of the", " license together with the source code of this sample and JEL itself.", " If You don't have the source code or license- contact me immediately." }; public static void main(String[] args) { if (args.length==0) { for(int i=0;i[1]; try { staticLib[0]=Class.forName("java.lang.Math"); } catch(ClassNotFoundException e) { // Can't be ;)) ...... in java ... ;) }; Library lib=new Library(staticLib,null,null,null,null); try { lib.markStateDependent("random",null); } catch (CompilationException e) { // Can't be also }; // Compile CompiledExpression expr_c=null; try { expr_c=Evaluator.compile(expr,lib); } catch (CompilationException ce) { System.err.print("--- COMPILATION ERROR :"); System.err.println(ce.getMessage()); System.err.print(" "); System.err.println(expr); int column=ce.getColumn(); // Column, where error was found for(int i=0;i. */ package gnu.jel; import java.util.*; import java.io.*; import gnu.jel.debug.Debug; public class TableWriter { private static final Hashtable tables = new Hashtable(); private static final ResourceBundle msgs = null; public static void main(String[] args) { if (Debug.enabled) { try { // Tables from gnu.jel.TypesStack String[] specialTypesStr={ null, // Boolean.TYPE, // 0 0x00 null, // Byte.TYPE, // 1 0x01 null, // Character.TYPE, // 2 0x02 null, // Short.TYPE, // 3 0x03 null, // Integer.TYPE, // 4 0x04 null, // Long.TYPE, // 5 0x05 null, // Float.TYPE, // 6 0x06 null, // Double.TYPE, // 7 0x07 null, // Generic reference // 8 0x08 null, // Void.TYPE, // 9 0x09 "java.lang.String", //[TSB] // 10 0x0A "java.lang.String", // 11 0x0B "gnu.jel.reflect.Boolean", // 12 0x0C "gnu.jel.reflect.Byte", // 13 0x0D "gnu.jel.reflect.Character", // 14 0x0E "gnu.jel.reflect.Short", // 15 0x0F "gnu.jel.reflect.Integer", // 16 0x10 "gnu.jel.reflect.Long", // 17 0x11 "gnu.jel.reflect.Float", // 18 0x12 "gnu.jel.reflect.Double", // 19 0x13 "java.lang.Boolean", // 20 0x14 "java.lang.Byte", // 21 0x15 "java.lang.Character", // 22 0x16 "java.lang.Short", // 23 0x17 "java.lang.Integer", // 24 0x18 "java.lang.Long", // 25 0x19 "java.lang.Float", // 26 0x1A "java.lang.Double", // 27 0x1B "gnu.jel.reflect.String" // 28 0x1C }; tables.put("specialTypes",specialTypesStr); Class[] specialTypes=new Class[specialTypesStr.length]; for (int i=10; i[] specialClasses=new Class[specialTypes.length+ specialClassesAddStr.length]; System.arraycopy(specialTypes,0,specialClasses,0, specialTypes.length); for(int i=specialTypes.length;i. */ package gnu.jel; import gnu.jel.debug.*; import java.util.Stack; import java.lang.reflect.Member; public class Parser { //******************** //*** PARSER variables Stack paramOPs; Stack xchgOP; // temporary paramops stack int err_col=-1; // int err_line=-1; // not yet Library lib; StringBuffer accDV=null; // null means DVs are disabled StringBuffer typeAccum=new StringBuffer(); // accumulates class name for cast //*** PARSER variables //******************** //*********************** //*** TOKENIZER variables private String in; // input string private int pos=0; protected int c; // current character // the next four are used for counting the columns and lines private boolean prevCR = false; // true if the last read char was CR private boolean prevLF = false; // true if the last read char was LF private int column=0; private int line=1; /** * Column, where the current token started */ public int ct_column; /** * Line, where the current token started */ public int ct_line; /** * value of the current token wrapped into a reflection object */ public Object val; /** * type of the current token */ public int type; // -1 "" // 0 "+" // 1 "-" // 2 "*" // 3 "/" // 4 "%" // 5 "&" // 6 "|" // 7 "^" // 8 "==" // 9 "!=" // 10 "<" // 11 ">=" // 12 ">" // 13 "<=" // 14 "<<" // 15 ">>" // 16 ">>>" // 17 "&&" // 18 "||" // 19 "[" // 20 "]" // 30 "~" // 31 "!" // 35 "?" // 36 ":" // 40 "." // 41 "(" // 42 ")" // 43 "," // 50 "" // 60 " /** * accumulator, used in processing of s, s or keywords */ private StringBuffer buf=new StringBuffer(); //*** TOKENIZER variables //*********************** /** * Initializes the parser. * @param in expression to parse * @param lib library to resolve functions in */ public Parser(String in, Library lib) { // init TOKENIZER this.in = in; read(); // init PARSER this.lib=lib; paramOPs=new Stack(); xchgOP=new Stack(); // initialize DV names accumulator if (lib.resolver!=null) accDV=new StringBuffer(); }; //*********************** //*** TOKENIZER methods /** * Reads character from underlying Reader. *

Additionally it counts line and column numbers. The read character * is automatically set as a current char of this Tokenizer. * * @return next character from the selected input. */ protected int read() { try { c=in.charAt(pos++); } catch (Exception e) { c=-1; }; column++; if (prevLF) { prevLF = false; line += (column = 1); } else if (prevCR) { prevCR = false; if (c == '\n') { prevLF = true; } else line += (column = 1); } switch (c) { case '\r': prevCR = true; break; case '\n': prevLF = true; break; case '\t': column--; column += (8 - (column & 07)); break; default: break; }; return c; }; public void error(int code, Object param, int column) throws CompilationException { CompilationException exc = new CompilationException(code,param); exc.col=column; throw exc; } // because EOF can never be expected, "consume(-1)" has a special // meaning, which is just to report the "current unexpected" char. protected void consume(int cc) throws CompilationException { if ((cc<0) || (c!=cc)) error(c==-1?1:3,new Character((char)c),column-(c==-1?1:0)); read(); }; public void nextToken() throws CompilationException { // store the column and line of the current token ct_column=column; ct_line=line; int cc; while (true) { switch (c) { case -1: // EOF type=-1; return; case ' ': case '\r': case '\t': case '\n': read(); // just ignored ct_column=column; // adjust start token ct_line=line; // adjust start token break; case '+': read(); type=0; return; case '-': read(); type=1; return; case '*': read(); type=2; return; case '/': read(); type=3; return; case '%': read(); type=4; return; case '&': switch (read()) { case '&': read(); type=17; return; default: type=5; return; } case '|': switch (read()) { case '|': read(); type=18; return; default: type=6; return; } case '^': read(); type=7; return; case '=': read(); consume('='); type=8; return; case '!': switch(read()) { case '=': read(); type=9; return; default: type=31; return; } case '<': switch (read()) { case '=': read(); type=13; return; case '<': read(); type=14; return; default: type=10; return; } case '>': switch (read()) { case '=': read(); type=11; return; case '>': switch(read()) { case '>': read(); type=16; return; default: type=15; return; } default: type=12; return; } case '~': read(); type = 30; return; case '[': read(); type = 19; return; case ']': read(); type = 20; return; case '?': read(); type = 35; return; case ':': read(); type = 36; return; case '.': cc=read(); if ((cc>='0') && (cc<='9')) { // case '0': case '1': case '2': case '3': case '4': // case '5': case '6': case '7': case '8': case '9': parseReal(); } else { type=40; }; return; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': parseNumber(); return; case '(': read(); type=41; return; case ')': read(); type=42; return; case ',': read(); type=43; return; case '\"': read(); parseString(); return; case '\'': parseChar(); return; default: if (Character.isJavaIdentifierStart((char)c)) { parseID(); return; } else consume(-1); } } }; // current char must be starting slash private int parseEscape() throws CompilationException { switch (read()) { case 'r': read(); return '\r'; case 'n': read(); return '\n'; case 'f': read(); return '\f'; case 'b': read(); return '\b'; case 't': read(); return '\t'; case 'u': { // parsing unicode escapes int v=0; for(int i=0;i<4;i++) { read(); v=v<<4; if ((c>='0')&&(c<='9')) { v+=c-'0'; } else if ((c>='a') && (c<='f')) { v+=c-'a'+10; } else if ((c>='A') && (c<'F')) { v+=c-'A'+10; } else { consume(-1); return -1; // never reached }; }; read(); // position to the next in stream return v; // character parsed } case '\\': case '\"': case '\'': // TRICK ! This should return an _old_ c before read, and then read(). return c+(read()-c); default: { // parsing octal escapes if ((c>='0') && (c<='7')) { int v=c-'0'; for (int i=0;i<2;i++) { read(); if ((c>='0') && (c<='7')) { v = (v << 3) + c - '0'; } else { if (v>0xFF) consume(-1); return v; }; }; read(); if (v>0xFF) consume(-1); return v; } else { // invalid escape character consume(-1); return -1; // never reached } } } // case }; private void parseChar() throws CompilationException { char ch=0; switch(read()) { case '\\': ch=(char)parseEscape(); break; case -1: // EOF case '\n': case '\r': case '\'': // these can't be encountered inside char literal consume(-1); break; default: ch=(char)c; read(); }; consume('\''); type=60; // val=new Character(ch); return; }; private void parseString() throws CompilationException { if (Debug.enabled) Debug.check(buf.length()==0); while(true) { switch(c) { case -1: // EOF case '\n': case '\r': case '\'': // these can't be encountered inside String literal consume(-1); break; case '\\': buf.append((char)parseEscape()); break; case '\"': read(); type=60; // val=buf.toString(); buf.setLength(0); return; default: buf.append((char)c); read(); }; } }; private void parseID() throws CompilationException { if (Debug.enabled) Debug.check(buf.length()==0); do { buf.append((char)c); read(); } while((c>0) && Character.isJavaIdentifierPart((char)c)); type=50; // assume for the start val=buf.toString(); buf.setLength(0); // check against keywords (so far JEL has only two of them) if (val.equals("true")) { type=60; // val=Boolean.TRUE; } else if (val.equals("false")) { type=60; // val=Boolean.FALSE; }; return; }; // starts to parse integer number, falls through to parseReal if '.' // is encountered private void parseNumber() throws CompilationException { if (Debug.enabled) Debug.check(buf.length()==0); boolean seenDigit=false; boolean seen89=false; int base=(c=='0'?8:10); long value=c-'0'; buf.append((char)c); // save digit, which was already read outerLoop: while(true) { switch(read()) { case '9': case '8': // can't just throw an error, the number can be Real seen89=true; case '7': case '6': case '5': case '4': case '3': case '2': case '1': case '0': seenDigit=true; buf.append((char)c); if (base==10) { // check for overflow, e.g. when can't store any more decimal digits if ((value*10)/10 != value) error(30,null,column-1); // overflow value=value*10+(c-'0'); } else if (base==8) { // check for overflow, e.g. when can't store any more octal digits // e.g. highest three bits already occupied if ((value>>>61)>0) error(30,null,column-1); // overflow value=(value<<3)+(c-'0'); } else { // hexadecimal number // check for overflow, e.g. when can't store any more hex digits // e.g. highest four bits already occupied if ((value>>>60)>0) error(30,null,column-1); // overflow value=(value<<4)+(c-'0'); }; break; case 'D': case 'd': case 'E': case 'e': case 'F': case 'f': // in non-hexadecimal mode switch to parsing real number if (base!=16) { parseReal(); return; }; case 'A': case 'a': case 'B': case 'b': case 'C': case 'c': if (base!=16) break outerLoop; // illegal character, error will appear later seenDigit=true; // check for overflow, e.g. when can't store any more hex digits // e.g. highest four bits already occupied if ((value>>>60)>0) error(30,null,column-1); // overflow value=(value<<4)+(10+Character.toLowerCase((char)c)-'a'); break; case '.': if (base==16) break outerLoop; // illegal character, error will appear later // switch to parsing real number parseReal(); return; case 'L': case 'l': // this, in particular, means FINISH read(); buf.setLength(0); // discard accumulated chars type=60; // val=new Long(value); break outerLoop; // finished parsing 'long' case 'X': case 'x': if ((buf.length()==1) && (base==8)) { // if there was only '0' before, switch to hexadecimal mode base=16; seenDigit=false; break; } else break outerLoop; // illegal character, error will appear later default: // anything else (e.g. EOF, '/n', space, letter, ...) means // we finished parsing an integer number buf.setLength(0); // discard accumulated chars type=60; // // select type based on range // note that the minus sign is handled as unary OP, not // as part of the number if (value<=127) val=new Byte((byte)value); else if (value<=32767) val=new Short((short)value); else if (value<=2147483647) val=new Integer((int)value); else if (((base==16) || (base==8)) && (value<=4294967295L)) // we allow HEX and octal ints val=new Integer((int)value); // to overflow to negative values else error(29,new Long(value),column-1); // int overflow break outerLoop; }; }; // let's check what have we parsed if ((c == '.') || Character.isJavaIdentifierPart((char)c)) { consume(-1); // immediately followed by letter, too bad } else if ((base==8) && seen89) { consume(-1); // no '8', '9' in hexadecimal numbers } else if ((base==16) && !seenDigit) { consume(-1); // hexadecimal with no digits inside }; }; private void parseReal() throws CompilationException { boolean seenE = false; boolean makeFloat = false; // if (c!='.') { // // it is called from nextToken after '.' is already discarded // // here we make up for it // buf.append('.'); // } if (c=='.') read(); buf.append('.'); // now we have the '.' in the buffer and the first digit? as // current char outerLoop: for(;;read()) { switch(c) { case 'e': case 'E': if (seenE) break outerLoop; // second 'E', error will appear later seenE=true; // fall through case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': buf.append((char)c); break; case '+': case '-': // can be only after 'E' char lch=buf.charAt(buf.length()-1); if ((lch!='e') && (lch!='E')) break outerLoop; // number finished buf.append((char)c); break; case 'f': case 'F': read(); makeFloat = true; break outerLoop; case 'd': case 'D': read(); // fall through default: // anything unknown means end of number break outerLoop; }; }; // let's check what have we accumulated and make a token out of it if ((c == '.') || Character.isJavaIdentifierPart((char)c)) { consume(-1); // immediately followed by letter, too bad } else { char lch=buf.charAt(buf.length()-1); // should not end by 'E','e','+','-' if ((lch=='E') || (lch=='e') || (lch=='+') || (lch=='-')) consume(-1); // illegal character else { // make token type=60; if (makeFloat) { val=Float.valueOf(buf.toString()); if (Float.isInfinite(((Float)val).floatValue())) error(31,null,column-1); // floating point literal overflow } else { // makeDouble val=Double.valueOf(buf.toString()); if (Double.isInfinite(((Double)val).doubleValue())) error(31,null,column-1); // floating point literal overflow }; buf.setLength(0); // if success -- reset buf }; }; }; // performs "cast" lookahead // returns true if the next sequence of tokens mathes: // 1) '(' ('.' )* ')' (|) // 2) '(' ('.' )* '[' ']' // after the lookahead the state of the tokenizer is restored // no objects are allocated on heap during this lookahead. public boolean isCast() { // must start with '(' which is already read and classified if (type!=41) return false; // save read state boolean t_CR=prevCR, t_LF=prevLF; int t_column=column, t_line=line, t_pos=pos; int t_c=c; boolean result=false; boolean arrCast=false; // look ahead (we can now freely use read, the state is saved) outerLoop: { parenLoop: while (true) { ws2: while(true) switch(c) { case -1: break outerLoop; case ' ': case '\t': case '\n': case '\r': read(); break; default: break ws2; }; if (!Character.isJavaIdentifierStart((char)c)) break outerLoop; // scan the rest of identifier read(); for(;Character.isJavaIdentifierPart((char)c);read()); // all identifier is consumed, consume dot ws3: while(true) switch(c) { case -1: break outerLoop; case ' ': case '\t': case '\n': case '\r': read(); break; default: break ws3; }; switch(c) { case '.': read(); continue parenLoop; // if dot we go to match the next case ')': // closing bracket finishes the '(' ('.' )* ')' // match, now we only to check -- what's after break parenLoop; case '[': // array designator, we match it with ']' // this covers the case ( ('.' )* '[' ']' // after which without ')' match it is already clear // that we have cast arrCast=true; break parenLoop; default: break outerLoop; // anything else -- bail } }; // parenLoop read(); // skip ')' or '[' // we now match beginning of '(', , '.', '\'', '\"', while (true) switch (c) { case ' ': case '\t': case '\n': case '\r': read(); break; case ']': result=true; case '(': case '.': case '\'': case '\"': if (arrCast) break outerLoop; result=true; // fall through case -1: break outerLoop; default: result= (!arrCast) && (((c>='0') && (c<='9')) || Character.isJavaIdentifierStart((char)c)); break outerLoop; } }; // outerLoop // restore state prevCR=t_CR; prevLF=t_LF; c=t_c; column=t_column; line=t_line; pos=t_pos; return result; }; //*** TOKENIZER methods //*********************** //*********************** //*** PARSER methods /** * Parses expression. * @param resultType the type to convert the result into * @return top of the parse tree */ public OP parse(Class resultType) throws CompilationException { try { expression(); err_col=ct_column-1; // this should be now set to // remove TSB at return if present if (paramOPs.peek().resID==10) paramOPs.push(new OPunary(paramOPs,11,null,false)); // set result type if (resultType!=null) paramOPs.push(new OPunary(paramOPs,OP.typeID(resultType), resultType,false)); // add the "return" instruction paramOPs.push(new OPunary(paramOPs,3)); } catch (CompilationException exc) { // examine if it has set error position if (exc.col<0) { if (Debug.enabled) Debug.check(err_col>0); exc.col=err_col; // set if not //exc.line=err_line; // not yet }; // exc.printStackTrace(); throw exc; }; if (Debug.enabled) Debug.check(paramOPs.size()==1, "There must be only a single item left in paramOPs stack."); return paramOPs.pop(); }; private void consumeT(int t) throws CompilationException { if (type!=t) consume(-1); // encountered unexpected (FIXME: report as token) nextToken(); }; private void expression() throws CompilationException { // expression ::= conditional nextToken(); conditional(); consumeT(-1); // consume EOF }; private void conditional() throws CompilationException { binOP(0); if (type==35) { // '?' int ecol=ct_column; nextToken(); int stackSizeBeforeBranch=paramOPs.size(); conditional(); consumeT(36); // ':' int stackSizeAfterFirstBranch=paramOPs.size(); conditional(); err_col=ecol; // report errors against '?' if (Debug.enabled) Debug.check((paramOPs.size()==stackSizeAfterFirstBranch+1) && (stackSizeAfterFirstBranch==stackSizeBeforeBranch+1), "Stack in conditional branches is not balanced."); paramOPs.push(new OPcondtnl(paramOPs)); }; }; // this array defines binary operators precedence // private final static byte[][] binR = { // // min max // { 18, 18}, // 0 LOR ('||') // { 17, 17}, // 1 LAND ('&&') // { 6, 6}, // 2 BOR ('|') // { 7, 7}, // 3 BXOR ('^') // { 5, 5}, // 4 BAND ('&') // { 8, 9}, // 5 EQUALITY ('==' | '!=') // { 10, 13}, // 6 RELATION ('<' | '>=' | '>' | '<=') // { 14, 16}, // 7 SHIFT ('<<' | '>>' | '>>>') // { 0, 1}, // 8 SUM ('+' | '-') // { 2, 4}}; // 9 TERM ('*' | '/' | '%') private void binOP(int idx) throws CompilationException { if (idx==9) unary(); else binOP(idx+1); int t; if (Debug.enabled) Debug.check((idx>=0)&&(idx<=9)); int v=(int)(idx<5?(0xA539CC68C652L>>>(idx*10)): (0x820820E6A928L>>>((idx-5)*10))); // m1= // 5, 5, 7, 7, 6, 6, 17, 17, 18, 18 // 00101,00101,00111,00111,00110,00110,10001,10001,10010,10010 // 00 1010 0101 0011 1001 1100 1100 0110 1000 1100 0110 0101 0010 // 0 A 5 3 9 C C 6 8 C 6 5 2 // 0x0A539CC68C652L // m2= // 4, 2, 1, 0, 16, 14, 13, 10, 9, 8 // 00100,00010,00001,00000,10000,01110,01101,01010,01001,01000 // 00 1000 0010 0000 1000 0010 0000 1110 0110 1010 1001 0010 1000 // 0 8 2 0 8 2 0 E 6 A 9 2 8 // 0x0820820E6A928L while ( ((t=type)>=(v & 0x1F)) && (t<=((v>>>5) & 0x1F)) ) { int ecol=ct_column; nextToken(); if (idx==9) unary(); else binOP(idx+1); err_col=ecol; // make use that token types and binary OPs coincide paramOPs.push(new OPbinary(paramOPs,t)); }; }; private void unary() throws CompilationException { int ecol; int t; int accumStrt; if (((t=type)==1)||(t==30)||(t==31)) { // '-' | '~' | '!' ecol=ct_column; nextToken(); unary(); if (t>=30) t-=28; err_col=ecol; paramOPs.push(new OPunary(paramOPs,t-1)); } else if (isCast()) { // lookahead for cast consumeT(41); // '(' ecol=ct_column; // error will be reported against the first accumStrt=typeAccum.length(); typeAccum.append(val); // value of identifier (if not, does not matter) consumeT(50); // '' while (type==40) { // '.' typeAccum.append('.'); nextToken(); typeAccum.append(val); consumeT(50); // '' }; consumeT(42); // ')' element(); err_col=ecol; // generate convert OP int typeID=0; Class clazz=null; while ((typeID<8) && !typeAccum.substring(accumStrt). equals(OP.specialTypes[typeID].toString())) typeID++; if (Debug.enabled) Debug.check(typeID<=8); // this handles non-primitive types. if ((typeID==8) && ( (clazz=(lib.cnmap==null?null: lib.cnmap.get(typeAccum.substring(accumStrt)) ) )==null ) ) typeID=-1; if (typeID==8) { // identify the type properly typeID=OP.typeID(clazz); }; typeAccum.setLength(accumStrt); if (typeID<0) // the type is unknown {if (true) throw new CompilationException(4,typeAccum.toString());} paramOPs.push(new OPunary(paramOPs,typeID,clazz,true)); // end of convert OP generation } else { // lookahead // here we can find only | | '(' t=type; if ((t==60)||(t==50)||(t==41)) element(); else consume(-1); // throw an error (FIXME: report as unexpected _token_) }; }; private void element() throws CompilationException { // deciding between , '(' conditional ')', invocation // there must be at least one of these switch (type) { case 60: // paramOPs.push(new OPload(val)); nextToken(); break; case 41: // '(' nextToken(); conditional(); consumeT(42); // ')' break; case 50: // invocation(false); break; default: consume(-1); // throw an error (FIXME: report as unexpected _token_) }; while (type==40) { // '.' nextToken(); invocation(true); }; genDVCall(); // finish prepared DV call }; private void invocation(boolean afterDot) throws CompilationException { int paramsStart=0; Class resolveIn=null; int ecol,ecol_id; boolean inDVmatch=false; ecol_id=ecol=ct_column; // error will be reported against the first Object idImage=val; consumeT(50); // if (accDV!=null) { int oldLen=accDV.length(); if (afterDot) accDV.append('.'); accDV.append(idImage); if (!(inDVmatch=isDV())) { accDV.setLength(oldLen); // back up err_col=ecol; genDVCall(); // finish prepared DV call }; }; // end if accDV!=null if (!inDVmatch) { if (afterDot) resolveIn=paramOPs.peek().resType; // start prepating a call to an object's method x.image paramsStart=paramOPs.size(); }; if (type==41) { // '(' ecol=ct_column; // error will be reported against this '(' if (inDVmatch) { // error: variable must have no parameters err_col=ecol; {if (true) throw new CompilationException(26,null);} // this is the place to hack in the abort of match and check // if the last matched name can be called as a method }; nextToken(); // now we need to determine if conditional() is present // it is prefixed by '-','~','!','(',, int t=type; if ((t==1) || (t==30) || (t==31) || (t==41) || (t==60) || (t==50)) { // conditional is here conditional(); while (type==43) { // ',' nextToken(); conditional(); }; }; consumeT(42); // ')' }; if (!inDVmatch) { // generate the method invocation err_col=ecol_id; functionCall(resolveIn,(String)idImage,paramsStart); }; while (type==19) { // '[' ecol=ct_column; // error will be reported against this '[' nextToken(); genDVCall(); // finish prepared DV call conditional(); consumeT(20); // ']' err_col=ecol; paramOPs.push(new OPbinary(paramOPs,19)); }; }; // service methods not directly related to parser, but to // complex method calling semantics of JEL private final boolean isDV() { return lib.resolver.getTypeName(accDV.toString())!=null; } private final void genDVCall() throws CompilationException { if ((accDV==null) || (accDV.length()==0)) return; String varName=accDV.toString(); String typeName=lib.resolver.getTypeName(varName); int paramsStart=paramOPs.size(); Object varObj; // This condition ensures binary and source compatibility // with old (pre 0.9.9) dynamic variables interface and // is subject for removal in JEL 1.0 if (lib.resolver instanceof DVMap) varObj=lib.resolver.translate(varName); else varObj=varName; paramOPs.push(new OPload(varObj)); functionCall(null,"get"+typeName+"Property",paramsStart); accDV.setLength(0); } private final void functionCall(Class resolveInClass,String name, int paramsStart) throws CompilationException{ // collect params int np=paramOPs.size()-paramsStart; Class[] params=new Class[np]; for(int i=np-1;i>=0;i--) { OP cop=paramOPs.pop(); xchgOP.push(cop); params[i]=cop.resType; } // find method Member m=lib.getMember(resolveInClass,name,params); // put "this" pointer in place if (resolveInClass==null) { if ((m.getModifiers() & 0x0008)==0) { // insert loading of "this" pointer paramOPs.push(new OPcall(1,(new Object[0]).getClass())); int classID=lib.getDynamicMethodClassID(m); paramOPs.push(new OPload(new Integer(classID))); paramOPs.push(new OPbinary(paramOPs,19)); } } // restore params & param ops for(int i=0;i. */ package gnu.jel; import gnu.jel.debug.Debug; import java.lang.reflect.Member; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Constructor; import java.util.HashMap; import java.util.List; import java.util.ArrayList; import java.util.Iterator; /** * A namespace for JEL expressions. *

There are two types of members in the library, those which are stateless * (i.e. their value depends only on their arguments, if there are any) and * stateful (also called here dynamic). The result of evaluation of * stateful members may depend on other factors besides their arguments. * *

Examples of possible stateless members are : Math.sin(double), * Math.PI. *

Examples of possible stateful members are : Math.random(), * System.currentTimeMillis(). * *

Stateless members of this library are always static members of the * classes, which define them. The inverse is generally not true. However, * this library goes as far as assuming that static members are stateless, * if this assumption does not hold for some of Your members it is possible to * mark them as stateful using the markStateDependent() method of * this class. * *

The most crucial difference between the two kind of members of this * library is that evaluation of stateless methods is attempted by JEL at * a compile time during the constants folding phase. */ public class Library { private HashMap> names; private HashMap dynIDs; private HashMap stateless; private HashMap,HashMap>> dotClasses; private boolean noDotSecurity=false; public DVMap resolver; // directly accessed from EC.jj public HashMap> cnmap; /** * Creates a library for JEL. *

The following should be kept in mind when constructing a library: *

    *
  1. This constructor may throw IllegalArgumentException if it does not * like something in Your library. The requirements to the method names * are somewhat more strict, than in Java because members of several * classes can be merged in root namespace. *
  2. When calling the * CompiledExpression.evaluate(Object[] dynalib) of the * expression, using dynamic library methods it is needed to pass as * dynalib parameter the array of objects, of the classes * _exactly_ in the same order as they are appearing in the * dynamicLib parameter of this constructor. If You do not * allow to call dynamic methods (there is no sense, then, to use a compiler) * it is possible to pass null istead of dynalib. *
  3. Generally speaking, this class should not let You to create wrong * libraries. It's methods will throw exceptions, return false's , * ignore Your actions,... ;) *
* If methods in the library classes conflict with each other, the last * conflicting method will be skipped. You will not get any messages unless * debugging is ON (see gnu.jel.debug.Debug.enabled). This is * done to avoid unnecessary error messages in the production code of the * compiler. *

The array (dotClasses), which is the third argument of * this constructor determines how (and whether) to compile the * dot operators encountered in expressions. These operators are * of the form <object>.(<method>|<field>), * which means to call method (access field) * of an <object>. There can be three types of the behaviour: *

1) dot operators are prohibited (dotClasses==null), * this is behaviour of older version of JEL. *

2) dot operators are allowed on all classes * (dotClasses==new Class[0], an empty array). * Depending on the types of objects returned by the static/dynamic library * classes this may pose a security risk. *

3) dot operators are allowed only on some classes. This is achieved * by listing these classes in the dotClasses array. * @param staticLib is the array of classes, whose public static * methods are exported. * @param dynamicLib is the array of classes, whose public virutal * methods are exported. * @param dotClasses is the array of classes on which the dot ('.') * operation is allowed. * @param resolver is the object used to resolve the names. * @param cnmap Maps class names into classes for non-primitive type casts. */ public Library(Class[] staticLib,Class[] dynamicLib,Class[] dotClasses, DVMap resolver,HashMap> cnmap) { this.cnmap=cnmap; this.resolver=resolver; if (dotClasses==null) { this.dotClasses=null; } else { noDotSecurity=(dotClasses.length==0); this.dotClasses= new HashMap,HashMap>>(); // hash the names Class[] temp=new Class[1]; for(int i=0;i>(); dynIDs = new HashMap(); stateless=new HashMap(); if (staticLib!=null) rehash(staticLib,names,null,stateless); if (dynamicLib!=null) rehash(dynamicLib,names,dynIDs,null); }; private void rehash(Class cls) { HashMap> tempNames=new HashMap>(); Class[] temp=new Class[1]; temp[0]=cls; // rehash(temp,tempNames,null,new HashMap()); rehash(temp,tempNames,new HashMap(),null); dotClasses.put(cls,tempNames); }; private static void rehash(Class[] arr, HashMap>hashedNames, HashMap dynIDs, HashMap stateless) { for (int i=0; i0) { // static if ((stateless!=null) && rehash(hashedNames,m)) stateless.put(m,Boolean.TRUE); } else { // not static if ((dynIDs!=null) && rehash(hashedNames,m)) dynIDs.put(m,dynID); }; }; }; }; private static boolean rehash(HashMap> hashedNames, Member m) { String name=m.getName(); String signature=getSignature(m); // for the purpose of matching fields behave like methods with no // arguments if (isField(m)) signature="()"+signature; HashMap signatures=hashedNames.get(name); if (signatures==null) { // No method with this name was added HashMap signatures_new=new HashMap(); signatures_new.put(signature,m); hashedNames.put(name,signatures_new); return true; }; // Name exists in the library, check for possible signature conflict. Object conflicting_method=signatures.get(signature); if (conflicting_method==null) { // No conflict signatures.put(signature,m); return true; }; // if (Debug.enabled) { // Debug.println("Conflict was detected during the library "+ // "initialization."+ // " Conflicting "+"\""+name+signature+ // "\", conflicting :"+ conflicting_method+" and "+m+" ."); // }; // If no debug then the method is ignored. return false; }; /** * This method marks a static member as having the internal state. *

If java.lang.Math is included into the library it is * necessary to mark java.lang.Math.random() as having the * state. This can be done by calling * markStateDependent("random",null). *

Please specify parameters as close as possible, otherwise you can * accidentally mark another function. * @param name is the function name. * @param params are the possible invocation parameters of the function. * @exception CompilationException if the method can't be resolved */ public void markStateDependent(String name, Class[] params) throws CompilationException { Object m; try { m=getMember(null,name,params); } catch (CompilationException exc) { if (exc.col<0) exc.col=0; throw exc; } Object removed=stateless.remove(m); if (Debug.enabled) Debug.check(removed!=null,"State dependent methos \""+m+ "\"is made state dependend again."); }; /** * Used to check if the given method is stateless. * @param o is method or field to check. * @return true if the method is stateless and can be invoked at * compile time. */ public boolean isStateless(Member o) { return stateless.containsKey(o); }; /** * Searches the namespace defined by this library object for method or field. *

The method with the same name, and closest (convertible) parameter * types is returned. If there are several methods the most specific one * is used. *

Ambiguities are detected. Example of detectable ambiguity:
* you ask for a call someName(int, int), but there are two * applicable methods someName(int, double) and * someName(double, int). Requirements to parameter types * of both can be satisfied by _widening_ conversions. Thus, there * is no most specific method of these two in terms of Java Language * Specification (15.11.2.2). It means, that an ambiguity is present, * and null will be returned. *

Java compiler normally would not allow to define such ambiguous * methods in the same class. However, as this library is assembled from * several Java classes, such ambiguities can happen, and should be * detected. * @param container the class to search the method within, if null * the root namespace is searched. * @param name is the name of the method to find. * @param params are the types of formal parameters in the method invocation. * @return the method/field object of the resolved method/field. * @exception CompilationException if the method can't be resolved */ public Member getMember(Class container,String name,Class[] params) throws CompilationException { HashMap> hashedMembers=names; // dot operator security if (container!=null) { if (dotClasses==null) // dot operator is prohibited throw new CompilationException(11,null); else if (! (noDotSecurity || dotClasses.containsKey(container))) { // dot is not allowed in this particular class Object[] paramsExc={container}; throw new CompilationException(12,paramsExc); }; if ((hashedMembers=dotClasses.get(container))==null) { rehash(container); hashedMembers=dotClasses.get(container); }; }; HashMap signatures=hashedMembers.get(name); // System.out.print("RESOLVING: "); // System.out.println(describe(name,params)); if (signatures==null) { // name is not found Object[] paramsExc={name,container}; throw new CompilationException(container==null?5:6,paramsExc); }; // Choose applicable methods List applicable_methods= getApplicable(container, name, params, signatures,-1); if (applicable_methods.size()==0) { // try varargs match List applicable_methods_with_varargs= getApplicable(container, name, params, signatures,params.length); if (applicable_methods_with_varargs.size()==0) { Object[] paramsExc={name,describe(name,params),container}; throw new CompilationException(container==null?7:8,paramsExc); } else { return getMostSpecific(container, name, params, applicable_methods_with_varargs,params.length); } } else { return getMostSpecific(container, name, params, applicable_methods,-1); } } /** * Returns applicable methods, for the call. * @param container class where the methods come from (if null the * method is assumed to be from static and dynamic libraries). * @param name method name. * @param params parameter types in the call * @param signatures list of method signatires to choose from. * @param np number of parameters in the call (must be equal either to * params.length for a varargs match or to -1 for usual match). */ protected List getApplicable(Class container,String name,Class[] params, HashMap signatures, int np) { if (Debug.enabled) Debug.check((np==-1||(np==params.length))); ArrayList applicable_methods=new ArrayList(); for(Member cm: signatures.values()) { Class[] cp=getParameterTypes(cm,np); boolean applicable=false; if (params!=null) { // if no parameters requested if (cp.length==params.length) { // If number of arguments matches applicable=true; for(int i=0;((i container,String name,Class[] params, List applicable_methods, int np) throws CompilationException { if (Debug.enabled) Debug.check((np==-1||(np==params.length))); // Search for the most specific method Iterator e=applicable_methods.iterator(); Member most_specific=e.next(); Class[] most_specific_params=getParameterTypes(most_specific,np); // System.out.println("--- APPLICABLE METHODS ---"); // System.out.println(most_specific.getName()+ // ClassFile.getSignature(most_specific)); while (e.hasNext()) { Member cm= e.next(); Class[] cp=getParameterTypes(cm,np); boolean moreSpecific=true; boolean lessSpecific=true; // System.out.println(cm.getName()+ClassFile.getSignature(cm)); for(int i=0; i[] params) { StringBuilder invp=new StringBuilder(); invp.append(name); invp.append('('); if (params!=null) for(int k=0;k ID's are used to locate the pointers to the objects, implementing * dynamic methods, in the array, argument of evaluate(Object[]) function. * @param m method to get an ID of. * @return the ID of the method or -1 if the method is static. * @exception NullPointerException if method is not a dynamic method of * this library. */ public int getDynamicMethodClassID(Member m) { Integer id=dynIDs.get(m); if (id==null) return -1; return id.intValue(); }; /** * Used to get return type of a class member. *

The type of a method is its return type, the type of a constructor is * void. * @param m member whose type is to be determined * @return type of the member */ public static Class getType(Member m) { if (m instanceof Method) return ((Method)m).getReturnType(); if (m instanceof Field) return ((Field)m).getType(); if (m instanceof LocalField) return ((LocalField)m).getType(); // otherwise it must be java.lang.reflect.Constructor if (Debug.enabled) Debug.check(m instanceof java.lang.reflect.Constructor); return OP.specialTypes[9]; // java.lang.reflect.Void.TYPE }; /** * Used to get types of formal parameters of a member. *

The reference to the class instance "this" is not counted by * this method. * @param m member whose formal parameters are to be obtained * @param np numer of parameters for varargs expansion (if np==-1 * or the last argument is not an array, the expansion is not * performed). It is also an error to pass the np, smaller * then the number of method parameters. * @return array of formal parameter types (empty array if none). */ public static Class[] getParameterTypes(Member m, int np) { Class[] params=null; if (m instanceof Method) params=((Method)m).getParameterTypes(); if (m instanceof LocalMethod) params=((LocalMethod)m).getParameterTypes(); if (m instanceof Constructor) params=((Constructor)m).getParameterTypes(); if (params!=null) { if ((np[] newparams=new Class[np]; for (int i=0; i[0]; } }; /** * Computes signature of the given member. * @param m the member to compute the sugnature of. * @return the signature. */ public static String getSignature(Member m) { StringBuilder signature=new StringBuilder(); if (!isField(m)) { Class parameters[]=getParameterTypes(m,-1); signature.append('('); for(int i=0;i The signature of the class (Field descriptor) is the string and * it's format is described in the paragraph 4.3.2 of the Java VM * specification (ISBN 0-201-63451-1). *

The same can be done using java.lang.Class.getName() by * converting it's result into the "historical form". *

This utility method can be used outside of the JEL package * it does not involve any JEL specific assumptions and should follow * JVM Specification precisely. * @param cls is the class to compute the signature of. Can be primitive or * array type. * @return the class signature. */ public static String getSignature(Class cls) { return appendSignature(new StringBuilder(),cls).toString(); }; private static StringBuilder appendSignature(StringBuilder buff, Class cls) { if (cls.isPrimitive()) { int tid; buff.append((tid=OP.typeID(cls))>9?'L':"ZBCSIJFDLV".charAt(tid)); } else if (cls.isArray()) { buff.append('['); appendSignature(buff,cls.getComponentType()); } else { // just a class buff.append('L'); appendHistoricalForm(buff,cls.getName()); buff.append(';'); }; return buff; }; public static String toHistoricalForm(String className) { return appendHistoricalForm(new StringBuilder(),className).toString(); }; private static StringBuilder appendHistoricalForm(StringBuilder buff, String className) { int namelen=className.length(); for(int i=0;i. */ package gnu.jel; //import gnu.jel.generated.EC; //import gnu.jel.generated.CharStream; import gnu.jel.debug.Debug; import java.lang.reflect.Member; /** * This is the main frontend to JEL. *

It is intended for compilation of algebraic expressions involving * functions. *

Syntax allows variables, which can be either a public fields of * certain objects or functions with no arguments. If a method like * "double x() {};" is defined in the dynamic library class * (see gnu.jel.Library documentation on how to do this), an * expression "sin(x)" will call the method "x()" ( * and function Math.sin() ) each time it is evaluated. * Static methods in namespace are assumed to be stateless (unless * this default behaviour is explicitly overridden, as is necessary * for Math.random()) and will be called at compile time if * their arguments are known. *

It is possible to have any type of intermediate object * throughout the calculation as long as types of the function return * values and parameters stay compatible. The compiler can * do all the type conversions permissible in Java language and more * (e.g. between reflection wrappers java.lang.Integer,... and * primitives). Widening type conversions (not leading to precision loss) * are applied by JEL automatically, narrowing should be explicitly * requested. *

There is variant of the "compile" function with three arguments, * which allows to fix the type of the expression result. For example: *

 * CompiledExpression expression=compile("2*6+6",lib,Double.TYPE); 
 * 
* will produce a compiled expression, whose return type is always * double. For additional information on how to use this * feature to eliminate object allocation overhead see * gnu.jel.CompiledExpression documentation. * *

Care should be taken during the assembly of static and dynamic libraries * to avoid conflicts and unexpected return types. * *

(c) 1998-2003, by Konstantin Metlov
* Prague, CZ * @see gnu.jel.CompiledExpression * @see gnu.jel.Library */ public class Evaluator { protected static ClassFile cf_orig; protected static int retID_patchback=0; protected static int retIDC_patchback=0; protected static LocalMethod[] eval_methods= new LocalMethod[10]; static { try { // prepare eval methods Class[] paramsE=new Class[1]; paramsE[0]=(new Object[0]).getClass(); Class[] excptnsE=new Class[1]; excptnsE[0]=Class.forName("java.lang.Throwable"); for(int i=0;i<10;i++) { String name="evaluate"; Class cls=OP.specialTypes[i]; if (i!=8) name=name+'_'+cls; else cls=(new Object()).getClass(); eval_methods[i]=new LocalMethod(0x0001,cls,name,paramsE,excptnsE); }; Class cmplExpr=Class.forName("gnu.jel.CompiledExpression"); ClassFile cf=new ClassFile(0x0001,"dump",cmplExpr,null,null); // public LocalMethod cnstr= new LocalMethod(0x0001,Void.TYPE,"",null,null); cf.newMethod(cnstr,null); cf.code(0x2a); //| aload_0 ;loads "this" cf.noteStk(-1,11); // not important what, it must be a reference cf.codeM(cmplExpr.getConstructor(new Class[0])); cf.noteStk(11,-1); cf.code(0xb1); //| return void LocalMethod getType= new LocalMethod(0x0001,Integer.TYPE,"getType",null,null); cf.newMethod(getType,null); cf.code(0x10); //| bipush retID_patchback=cf.tsize; cf.code(8); // type placeholder cf.noteStk(-1,4); // note "int" cf.code(0xAC); //| ireturn cf.noteStk(4,-1); // rm "int" Class clazz=Class.forName("java.lang.Class"); Class[] paramsC=new Class[1]; paramsC[0]=Class.forName("java.lang.String"); java.lang.reflect.Method forName=clazz.getMethod("forName",paramsC); Class[] excptnsC=new Class[1]; excptnsC[0]=Class.forName("java.lang.ClassNotFoundException"); LocalMethod getTypeC= new LocalMethod(0x0001,clazz,"getTypeC",null,excptnsC); cf.newMethod(getTypeC,null); cf.code(0x13); //| ldc_w retIDC_patchback=cf.tsize; cf.writeShort(0); //| Cp index to the class name cf.noteStk(-1,11); // note string load cf.codeM(forName); //| Class.forName cf.noteStk(11,8); // string replaced by "class" cf.code(0xB0); //| areturn cf.noteStk(8,-1); // rm "class" cf_orig=cf.clone(); } catch (Exception exc) { if (Debug.enabled) Debug.reportThrowable(exc); }; }; /** * Compiles expression, resolving the function names in the library. * @param expression is the expression to compile. i.e. "sin(666)" . * @param lib Library of functions exported for use in expression. * @param resultType identifies the type result should be converted to. Can * be null, in this case the result type is not fixed. * @return Instance of the CompiledExpression subclass, implementing * the specified expression evaluation. * @exception gnu.jel.CompilationException if the expression is not * syntactically or semantically correct. * @see gnu.jel.CompiledExpression */ public static CompiledExpression compile(String expression, Library lib, Class resultType) throws CompilationException { byte[] image=compileBits(expression,lib,resultType); try { return (CompiledExpression)(ImageLoader.load(image)).newInstance(); } catch (Exception exc) { if (Debug.enabled) Debug.reportThrowable(exc); return null; } }; /** * Compiles expression, resolving the function names in the library. *

This variant of compile allows to store expressions in a * java.io.OutputStream using Java serialization mechanism. * @param expression is the expression to compile. i.e. "sin(666)" . * @param lib Library of functions exported for use in expression. * @param resultType identifies the type result should be converted to. Can * be null, in this case the result type is not fixed. * @return Byte array, representing the expression * in a standard Java classfile format. It can be conveniently * loaded (with renaming, if necessary) * into Java VM using gnu.jel.ImageLoader. * @exception gnu.jel.CompilationException if the expression is not * syntactically or semantically correct. * @see gnu.jel.CompiledExpression * @see gnu.jel.ImageLoader */ public static byte[] compileBits(String expression, Library lib, Class resultType) throws CompilationException { OP code=parse(expression,lib,resultType); // Perform constants folding try { code=new OPload(code,code.eval()); } catch (Exception exc) { }; return getImage(code); }; /** * Compiles expression, resolving the function names in the library. * @param expression is the expression to compile. i.e. "sin(666)" . * @param lib Library of functions exported for use in expression. * @return Instance of the CompiledExpression subclass, implementing * the specified expression evaluation. * @exception gnu.jel.CompilationException if the expression is not * syntactically or semantically correct. * @see gnu.jel.CompiledExpression */ public static CompiledExpression compile(String expression, Library lib) throws CompilationException { return compile(expression, lib, null); }; /** * Compiles expression, resolving the function names in the library. *

This variant of compile allows to store expressions in a * java.io.OutputStream using Java serialization mechanism. * @param expression is the expression to compile. i.e. "sin(666)" . * @param lib Library of functions exported for use in expression. * @return Byte array, representing the expression * in a standard Java classfile format. It can be conveniently * loaded (with renaming, if necessary) * into Java VM using gnu.jel.ImageLoader. * @exception gnu.jel.CompilationException if the expression is not * syntactically or semantically correct. * @see gnu.jel.CompiledExpression * @see gnu.jel.ImageLoader */ public static byte[] compileBits(String expression, Library lib) throws CompilationException { return compileBits(expression, lib, null); }; static OP parse(String expression, Library lib, Class resultType) throws CompilationException { return (new Parser(expression,lib)).parse(resultType); // return (new EC(new CharStream(expression))).parse(resultType,lib); }; static byte[] getImage(OP code) { int retID=code.resID; ClassFile cf=cf_orig.clone(); // set return type int otsize=cf.tsize; cf.tsize=retID_patchback; cf.write((byte)retID); cf.tsize=otsize; String retName; if ((retID<8)) retName=OP.specialTypes[20+retID].getName(); else if (retID==9) retName="java.lang.Void"; else retName=code.resType.getName(); // set return class otsize=cf.tsize; cf.tsize=retIDC_patchback; cf.writeShort(cf.getIndex(retName,8)); cf.tsize=otsize; // add the evaluate method cf.newMethod(eval_methods[retID],null); code.compile(cf); return cf.getImage(); }; }; source/src/java/gnu/jel/OPload.java0000644000175000017500000000604412714113765016153 0ustar olesoles/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * This file is part of the Java Expressions Library (JEL). * For more information about JEL visit : http://fti.dn.ua/JEL/ * * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2006, 2007, 2009 Konstantin L. Metlov * * 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 . */ package gnu.jel; import gnu.jel.debug.Debug; /** * A tree node, representing loading of a constant. */ public class OPload extends OP { /** Holds an object to be loaded */ public Object what; /** * Creates an OP, loading a constant. * @param what is a constant wrapped into a reflection object. E.g * java.lang.Integer(1) to load 1 of * primitive type int. */ public OPload(Object what) { this.resID=typeIDObject(what); if (Debug.enabled) Debug.check((resID!=8)); this.resType=specialTypes[resID]; this.what=what; }; /** * Creates an OP, loading a constant to be put instead of another OP. *

For private JEL usage in constants folding. * @param instead an OP, which will be raplaced by this OPload. * @param what is a constant wrapped into a reflection object. E.g * java.lang.Integer(1) to load 1 of * primitive type int. */ public OPload(OP instead,Object what) { if (Debug.enabled) { if (!( ( (typeIDObject(what)==instead.resID) && (instead.resID!=8) ) || ( (instead.resID==10) && (what instanceof StringBuffer) ) ) ) { Debug.println("typeIDObject(what)="+ typeIDObject(what)); Debug.println("instead.resID="+instead.resID); Debug.println("what="+what); Debug.println("what.getClass()="+what.getClass()); }; Debug.check(( (typeIDObject(what)==instead.resID) && (instead.resID!=8) ) || ( (instead.resID==10) && (what instanceof StringBuffer) ) ); }; this.resType=instead.resType; this.resID=instead.resID; this.what=what; }; public Object eval() throws Exception { return what; }; public void compile(ClassFile cf) { cf.codeLDC(what,resID); }; }; source/src/java/gnu/jel/CompilationException.java0000644000175000017500000000552112714113765021131 0ustar olesoles/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * This file is part of the Java Expressions Library (JEL). * For more information about JEL visit : http://fti.dn.ua/JEL/ * * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2006, 2007, 2009 Konstantin L. Metlov * * 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 . */ package gnu.jel; import gnu.jel.debug.Debug; import java.text.MessageFormat; /** * Represents an error encountered during the compilation. *

The text of the messages can be changed/internationalized by * modification of JEL.properties file */ @SuppressWarnings("serial") public class CompilationException extends Exception { public int col=-1; private int code=-1; // error code private Object[] params=null; // parameters to generate messages /** * Constructs new CompilationException with a single formatting parameter. * @param code is the error code (must correspond to a message in * JEL.properties file). * @param param is the single Object parameter or an array of Objects to * be used in message formatting. */ public CompilationException(int code, Object param) { if (Debug.enabled) Debug.check(code>=0); this.code=code; if (param!=null) if (param.getClass().isArray()) this.params=(Object[])param; else { Object[] temp={param}; this.params=temp; } } /** * Used to obtain the column, where error have occurred. * @return column, where error have occurred. */ public int getColumn() { return col; }; /** * Used to obtain the error code. * @return the error code, corresponding to one of the messages in * JEL.properties file. */ public int getType() { return code; }; /** * Used to obtain the parameters for this error. * @return the parameters to be used in message formatting, they provide * further information about the error. */ public Object[] getParameters() { return params; }; /** * Used to obtain the formatted error message. * @return the formatted error message. */ public String getMessage() { if (Debug.enabled) Debug.check(col>=0); return TableKeeper.getMsg(code,params); }; }; source/src/java/gnu/jel/debug/0000755000175000017500000000000012714113765015214 5ustar olesolessource/src/java/gnu/jel/debug/Debug.java0000644000175000017500000000743512714113765017116 0ustar olesoles/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * This file is part of the Java Expressions Library (JEL). * For more information about JEL visit : http://fti.dn.ua/JEL/ * * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2006, 2007, 2009 Konstantin L. Metlov * * 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 . */ package gnu.jel.debug; /** * This class used for incorporating internal checks and * assertions into the code. *
None of these functions does anything if Debug.enabled is false. *
If you really want to throw ALL debug messages from the final, * compiler generated, code -- wrap calls to Debug methods into the * if statement, checking Debug.enabled constant. * As shown in the example : *

 * import cz.fzu.metlov.jel.*;
 * ..... BLA BLA BLA ...
 * if (Debug.enabled) {
 *  Debug.println("I want this message to disappear in the optimized version");
 *  Debug.check(foo==superTimeConsumingFunction(bar), 
 * "I do not want to evaluate superTimeConsumingFunction(), when optimized."); 
 * }; 
 *
*/ public final class Debug { /** * Determines if debugging is enabled in current compilation. */ public final static boolean enabled=@DEBUG@; // <-- AUTO GENERATED /** * Prints a line of the debug output. * The resulting line goes to System.err and is prefixed by "[DEBUG] ". * @param message message to print. */ public final static void println(String message) { if (enabled) { System.err.print("[DEBUG] "); System.err.println(message); }; }; /** * Checks for the condition. * If condition is false this function prints a given message * to the System.err along with the stack trace. * @param condition is the condition to check. * @param message is the message to print if condition is false. */ public final static void check(boolean condition, String message) { if (enabled && (!condition)) { System.err.print("Assertion failed :"); System.err.println(message); Throwable tracer=new Throwable(message); tracer.printStackTrace(); }; }; /** * Checks for the condition. * If condition is false this function prints a "Assertion failed." * to the System.err along with the stack trace. * @param condition is the condition to check. */ public final static void check(boolean condition) { if (enabled && (!condition)) { Throwable tracer=new Throwable("Assertion failed."); tracer.printStackTrace(); }; }; /** * Reports an exception, which should not occur(i.e. handled improperly). * @param t is what was thrown. * @param message is algorithm specific message. */ public final static void reportThrowable(Throwable t,String message) { if (enabled) { System.err.println("Unexpected exception has occured :"); System.err.println(message); t.printStackTrace(); }; }; /** * Reports an exception, which should not occur(i.e. handled improperly). * @param t is what was thrown. */ public final static void reportThrowable(Throwable t) { if (enabled) { System.err.println("Unexpected exception has occured :"); t.printStackTrace(); }; }; }; source/src/java/gnu/jel/OP.java0000644000175000017500000002012712714113765015311 0ustar olesoles/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * This file is part of the Java Expressions Library (JEL). * For more information about JEL visit : http://fti.dn.ua/JEL/ * * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2006, 2007, 2009 Konstantin L. Metlov * * 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 . */ package gnu.jel; import gnu.jel.debug.Debug; import java.util.Stack; /** * A tree node, representing an operation. */ public abstract class OP { /** Holds references to children of this node */ public OP[] chi=null; /** Holds type ID of the result of this OP */ public int resID; /** Holds type of the result of this OP */ public Class resType; /** * Called to evaluate this node and all its sub-nodes. *

Upon success this node is to be replaced by the constant node * holding the returned object. * @return an object to which this node evaluates * @exception if can't evaluate, in this case the sub-nodes */ public abstract Object eval() throws Exception; /** * Called to generate the code implementing this OP. * @param cf class file with a new open method to write the code into. */ public abstract void compile(ClassFile cf); //====================================================== // Utility methods for dealing with types, etc... //====================================================== /** * Classes of the special types by ID. *

The frequently used types (those on which many operations are * defined) are identified by an integer number. The advantage is * the possibility to have almost completely table driven code generator. *

So, the special types are only special in the fact that except * of the reference to their class object they are also identified by an * integer number. */ public final static Class[] specialTypes; // defined in gnu.jel.TablesKeeper /** * Unwraps the type ID. *

That is all special types which are references are translated into 8. */ public final static byte[] unwrapType; static { specialTypes=(Class[])TableKeeper.getTable("specialTypes"); unwrapType=(byte[]) TableKeeper.getTable("unwrapType"); }; /** * Identifies the primitive type of the given class. * @param c class to identify. * @return id of the corresponding primitive type. */ public static final int typeID(Class c) { final int NUM_SPECIAL_PRIMITIVE_TYPES=10; // ^^^ it is the number of primitive types out of special ones if (c==null) return 8; if (c.isPrimitive()) { int i; for(i=0;(it2 is widening. * @param id1 type ID to convert from * @param c1 class to convert from (used if id1==8) * @param id2 type ID to convert to * @param c2 class to convert to (used if id2==8) * @return true if the given conversion is widening (can be done * automatically) */ public static boolean isWidening(int id1, Class c1, int id2, Class c2) { if (c2 == java.lang.Object.class) return true; // everything (including the primitives) is convertible to Object if (c2 == java.lang.Number.class) { id1=unwrapType[id1]; return (id1<8) && (id1!=0) && (id1!=2); // convertible to Number } if (((id2<=11)|| ((id2>=20)&&(id2<=27)) ) && (id2!=8)) { // converting into primitive (or into wrapped primitive) id1=unwrapType[id1]; id2=unwrapType[id2]; if (Debug.enabled) Debug.check(id1> id1)) >0; }; // converting into object if (id1>=8) { // converting object into object if (c1==c2) return true; // for nulls also if (c1==null) return true; // "null" can be widened to any reference if (c2==null) return false; // assignment to "null" is narrowing return c2.isAssignableFrom(c1); // can assign references }; // primitive into object is certainly not widening return false; }; /** * Used to find out if the conversion t1->t2 is widening. * @param c1 class to convert from (used if id1==8) * @param c2 class to convert to (used if id2==8) * @return true if the given conversion is widening (can be done * automatically) */ public static boolean isWidening(Class c1, Class c2) { return isWidening(typeID(c1),c1,typeID(c2),c2); }; /** * Makes widest possible representation of a value of Java primitive type. * @param o reflection object, containing value to represent. * @param clsID ID of a type of this reflection object (to save lookup). * @return Number, representing the given value. */ protected static Number widen(Object o, int clsID) { switch (clsID) { case 0: // Z if (((Boolean)o).booleanValue()) return new Long(1L); else return new Long(0L); case 1: // B return (Number)o; case 2: // C return new Long((long)((Character)o).charValue()); case 3: // S case 4: // I case 5: // J case 6: // F case 7: // D return (Number)o; default: if (Debug.enabled) Debug.println("Attempt to widen wrong primitive ("+clsID+")."); return new Long(0L); } }; /** * Narrows the value back to desired primitiva type. * @param val reflection object, containing value to narrow. * @param clsID ID of a type to narrow the given object into. * @return narrowed reflection object. */ protected static Object narrow(Number val, int clsID) { switch (clsID) { case 0: // Z if (val.longValue()!=0) return Boolean.TRUE; else return Boolean.FALSE; case 1: // B return new Byte(val.byteValue()); case 2: // C return new Character((char)val.longValue()); case 3: // S return new Short(val.shortValue()); case 4: // I return new Integer(val.intValue()); case 5: // J return new Long(val.longValue()); case 6: return new Float(val.floatValue()); case 7: return new Double(val.doubleValue()); default: if (Debug.enabled) Debug.println("Attempt to narrow wrong primitive ("+clsID+")."); return null; } }; }; source/src/java/gnu/jel/JEL.properties0000644000175000017500000000337212714113765016663 0ustar olesolese1=\ Encountered unexpected end of expression. e2=\ Encountered unexpected token "{0}". e3=\ Encountered unexpected character ''{0}''. e4=\ The type "{0}" is unknown. e5=\ The name "{0}" is unknown. e6=\ There is no field/method "{0}" in the class "{1}". e7=\ Function "{0}" exists but parameters "{1}" can not be accepted by it. e8=\ Method "{0}" exists in {2} but parameters "{1}" can not be accepted by it. e9=\ Ambiguity detected between "{0}" and "{1}" on invocation "{2}". e10=\ Ambiguity detected between "{0}" and "{1}" on invocation "{2}" in {3}. e11=\ The access to class members is not allowed. e12=\ The access to members of {0} is not allowed. e13=\ The number "{0}" is too large it does not fit even in 64 bit long. e14=\ The number "{0}" is too large for type int, be sure to add 'L' suffix to use the long type. e15=\ Types "{0}" and "{1}" are incompatible for "{2}" operation. e16=\ The "{0}" operation is not defined for {1} and {2}. e18=\ The first operand for the array element access operation must be an array. e21=\ Can''t convert {0} to {1}. e22=\ You must specify the narrowing conversion from {0} to {1} explicitly. e23=\ First argument of conditional must be of boolean type. e24=\ Branches of conditional are references to {0} and {1} and are not compatible. e25=\ Branches of conditional must be either both of primitive types or both be references. e26=\ Dynamic variable can''t have the formal parameters. e27=\ Second argument of "{0}" must be of integral type but {1} is not. e28=\ The "{0}" operation is not defined for {1}. e29=\ The integer literal "{0}" is too large for type int, try adding ''L'' at the end. e30=\ The integer literal is too large for type long. e31=\ The floating point literal is too large. source/src/java/gnu/jel/DVMap.java0000644000175000017500000000634012714113765015743 0ustar olesoles/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * This file is part of the Java Expressions Library (JEL). * For more information about JEL visit : http://fti.dn.ua/JEL/ * * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2006, 2007, 2009 Konstantin L. Metlov * * 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 . */ package gnu.jel; /** * Provides the information about defined dynamic variables. *

Allows to translate variable names into * constants of Java primitive types at compile-time. See the section of the * manual on dynamic variables. */ public abstract class DVMap { /** * Returns the name of the type of the named property. *

The dot ('.') symbol can be present in the property name to denote * hierarchical naming scheme. *

If hierarchical naming scheme is used and the variable * x.y is defined the variable x must also be defined. * @param name is the name of the property. * @return the XXX in the name of the corresponding getXXXProperty() * method of dynamic library, null if the variable with the given name * is not defined. */ public abstract String getTypeName(String name); /** * Translates the variable name (a String) to a constant of any primtive * type (e.g. a number). * *

The performance of the compiled code can be sometimes improved * by letting it not to deal with strings. For example, in older JEL <=0.9.8 * this method was absent, and, if the underlying representation of the * dynamic variables storage was an array, the translation of variable name * (represented by String) into integer index had to happen at run-time, * taking up the valuable processor cycles. Defining the proper * DVMap.translate one can perform the translation * "variable name(String)"->"slot number(int)" at compile * time. There can be also other clever ways of using translation to * improve performance even if variables are not stored in an array or * vector. *

The default implementation provides the identity translation, which * simulates the behaviour of older versions of JEL. * * @since 0.9.9 * @param name Name of the variable to be translated. * @return Object representing the translated name, this object must be * either a reflection type wrapping a primitive (e.g. java.lang.Integer, * java.lang.Byte) or String. No other object is allowed, othwerwise an * exception will emerge at compile-time. This limitation is due to Java * class file format not allowing to store constants of types other than * specified above. */ public Object translate(String name) { return name; }; }; source/src/java/gnu/jel/OPunary.java0000644000175000017500000002633012714113765016372 0ustar olesoles/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * This file is part of the Java Expressions Library (JEL). * For more information about JEL visit : http://fti.dn.ua/JEL/ * * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2006, 2007, 2009 Konstantin L. Metlov * * 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 . */ package gnu.jel; import gnu.jel.debug.Debug; import java.util.Stack; /** * A tree node, representing unary operation. */ public class OPunary extends OP { /** code of this operation */ public int code; private int uwrpCode=0; // what to code to unwrap the object private int implCode=0; private int uwrpsTo=-1; // The full list of codes is : // 0 -- negation (applicable to anything except boolean) // 1 -- bitwise not (applicable to all integral types) // 2 -- logical not (applicable to booleans only) // 3 -- return // 4 -- convert to boolean // 5 -- convert to byte // 6 -- convert to char // 7 -- convert to short // 8 -- convert to int // 9 -- convert to long // 10 -- convert to float // 11 -- convert to double // 12 -- convert to object (in this case the cls parameter gives class) // 13 -- convert to void (throw from stack) // 14 -- convert string to temporary string buffer (TSB) // 15 -- convert temporary string buffer (TSB) to string /** unary promotions of base types */ protected final static byte[] unary_prmtns; private final static int[][] una; private final static String[] opNames; static { unary_prmtns=(byte[])TableKeeper.getTable("unary_prmtns"); una=(int[][])TableKeeper.getTable("una"); opNames=(String[])TableKeeper.getTable("opNames"); if (Debug.enabled) Debug.check((opNames.length==una.length)); }; /** * Constructs a new unary operation. *

Codes are following: *

   * 0  -- negation (applicable to anything except boolean)
   * 1  -- bitwise not (applicable to all integral types)
   * 2  -- logical not (applicable to booleans only)
   * 3  -- return the type in stack
   * 
* @param paramOPs stack holding the operands * @param code operation code */ public OPunary(Stack paramOPs, int code) throws CompilationException { if (Debug.enabled) Debug.check((code>=0) && (code<=3)); this.code=code; chi=new OP[1]; chi[0]=paramOPs.pop(); int opID=chi[0].resID; Class opType=chi[0].resType; if (code==3) { // return // everything can be returned no checks/unwraps needed resID=(opID>9?8:opID); // computes base type resType=opType; implCode=una[code][resID]; } else { // unwrap object if can int unwrpID=unwrapType[opID]; if (unwrpID!=opID) { uwrpCode=((opID-12+11)<<8)+0x00FE; uwrpsTo=unwrpID; }; if ((implCode=una[code][unwrpID])==0xFF) { // operation is not defined on types Object[] paramsExc={opNames[code],opType}; throw new CompilationException(28,paramsExc); }; resID=unary_prmtns[unwrpID]; resType=specialTypes[resID]; }; }; /** * Creates conversion operation to the given class. * @param paramOPs stack holding the operands * @param targetID ID of primitive type to convert to. * @param targetClass the class to convert to, in case cldID=8 * @param allownarrowing if narrowing conversions are allowed. */ public OPunary(Stack paramOPs, int targetID, Class targetClass, boolean allownarrowing) throws CompilationException { if (Debug.enabled) { // check for proper target type was identification Debug.check(((targetID==8)^(targetClass==null)) || ((targetID!=8)&& (specialTypes[targetID].isAssignableFrom(targetClass))) ); if (targetID==8) { Debug.check(typeID(targetClass)==targetID, "The type was improperly identified for OPunary conv."); }; }; // set the result type resID=targetID; resType=(targetClass!=null?targetClass:specialTypes[targetID]); chi=new OP[1]; chi[0]=paramOPs.pop(); Class currClass=chi[0].resType; int currID=chi[0].resID; int unwrappedCurrID=unwrapType[currID]; // there are folowing cases: // 1) unwrappable object to primitive // 2) string-like to string // 3) string or string-like to TSB // 4) TSB to string // 5) primitive (or unwrappable to primitive) to primitive // 6) primitive (or unwrappable to primitive) to wrapper object // 7) primitive (or onwrappable to primitive) of numeric type into java.lang.Number // or java.lang.Object // 8) general object to object // object to object // error (object -> primitive, primitive->object) code=4+resID; if ((resID>=8) && (resID!=10) && (currID!=10) && (!((currID==28) && ((resID==10) || (resID==11))))) { // here we have the following cases: // 6) primitive (or unwrappable to primitive) to wrapper object // 8) general object to object boolean boxToSuperclass= ((targetClass == java.lang.Number.class) && (unwrappedCurrID!=0) && (unwrappedCurrID!=2)) || (targetClass == java.lang.Object.class); // box to Number or Object if ((unwrappedCurrID<8) && (((resID>=20) && (resID<=27)) || boxToSuperclass)) { // 6) primitive (or unwrappable to primitive) to wrapper object (boxing) // 7) primitive (or onwrappable to primitive) of numeric type into java.lang.Number // or java.lang.Object if (boxToSuperclass) resID = 20 + unwrappedCurrID; code = 4 + resID - 20; // perform the usual type conversion // (the object itself is created in compile and eval) if (unwrappedCurrID!=currID) { // TODO (*) eliminate the duplicate block uwrpCode=((currID-12+11)<<8)+0x00FE; uwrpsTo=unwrappedCurrID; } } else { // 8) general object to object code=4+8; unwrappedCurrID=8; } } else { // 1) unwrappable object to primitive // 2) string-like to string // 3) string or string-like to TSB // 4) TSB to string // 5) primitive (or unwrappable to primitive) to primitive if (unwrappedCurrID!=currID) { // TODO (*) eliminate the duplicate block uwrpCode=((currID-12+11)<<8)+0x00FE; uwrpsTo=unwrappedCurrID; }; }; if ((implCode=una[code][unwrappedCurrID])==0xFF) { //Debug.println("code="+code); // can't convert at all Object[] paramsExc={currClass,resType}; throw new CompilationException(21,paramsExc); }; if (!(allownarrowing || isWidening(currID,currClass,resID,resType))) { // can't do narrowing conversions automatically Object[] paramsExc={currClass,resType}; throw new CompilationException(22,paramsExc); }; }; public void compile(ClassFile cf) { if (code==2) cf.code(0xFB); // equivalent to cf.labels_block(); if (code==14) { cf.code(0x0001FE591DFDBBL); // ANY => TSB // | new // // | dup // | invokespecial StringBuffer() cf.noteStk(-1,10); // pushes ref to TSB }; int cvtResult=resID; if ((code>=4) && (code<=4+7) && (resID>=20) && (resID<=27)) { cvtResult=resID-20; // result of the type conversion // create new object on stack cf.code(0x5900FDBBL+((resID)<<16)); // | new // | // | dup cf.noteStk(-1, 8); cf.noteStk(-1, 8); // pushes two refs to the created object }; chi[0].compile(cf); cf.code(uwrpCode); // unwrap object if needed if (uwrpsTo>=0) cf.noteStk(chi[0].resID,uwrpsTo); // note the unwrapping on stack cf.code(implCode); if (code==12) // code CP index for conversion to reference cf.writeShort(cf.getIndex(resType,9)); // get rid of this switch is the task for the NEXT major update switch(code) { case 2: // logical inversion does not change stack case 4: // conversion to boolean does not change stack as well // if it was a jump, jump is preserved break; case 3: case 13: cf.noteStk(resID,-1); // return and (void) throw one word, add nothing break; case 14: cf.noteStk(11,-1); break; case 1: // bitwise not may have excess item on stack cf.noteStk(-1,resID); cf.noteStk(resID,-1); default: // other ops throw one word replace it by another cf.noteStk(uwrpsTo>=0?uwrpsTo:chi[0].resID,cvtResult); }; if ((code>=4) && (code<=4+7) && (resID>=20) && (resID<=27)) { // finish creating of the wrapper object by calling its constructor cf.code(0x00FEL+((29+resID-20)<<8)); // | invokespecial java.lang.[Boolean, Char,...] ([boolean, char, ...]) cf.noteStk(resID-20, 0); // the wrapped value is gone from the stack cf.noteStk(8,-1); // one reference to the created wrapper object is gone // one reference to the created wrapper object remains } }; public Object eval() throws Exception { Object operand=chi[0].eval(); int operand_resID=chi[0].resID; if ((code==3) || (code==13) || (code==12)) { // do not evaluate, just replace operand chi[0]=new OPload(chi[0],operand); throw new Exception(); // bail out }; if (code==2) { // logical not if (((Boolean)operand).booleanValue()) operand=Boolean.FALSE; else operand=Boolean.TRUE; } else if (code<2) { Number val=widen(operand,operand_resID); switch(code) { case 0: // negation if (operand_resID>5) val=new Double(-val.doubleValue()); else val=new Long(-val.longValue()); break; case 1: // bitwise complement val=new Long(~val.longValue()); break; default: if (Debug.enabled) Debug.check(code>=0,"Wrong unary opcode."); }; operand=narrow(val,resID); } else { // conversion operations if (code==14) { // ANY->TSB operand=new StringBuffer(String.valueOf(operand)); } else if (code==15) { // TSB->STR operand=operand.toString(); } else { if (resID>=20) throw new Exception(); // do not evaluate boxing conversions (can't store result) operand=narrow(widen(operand,operand_resID),resID); }; }; return operand; }; }; source/src/java/gnu/jel/OPcall.java0000644000175000017500000002352612714113765016153 0ustar olesoles/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * This file is part of the Java Expressions Library (JEL). * For more information about JEL visit : http://fti.dn.ua/JEL/ * * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2006, 2007, 2009 Konstantin L. Metlov * * 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 . */ package gnu.jel; import java.lang.reflect.Array; import java.lang.reflect.Member; import java.lang.reflect.Field; import java.lang.reflect.Method; import gnu.jel.debug.Debug; import java.util.Stack; /** * A tree node, representing a method call (field/local variable load). */ public class OPcall extends OP { /** Holds method to be executed */ public Member m; // member to eval (null for the local variable access) /** * local variable number (in case m=null), number of formal * parameters of the method to call otherwise. */ public int nplv=0; /** * if evaluation of the method will be attempted at compile-time */ private boolean aEval=false; /** * if the varagrs expansion is used va is the number of the * parameters at the tail of the call to be converted into the * array. */ private int va=0; /** * Prepares a new method/field call/get operation to be added to the code. * @param m method/field to call/get. * @param np number of actual formal parameters (not considering "this") * @param paramOPs stack holding the operands * @param aEval indicates if the method call should be attempted * at the compile time */ public OPcall(Member m, int np, Stack paramOPs, boolean aEval) throws CompilationException { this.m=m; // if method is not static note "this" int thisIdx=((m.getModifiers() & 0x0008) == 0)?-1:0; Class[] reqParamTypes=Library.getParameterTypes(m,-1); // determine if we need to do the varargs expansion // The Library had already made this decision, but we do it // in AST too because it can be used independently. if (reqParamTypes.length>0) { Class LA=reqParamTypes[reqParamTypes.length - 1]; if (np>reqParamTypes.length) va=np-reqParamTypes.length+1; else if (LA.isArray()) { if (Debug.enabled) Debug.check(np == reqParamTypes.length); // if the argument number is matching exactly we analyze the last arg type OP cop=paramOPs.peek(); if ((!isWidening(cop.resType,LA)) && isWidening(cop.resType, LA.getComponentType())) va=1; } } if (va>0) reqParamTypes=Library.getParameterTypes(m, np); nplv=reqParamTypes.length; if (thisIdx==-1) nplv++; // method is not static this.chi=new OP[nplv]; // convert formal and actual parameter types and "this", if needed for(int i=reqParamTypes.length-1;i>=thisIdx;i--) { Class cReq=(i>=0?reqParamTypes[i]:m.getDeclaringClass()); OP cop=paramOPs.peek(); // add convert type OP if ((cop.resID==10) || (cop.resType!=cReq)) paramOPs.push(new OPunary(paramOPs,typeID(cReq),cReq,i<0)); chi[i-thisIdx]=paramOPs.pop(); }; // push & store the result type resType=Library.getType(m); resID=typeID(resType); // System.out.println("MAKING CALL TO "+m.getName()+ // ClassFile.getSignature(m)+" returning "+ // m.getType()); // determine if compile-time evaluation should be attempted this.aEval=(aEval && // eval only if requested. ((m.getModifiers() & 0x0008)!=0) && // if static ((resID<=7) || (resID==11)) // if can store result ); }; /** * Prepares access to the local variable (formal parameter) of method. * @param lvarn local variable number. * @param type local variable type. */ public OPcall(int lvarn, Class type) { this.m=null; this.nplv=lvarn; resID=typeID(type); resType=type; }; /** * Attempts to evaluate this function. * @return the OPload, representing the function's result (if it can \ * be evaluated). * @throws Exception if the function can't be evaluated, or the evaluation * results in error. */ public Object eval() throws Exception { Object[] params=new Object[chi.length]; boolean[] evaltd=new boolean[chi.length]; Exception exception=null; for(int i=0;i0) { // convert varargs Object[] newparams=new Object[chi.length-va+1]; Class[] reqParamTypes=Library.getParameterTypes(m,-1); Class arrpar=reqParamTypes[reqParamTypes.length-1]; // copy the leading parameters for (int i=0;i LA=null; int tID=0; for(int i=0;i[] reqParamTypes=Library.getParameterTypes(m,-1); LA=reqParamTypes[reqParamTypes.length - 1].getComponentType(); tID=typeID(LA); cf.codeLDC(new Integer(va),4); // push item count to the stack if (tID<8) { // array of primitive types cf.code(0xbc); // | newarray cf.code(arrayTypeCodes[tID]); // | } else { // array of references cf.code(0xbd); // | anewarray cf.writeShort(cf.getIndex(LA,9)); // | } cf.noteStk(4, 8); // element count comes out, array ref comes in } if (i>=chi.length-va) { cf.code(0x59); // | dup cf.noteStk(-1, 8); // another array ref comes in cf.codeLDC(new Integer(i-chi.length+va),4); // load array index } chi[i].compile(cf); // compile the argument value cf.code(0xFA); // ensure value in stack if (i>=chi.length-va) { cf.code(arrayStoreCodes[tID>8?8:tID]); cf.noteStk(chi[i].resID, -1); // value comes out cf.noteStk(4, -1); // index comes out cf.noteStk(8, -1); // arrayref comes out } } cf.code(0xF8); // labels unblock; for(int i=0;i0) cf.noteStk(8,-1); // array ref (in case of varargs) comes out cf.codeM(m); // call the method / get field }; cf.noteStk(-1,resID); // result of the call comes in }; }; source/src/java/gnu/jel/LocalField.java0000644000175000017500000000533412714113765016774 0ustar olesoles/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * This file is part of the Java Expressions Library (JEL). * For more information about JEL visit : http://fti.dn.ua/JEL/ * * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2006, 2007, 2009 Konstantin L. Metlov * * 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 . */ package gnu.jel; import gnu.jel.debug.Debug; import java.lang.reflect.Member; /** * Represents a field local to the class being compiled. */ public class LocalField implements Member { private int modifiers; private java.lang.String name; private Class type; private Object constValue; /** * Constructs a new local field. * @param modifiers field modifiers, a sum of one or more of PUBLIC, * PRIVATE,PROTECTED, STATIC, * FINAL,VOLATILE, TRANSIENT * constants defined in java.lang.reflect.Modifier * @param type is a class representing the type of this field. * @param name is the name of this field. * @param constValue is the value of this field if it is static final, * null otherwise. */ public LocalField(int modifiers, Class type, java.lang.String name, Object constValue){ if (Debug.enabled) Debug.check((constValue==null) || ((modifiers & 0x0018) ==0x0018)); this.type=type; this.name=name; this.modifiers=modifiers; this.constValue=constValue; }; public Class getDeclaringClass() { return null; // means local field }; public java.lang.String getName() { return name; }; public int getModifiers() { return modifiers; }; public Class getType() { return type; }; public boolean isSynthetic() { return true; }; /** * Returns a value of the public static final field. *

Fails assertion if called on the field which is not public * static final. * @return value of the field, object of wrapped primitive type or string. */ public Object getConstValue() { if (Debug.enabled) Debug.check(constValue!=null); return constValue; }; }; source/src/java/gnu/jel/ClassFile.java0000644000175000017500000010253212714113765016641 0ustar olesoles/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * This file is part of the Java Expressions Library (JEL). * For more information about JEL visit : http://fti.dn.ua/JEL/ * * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2006, 2007, 2009 Konstantin L. Metlov * * 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 . */ package gnu.jel; import gnu.jel.debug.Debug; import java.lang.reflect.Member; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Constructor; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.io.IOException; import java.util.HashMap; import java.util.Stack; import java.util.Vector; /** * This class represents a classfile image in JEL. */ public class ClassFile implements Cloneable { // constant pool handling private int poolEntries=1; // Number of entries in the constant pool // the class name is in the first element of the CP // it is not written by default to enable the dynamic class renaming. private ByteArrayOutputStream constPoolData; private DataOutputStream constPool; // Constant pool hashing : // In next hashtables keys are Objects, values their CP indices // UTFs require special handling since their keys can be the same as // ones of strings private HashMap Items=new HashMap(); private HashMap UTFs=new HashMap(); // holds code of all methods private int nMethods=0; private int nMethodsPatch; // holds code of all methods private byte[] text; int tsize=0; // write a byte void write(int b) { try { text[tsize++]=(byte)b; } catch (ArrayIndexOutOfBoundsException exc) { byte[] new_text=new byte[text.length<<1]; System.arraycopy(text, 0, new_text, 0, tsize-1); text=new_text; text[tsize-1]=(byte)b; }; }; // write short void writeShort(int v) { write((v >>> 8) & 0xFF); write( v & 0xFF); }; // write int void writeInt(int v) { write((v >>> 24) & 0xFF); write((v >>> 16) & 0xFF); write((v >>> 8) & 0xFF); write( v & 0xFF); }; private boolean isInterface; private IntegerStack[] cstk=new IntegerStack[6]; // six stacks // 0) "false" jumps // 1) "true" jumps // 2) unconditional jumps // 3) "false" blocks // 4) "true" blocks // 6) unconditional blocks /** * Starts creation of a new class file. *

Sizes of fAccess, fNames and fTypes * arrays must be the same. * @param modifiers sum of one or more of PUBLIC, FINAL, * INTERFACE, ABSTRACT * constants of java.lang.reflect.Modifier * @param name is the name of new class (must be in Java historical form, * i.e. with dots replaced by slashes '/') * @param superClass is the superclass of this class * @param interfaces array of interfaces this class implements * @param fields fields this class will have */ public ClassFile(int modifiers,String name,Class superClass, Class[] interfaces,LocalField[] fields) { constPoolData=new ByteArrayOutputStream(); constPool=new DataOutputStream(constPoolData); text=new byte[256]; if (Debug.enabled) Debug.check(cstk.length==6); for (int i=0;i<6;i++) cstk[i]=new IntegerStack(); try { if (Debug.enabled) // check if the name is in historical form Debug.check(name.indexOf('.')==-1); getUTFIndex(name); // must be the first entry if (Debug.enabled) Debug.check((modifiers & ~(java.lang.reflect.Modifier.PUBLIC+ java.lang.reflect.Modifier.FINAL+ java.lang.reflect.Modifier.INTERFACE+ java.lang.reflect.Modifier.ABSTRACT))==0); isInterface=((modifiers & 0x0200)>0); // write modifiers writeShort(modifiers | 0x0020); // set ACC_SUPER flag // CONSTANT_CLASS for a new class, has to be written by hand // since no corresponding java.lang.Class object exists yet. if (Debug.enabled) Debug.check(poolEntries==2); poolEntries++; constPool.write(7); constPool.writeShort(1); //name of this class is always the first entry. // write class cp index writeShort(2); // write superclass cp index writeShort(getIndex(superClass,9)); // write out interfaces int nInterfaces; if (interfaces==null) nInterfaces=0; else nInterfaces=interfaces.length; writeShort(nInterfaces); for(int i=0;i This is used in JEL to avoid step-by step creation of service * methods of gnu.jel.CompiledExpression (, getType, ...). They are * created only once, and then the resulting ClassFile is cloned * at the point, when it is ready to accept the code for evaluation method. * @return a clone of this object */ public ClassFile clone() { ClassFile res=null; try { res=(ClassFile)super.clone(); // clone all primitive members // clone containers res.Items=new HashMap(res.Items); res.UTFs=new HashMap(res.UTFs); res.paramsVars=res.paramsVars.clone(); res.branchStack=res.branchStack.copy(); if (Debug.enabled) Debug.check(cstk.length==6); res.cstk=new IntegerStack[6]; for(int i=0;i<6;i++) res.cstk[i]=cstk[i].copy(); // clone streams res.constPoolData=new ByteArrayOutputStream(); constPool.flush(); constPoolData.writeTo(res.constPoolData); res.constPool=new DataOutputStream(res.constPoolData); res.text=res.text.clone(); } catch (IOException exc) { if (Debug.enabled) Debug.reportThrowable(exc); } catch (CloneNotSupportedException exc) { if (Debug.enabled) Debug.reportThrowable(exc); }; return res; }; private int startCodeAttr=0; private int startCode=0; /** * Starts a new method of this class. * @param m method descriptor. * @param vars types of local variables by number. */ public void newMethod(LocalMethod m, Class[] vars) { if (Debug.enabled) { Debug.check(cW==0); for(int i=0;i<6;i++) Debug.check(cstk[i].size()==0); Debug.check(currJump==0); }; // first finish the last method finishMethod(); nMethods++; // now prepare creation of a new one. int mdfrs=m.getModifiers(); if (isInterface) mdfrs=mdfrs | 0x0400; // mark abstract for interfaces boolean isAbstract=((mdfrs & 0x0400) > 0); writeShort(mdfrs); // modifiers writeShort(getUTFIndex(m.getName())); // name index writeShort(getUTFIndex(Library.getSignature(m))); // signature index int temp=0; Class[] exceptions=m.getExceptionTypes(); if (exceptions!=null) temp++; // exceptions are in separate attribute if (!isAbstract) temp++; // non-abstract methods have code writeShort(temp); // first we write exceptions attribute, if needed if (exceptions!=null) { temp=exceptions.length; writeShort(getUTFIndex("Exceptions")); writeInt((temp+1)*2); // attribute length writeShort(temp); for(int i=0;i>> 8) & 0xFF); image.write((poolEntries >>> 0) & 0xFF); constPoolData.writeTo(image); image.write(text,0,tsize); image.write(0); // no class file attributes image.write(0); // no class file attributes } catch (IOException exc) { // can't be }; return image.toByteArray(); }; //========================================================= //========== INSTRUCTIONS INTERFACE TO THE STATE=========== //========================================================= private LocalMethod currMethod=null; int[] paramsVars=null; // correspondence between parameter number and lvars. // current, and maximum number of words in Java stack private int cW=0, mW=0; /** Notes removal of typeID s and subsequent addition of typeID a * to Java stack. *

If either is negative the corresponding operation * (addition/removal) is skipped. This method is needed to allow ClassFile * to compute the maximum stack occupation for the generated code. It is * responsibility of the user (of this class) to call noteStk() each * time the stack is changed from within the code. * @param s typeid to be put on stack (-1 if none). * @param a typeid to be taken off Java stack (-1 if none). */ public void noteStk(int s,int a) { if (Debug.enabled) Debug.check(cW<=mW); if ((s>=0) && (s!=9)) { cW--; if ((s & (~2)) == 5) cW--; // Note additional word for J and D if (Debug.enabled) Debug.check(cW>=0); }; if ((a>=0) && (a!=9)) { cW++; if ((a & (~2)) == 5) cW++; // Note additional word for J and D if (cW>mW) mW=cW; }; }; /** * classes frequently used in generated code */ private static final Class[] specialClasses; static { if (Debug.enabled) Debug.check(OP.specialTypes.length==29, "You changed special types in TypesStack please update "+ "specialClasses array in ClassFile."); specialClasses=(Class[])TableKeeper.getTable("specialClasses"); }; private static final Member[] specialMethods; static { char[][] specialMds=(char[][]) TableKeeper.getTable("specialMds"); String[] specialMdsN=(String[]) TableKeeper.getTable("specialMdsN"); specialMethods=new Member[specialMds.length]; { Class definingClass=null; String name=null; Class[] params=null; int i=0; try { for (i=0;i[specialMds[i].length-2]; for(int j=0;j=beforeStk); }; // remove the result of the previous branch, the other branch must // put the same thing back into the types stack cW=beforeStk; code(0xEDECF2A7L); //| A7 -- goto //| F2 -- make down pointing unconditional label //| EC -- block unconditional labels //| ED -- land unblocked "false" labels break; case 2: // opc=230 (0xE6) -- finish "false" branch if (Debug.enabled) { code(0xFA); // FA -- ensure_value(); Debug.check((branchStack.pop()==cW), "Stack mismatch when compiling conditional"); code(0xEFE9); // E9 -- unblock unconditional jumps // EF -- land unblocked unconditional labels } else { code(0xEFE9FA); // FA -- ensure_value(); // E9 -- unblock unconditional jumps // EF -- land unblocked unconditional labels }; break; case 3: // opc=231 (0xE7) -- unblock "false" labels case 4: // opc=232 (0xE8) -- unblock "true" labels case 5: // opc=233 (0xE9) -- unblock unconditional labels cstk[opc-(mc+3-3)].pop(); break; case 6: // opc=234 (0xEA) -- block "false" labels case 7: // opc=235 (0xEB) -- block "true" labels case 8: // opc=236 (0xEC) -- block unconditional labels cstk[opc-(mc+6-3)].push(cstk[opc-(mc+6)].size()); break; case 9: // opc=237 (0xED) -- land unblocked "false" labels case 10: // opc=238 (0xEE) -- land unblocked "true" labels case 11: // opc=239 (0xEF) -- land unblocked unconditional labels { int blocked_at=0; final IntegerStack blk=cstk[opc-(mc+9-3)]; final IntegerStack jmp=cstk[opc-(mc+9 )]; if (blk.size()>0) blocked_at=blk.peek(); while (jmp.size()>blocked_at) { int currpos=tsize; int addrpos=jmp.pop(); // in the next command -1 because displacement is counted from the // jump opcode tsize=addrpos; writeShort(currpos-addrpos+1); tsize=currpos; }; }; break; case 12: // opc=240 (0xF0) -- make down pointing "false" label (j0) case 13: // opc=241 (0xF1) -- make down pointing "true" label (j1) case 14: // opc=242 (0xF2) -- make down pointing unconditional label cstk[opc-(mc+12 )].push(tsize); writeShort(0); // placeholder for the backpatched address break; case 15: // opc=243 (0xF3) -- set current open jump (code in next byte) currJump=(int)((op=op>>>8) & 0xFF); break; case 16: // opc=244 (0xF4) -- logical param AND case 17: // opc=245 (0xF5) -- logical param OR { // for AND s=0 for OR s=1 int s=(opc-(mc+16)); code(0xF9); // ensure jump if (iNJ ^ (s==0)) { if (Debug.enabled) Debug.check((currJump>=153) && (currJump<=166), "Attempt to invert non jump bytecode ("+ currJump+")"); currJump=(((currJump-1) ^ 0x0001)+1); }; iNJ=false; code(0x00F300+currJump); // 00F3 -- set curr jump to 0 code((0xEAEDF0) + (s<<16)+((s^1)<<8)+s); // code is // F0 - make label j0 modified by s // ED - land labels j1 modified by s^1 // EA - block labels j0 modified by s }; break; case 18: // opc=246 (0xF6) -- logical end AND case 19: // opc=247 (0xF7) -- logical end OR cstk[opc-(mc+18-3)].pop(); // just throw the corresponding block break; case 20: // opc 248 (0xF8) -- unblock all labels code(0xE7E8E9); break; case 21: // opc=249 (0xF9) -- ensure jump is in progress if (currJump==0) { // if no jump in progress yet noteStk(0,-1); // "boolean" is removed from stack currJump=157; //| }; break; case 22: // opc=250 (0xFA) -- ensure value is in stack boolean noPendingJumps=false; if (currJump==0) { // check if there are pending jumps int blocked0=0; if (cstk[3].size()>0) blocked0=cstk[3].peek(); int blocked1=0; if (cstk[4].size()>0) blocked1=cstk[4].peek(); noPendingJumps=(cstk[0].size()==blocked0) && (cstk[1].size()==blocked1); }; if (!noPendingJumps) { // if there are pending jumps or jump in progress code(0xE4); // branch_true(); codeLDC(Boolean.TRUE,0); code(0xE5); // branch_false(); codeLDC(Boolean.FALSE,0); code(0xE6); // branch_end(); }; break; case 23: // opc=251 (0xFB) -- block labels code(0xEAEBEC); break; case 24: // opc==252 (0xFC) -- unblock labels with inversion code(0xF9); // ensure jump IntegerStack.swap(cstk[1],cstk[4].pop(),cstk[0],cstk[3].pop()); cstk[5].pop(); iNJ=!iNJ; break; case 25: // opc==253 (0xFD) -- write special class CP ref op=op >>> 8; writeShort(getIndex(specialClasses[(int)(op & 0xFFL)],9)); break; case 26: // opc==254 (0xFE) -- call special method op=op >>> 8; codeM(specialMethods[(int)(op & 0xFF)]); break; default: if (Debug.enabled) Debug.check(opc !=0xFF); write(opc); }; op=op >>> 8; }; }; // Shortcut load opcodes for int type // index is value+1; allowed values from -1 to 5. // other values should be loaded from CP. // private final static int[] load_ints= // { 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; // -1 0 1 2 3 4 5 // private final static int[] load_long_ints= // {0x8502, 0x09, 0x0A,0x8505,0x8506,0x8507,0x8508}; // -1 0 1 2 3 4 5 /** * generates code for code loading constant of primitive type or string. * @param o reflection object or String containing the constant * @param primitiveID type ID to save lookups. */ public final void codeLDC(Object o, int primitiveID) { if (Debug.enabled) Debug.check(((primitiveID>=0) && (primitiveID<8)) || ((primitiveID==8) && (o==null)) || ((primitiveID==10) && (o instanceof StringBuffer)) || ((primitiveID==11) && (o instanceof String))); int short_opcodes=0; boolean tsb_store=false; int iv=-1; switch (primitiveID) { case 0: iv=(((Boolean)o).booleanValue()?1:0); case 2: if (iv<0) iv=(int)((Character)o).charValue(); case 1: case 3: case 4: if (iv<0) iv=((Number)o).intValue(); if ((iv>=-1) && (iv<=5)) short_opcodes=iv+3; //| iconst_ else if ((iv>=-128) && (iv<=127)) short_opcodes=0x00000010 | ((iv & 0xFF)<<8); //| bipush, break; case 5: long lv=((Long)o).longValue(); if (((lv | 1)^1) == 0) { // 0 or 1 short_opcodes=0x09+(int)lv; } else if ((lv>=-1) && (lv<=5)) { short_opcodes=0x8503+(int)lv; }; break; case 6: float fv=((Float)o).floatValue(); if (fv==0.0f) short_opcodes=0x0B; //| fconst_0 else if (fv==1.0f) short_opcodes=0x0C; //| fconst_1 else if (fv==2.0f) short_opcodes=0x0D; //| fconst_2 break; case 7: double dv=((Double)o).doubleValue(); if (dv==0.0) short_opcodes=0x0E; //| dconst_0 else if (dv==1.0) short_opcodes=0x0F; //| dconst_1 break; case 8: if (o==null) short_opcodes=0x01; //| aconst_null break; case 10: tsb_store=true; case 11: short_opcodes=0; primitiveID=8; break; default: if (Debug.enabled) Debug.check(false,"Loading of object constants is not supported by "+ "the Java class files."); }; if (short_opcodes==0) { // longs and doubles occupy two elements of stack all others just one boolean dword_const=((primitiveID==5) || (primitiveID==7)); int cpindex; if (tsb_store) { code(0x0001FE591DFDBBL); // STR => TSB // | new // // | dup // | invokespecial StringBuffer() noteStk(-1,10); // pushes ref to TSB cpindex=getIndex(o.toString(),primitiveID); } else { // makes use of the fact that primitiveID(Object)==typeID(string) cpindex=getIndex(o,primitiveID); }; if (Debug.enabled) Debug.check((cpindex>=0) && (cpindex<=65535)); if ((!dword_const) && (cpindex<=255)) { write(0x12); //| ldc write(cpindex); } else { int opc=0x13; //| ldc_w if (dword_const) opc++; //| ldc2_w write(opc); writeShort(cpindex); }; } else { codeB(short_opcodes); } noteStk(-1,primitiveID); // add what was loaded if (tsb_store) { code(0x08FE); noteStk(11,-1); // remove extra string used up by constructor }; }; //========================================================= //================= CONSTANTS POOL HANDLING =============== //========================================================= /** * Used to get the index of the given UTF8 string in the Constant Pool. *

If the specified string was not found in the pool -- it is added. * @param str the string to look for ( to add ) * @return index of the string in the Constant Pool. */ int getUTFIndex(String str) { // Check if it is in the pool already Integer index=UTFs.get(str); if (index==null) { // add UTF to the pool index=new Integer(poolEntries++); try { constPool.write(1); // CONSTANT_Utf8 = 1; constPool.writeUTF(str); } catch (java.io.IOException e) { if (Debug.enabled) Debug.reportThrowable(e); }; UTFs.put(str,index); }; return index.intValue(); }; // encodes types of relevant objects as integers // for classes corresponding to primitive types codes are the same as // primitiveID's private int typeID(Object item) { int id=OP.typeIDObject(item); if (id<8) return id; if (item instanceof String) return 8; if (item instanceof Class) return 9; if (item instanceof Member) return 10; return -1; }; /** * Used to determine an old CP index or to create a new one for an item. * @param item an item to create or get an index for * @return index for an item (negative if it has to be written) */ private final int getIndex(Object item) { return getIndex(item,typeID(item)); }; /** * Used to determine an old CP index or to create a new one for an item. * @param item an item to create or get an index for * @param typeid identifies type of argument to avoid linear searches * @return index for an item (negative if it has to be written) */ public int getIndex(Object item,int typeid) { Integer index=Items.get(item); if (index==null) { int newIndex=-1; try { int ival=-1; switch (typeid) { case 0: ival=((Boolean)item).booleanValue()?1:0; case 2: if (ival<0) ival=(int)((Character)item).charValue(); case 1: case 3: case 4: if (ival<0) ival=((Number)item).intValue(); newIndex=poolEntries++; constPool.write(3); // CONSTANT_Integer = 3; constPool.writeInt(ival); break; case 5: newIndex=poolEntries; constPool.write(5); // CONSTANT_Long = 5; constPool.writeLong(((Long)item).longValue()); poolEntries+=2; // Long occupies two entries in CP, weird !!! break; case 6: newIndex=poolEntries++; constPool.write(4); // CONSTANT_Float = 4; constPool.writeFloat(((Float)item).floatValue()); break; case 7: newIndex=poolEntries; constPool.write(6); // CONSTANT_Double = 6; constPool.writeDouble(((Double)item).doubleValue()); poolEntries+=2; // Double occupies two entries in CP, weird !!! break; case 8: { int UTFIndex=getUTFIndex((String)item); // write string , if needed newIndex=poolEntries++; constPool.write(8); // CONSTANT_String = 8; constPool.writeShort(UTFIndex); } break; case 9: { String histNameStr= Library.toHistoricalForm(((Class)item).getName()); int UTFIndex=getUTFIndex(histNameStr); // write FQCN , if needed newIndex=poolEntries++; constPool.write(7); // CONSTANT_Class = 7; constPool.writeShort(UTFIndex); } break; case 10: // Method case 11: // Constructor case 12: // Field Member member = (Member) item; Class dClass=member.getDeclaringClass(); int entryType; if (Library.isField(member)) entryType=9; // CONSTANT_Fieldref = 9; else if ((dClass!=null) && (dClass.isInterface())) entryType=11; // CONSTANT_InterfaceMethodref = 11; else entryType=10; // CONSTANT_Methodref = 10; newIndex=writeMemberRef(member,entryType); break; default: if (Debug.enabled) Debug.println("Can't place an item of type \""+ item.getClass().getName()+ "\" to the constant pool."); }; } catch (java.io.IOException e) { if (Debug.enabled) Debug.reportThrowable(e); }; index=new Integer(newIndex); Items.put(item,index); }; return index.intValue(); }; // writes out full reference to method, interface or field // this includes UTFs, Name&Type and XXX_ref entries private int writeMemberRef(Member member, int entry) throws java.io.IOException { if (Debug.enabled) Debug.check((entry==10)||(entry==9)||(entry==11)); // CONSTANT_Fieldref = 9; CONSTANT_Methodref = 10; // CONSTANT_InterfaceMethodref = 11; int name_ind=getUTFIndex((member instanceof Constructor)?"": member.getName()); int sign_ind=getUTFIndex(Library.getSignature(member)); Class dClass=member.getDeclaringClass(); int cls_ind; if (dClass==null) cls_ind=2; else cls_ind=getIndex(dClass,9); // this class ---^^^^^^^^^ 9 means Class--^ // Create Name and Type record int nat_ind=poolEntries++; constPool.write(12); // CONSTANT_NameAndType = 12; constPool.writeShort(name_ind); constPool.writeShort(sign_ind); // Create XXX_ref entry (where XXX is InterfaceMethod, Method or field) int index=poolEntries++; constPool.write(entry); constPool.writeShort(cls_ind); constPool.writeShort(nat_ind); return index; }; //================================================================ //================== END OF CONSTANT POOL HANDLING =============== //================================================================ }; source/src/java/gnu/jel/ImageLoader.java0000644000175000017500000001177612714113765017156 0ustar olesoles/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * This file is part of the Java Expressions Library (JEL). * For more information about JEL visit : http://fti.dn.ua/JEL/ * * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2006, 2007, 2009 Konstantin L. Metlov * * 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 . */ package gnu.jel; import gnu.jel.debug.Debug; /** * Loads JEL-generated classes into Java VM. *

Specifics of JEL generated classes is that the class name UTF8 is always * the first entry in the constant pool. This loader will not load * other classes. */ public class ImageLoader extends ClassLoader { String name; byte[] bytes; Class c; ClassLoader parent; private ImageLoader(String name, byte[] bytes) { this.name=name; this.bytes=bytes; this.c=null; this.parent=this.getClass().getClassLoader(); }; /** * Loads given JEL-generated image under its own name. * @param image to load * @return the class object for the new class or null * if unsuccessful. */ public static Class load(byte[] image) { if (Debug.enabled) Debug.check(image[10]==1, "Attempt to load non-JEL generated class file"); // JEL generated class file never have UNICODE class name // although they might reference UNICODE methods, etc... int len=(image[11]<<8)+image[12]; char[] nameChr=new char[len]; for(int i=0;i"load" below) if You have an older version // // of JDK (below 1.1.7, AFAIK), which does not allow classes with // // the _same_ names to be loaded by _different_ classloaders. // // // // Number of loaded expressions in this session // private transient volatile static long expressionUID=0; // /** // * Prefix of the expression classname // *

Example: "gnu.jel.generated.E_" // */ // public static String classNamePrefix="gnu.jel.generated.E_"; // /** // * Loads given JEL-generated image under unique name. // *

The unique name is generated by appending a steadily incremented // * number to the classNamePrefix. // * @param image to load // * @return the class object for the new class or null // * if unsuccessful. // * @see gnu.jel.ImageLoader#classNamePrefix // */ // public static Class loadRenamed(byte[] image) { // if (Debug.enabled) // Debug.check(image[10]==1, // "Attempt to load non-JEL generated class file"); // String newname=classNamePrefix+Long.toString(expressionUID++); // String newnameHF=TypesStack.toHistoricalForm(newname); // // JEL generated class file never have UNICODE class name // // although they might reference UNICODE methods, etc... // int len=(image[11]<<8)+image[12]; // int newlen=newname.length(); // byte[] newimage=new byte[image.length-len+newlen]; // System.arraycopy(image,0,newimage,0,11); // newimage[11]=(byte)(newlen>>8); // newimage[12]=(byte)newlen; // for(int i=0;i loadClass(String name, boolean resolve) throws java.lang.ClassNotFoundException { if (!name.equals(this.name)) { if (parent!=null) return parent.loadClass(name); else return findSystemClass(name); } else { synchronized (name) { if(c==null) { c = defineClass(name,bytes, 0, bytes.length,this.getClass().getProtectionDomain()); if (resolve) resolveClass(c); } } return c; } }; }; source/src/java/gnu/jel/OPcondtnl.java0000644000175000017500000001053212714113765016672 0ustar olesoles/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * This file is part of the Java Expressions Library (JEL). * For more information about JEL visit : http://fti.dn.ua/JEL/ * * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2006, 2007, 2009 Konstantin L. Metlov * * 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 . */ package gnu.jel; import gnu.jel.debug.Debug; import java.util.Stack; /** * A tree node, representing conditional. */ public class OPcondtnl extends OP { /** * Creates conditional operator. *

On entry the paramOPs should contain . * @param paramOPs stack holding the operands */ public OPcondtnl(Stack paramOPs) throws CompilationException { chi=new OP[3]; for (int i=2;i>=0;i--) chi[i]=paramOPs.pop(); int type2ID=chi[2].resID; Class type2=chi[2].resType; int type1ID=chi[1].resID; Class type1=chi[1].resType; int argID=chi[0].resID; if (unwrapType[argID]!=0) // first argument must be boolean throw new CompilationException(23,null); if (argID!=0) { // unwrap paramOPs.push(chi[0]); chi[0]=new OPunary(paramOPs,0,null,false); }; // determine the result type according to JLS 15.24 resID=-1; if ((type1ID>=8) && (type2ID>=8)) { // references if (isWidening(type1ID, type1, type2ID, type2)) { resID=type2ID; resType=type2; } else if (isWidening(type2ID, type2, type1ID, type1)) { resID=type1ID; resType=type1; }; // otherwise both must unwrap to primitives, which is checked next }; if (resID<0) { // if reference conversion did not work int type1IDunwrp; int type2IDunwrp; if ((resID=type1IDunwrp=unwrapType[type1ID])!= (type2IDunwrp=unwrapType[type2ID])) { if (((type1IDunwrp==1) && (type2IDunwrp==3)) || ((type1IDunwrp==3) && (type2IDunwrp==1))) resID=3; else { if ((type1IDunwrp>=8) || (type2IDunwrp>=8) || ((resID=OPbinary.promotions[type1IDunwrp][type2IDunwrp])<0)) { Object[] paramsExc={type1,type2}; throw new CompilationException(24,paramsExc); }; }; }; resType=specialTypes[resID]; // here it's always the primitive }; // convert types if ((type1ID!=resID) || ((resID==8) && (type1!=null) && (type1!=resType))) { paramOPs.push(chi[1]); chi[1]=new OPunary(paramOPs,resID,resType,false); }; if ((type2ID!=resID) || ((resID==8) && (type2!=null) && (type2!=resType))) { paramOPs.push(chi[2]); chi[2]=new OPunary(paramOPs,resID,resType,false); }; }; public void compile(ClassFile cf) { chi[0].compile(cf); if (chi[1]!=null) { // in the case condition was impossible to evaluate at compile-time cf.code(0xE4); // start "true" branch chi[1].compile(cf); cf.code(0xE5); // finish "true" branch / start "false" branch chi[2].compile(cf); cf.code(0xE6); // finish "false" branch }; }; public Object eval() throws Exception { boolean cond; try { cond=((Boolean)chi[0].eval()).booleanValue(); } catch (Exception e) { try { chi[1]=new OPload(chi[1],chi[1].eval()); } catch (Exception exc) { }; try { chi[2]=new OPload(chi[2],chi[2].eval()); } catch (Exception exc) { }; throw e; }; OP rop=cond?chi[1]:chi[2]; try { return rop.eval(); } catch (Exception e) { // if can't eval, but know the condition chi[0]=rop; chi[1]=null; chi[2]=null; throw e; } }; }; source/src/java/gnu/jel/LocalMethod.java0000644000175000017500000000506712714113765017174 0ustar olesoles/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * This file is part of the Java Expressions Library (JEL). * For more information about JEL visit : http://fti.dn.ua/JEL/ * * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2006, 2007, 2009 Konstantin L. Metlov * * 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 . */ package gnu.jel; import gnu.jel.debug.Debug; /** * Represents a method local to the class being compiled. */ public class LocalMethod extends LocalField { private Class[] paramTypes; private Class[] exceptions; /** * Constructs a new local method. * @param modifiers sum of one or more of PUBLIC, PRIVATE, * PROTECTED,STATIC, FINAL, * SYNCHRONIZED, NATIVE, ABSTRACT * constants of java.lang.reflect.Modifier . * @param type type of the return value. * @param name name of the method * @param paramTypes array of types of formal parameters excluding "this" * (null means no parameters). * @param exceptions checked exceptions thrown */ public LocalMethod(int modifiers, Class type, java.lang.String name, Class[] paramTypes,Class[] exceptions) { super(modifiers,type,name,null); if (paramTypes!=null) this.paramTypes=paramTypes; else this.paramTypes=new Class[0]; if (exceptions!=null) this.exceptions=exceptions; else this.exceptions=new Class[0]; }; /** * Used to obtain types of formal parameters of this method. * @return array of classes representing formal parameters of the * method except "this" */ public Class[] getParameterTypes() { return paramTypes; }; /** * Used to get checked exceptions thrown by this method * @return array of checked exceptions */ public Class[] getExceptionTypes() { return exceptions; }; }; source/src/java/gnu/jel/IntegerStack.java0000644000175000017500000000760312714113765017362 0ustar olesoles/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * This file is part of the Java Expressions Library (JEL). * For more information about JEL visit : http://fti.dn.ua/JEL/ * * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2006, 2007, 2009 Konstantin L. Metlov * * 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 . */ package gnu.jel; import gnu.jel.debug.Debug; /** * Specialized stack which works with integers. */ class IntegerStack { private int[] data; private int count=0; public IntegerStack(int initCapacity) { data=new int[initCapacity]; }; public IntegerStack() { this(30); }; public IntegerStack copy() { IntegerStack res=new IntegerStack(data.length); res.count=count; for(int i=0;i=data.length) incCap(count+1); data[count++]=what; }; public final int peek() { return data[count-1]; }; public final int pop() { return data[--count]; }; public final int size() { return count; }; // Swaps values above given limits in two stacks public static void swap(IntegerStack one,int oneLim, IntegerStack other,int otherLim) { // this is used for swapping labels in logical expressions compilation // usually there are not so many labels to swap... and the element // by element copy should not incur significant peformance penalty // ordering of elements between limits is not important IntegerStack temp=null; if (one.size()>oneLim) temp=new IntegerStack(); // System.out.println("vgv one.size()= "+one.size()+" ( "+oneLim+" )"+ // " other.size()= "+other.size()+" ( "+otherLim+" )"); while (one.size()>oneLim) temp.push(one.pop()); while (other.size()>otherLim) one.push(other.pop()); while ((temp!=null) && (temp.size()>0)) other.push(temp.pop()); // ----- faster version of the same // int copyFromOne=one.count-oneLim; // int copyFromOther=other.count-otherLim; // boolean cf_one=copyFromOne>0; // boolean cf_other=copyFromOther>0; // if ((cf_one) || (cf_other)) { // int nSizeOne=oneLim+copyFromOther; // int nSizeOther=otherLim+copyFromOne; // // ensure capacities // if (nSizeOne>one.data.length) one.incCap(nSizeOne); // if (nSizeOther>other.data.length) other.incCap(nSizeOther); // int[] temp=null; // if (cf_one) { // temp=new int[copyFromOne]; // System.arraycopy(one.data,oneLim,temp,0,copyFromOne); // }; // if (cf_other) // System.arraycopy(other.data,otherLim,one.data,oneLim,copyFromOther); // if (cf_one) // System.arraycopy(temp,0,other.data,otherLim,copyFromOne); // one.count=nSizeOne; // other.count=nSizeOther; // }; // ----- end of faster version of the same }; private void incCap(int minCapacity) { int[] old_data=data; int oldSize=data.length; int newSize=oldSize*2; if (newSize. */ package gnu.jel; import gnu.jel.debug.Debug; /** * This abstract class is a superclass of every JEL-compiled expression, * each of which overrides some of the abstract methods below. *

Most methods of this class accept a reference to the array of objects. * This reference is a pointer to the dynamic object library. As you know, * JEL allows to call virtual methods of Java classes, but, as you also know, * virtual methods require a reference to an object instance * (this) to be * passed along with parameters. The array dl (dynamic * library) serves just this purpose. It should contain references * to objects of all classes, whose * virtual methods were put into the Library of callable functions. * Objects * in the dl array should correspond one-to-one to classes * in the array, passed as a second argument of gnu.jel.Library * constructor. *

*

There are two ways of evaluating the compiled expressions allowing * to compromise between raw performance and simplicity: *

The first method (simplest one) is based on the call to the * evaluate method, which will * return an object even if the result of computation was of a primitive type. * The primitive types will be automatically converted into the * corresponding reflection * objects. There is certain overhead, associated with object creation, it * takes CPU cycles and also produces load on the garbage collector later.. *

For massive (thousand times) evaluations of functions, producing * results of primitive Java types, the second * method can be more suitable. It is based on : first, determining the * type of the result, and, then, subsequent call to the * corresponding evaluateXXX method. *

The type of the resulting expression can be determined by call to the * getType() method. It will return an integer number, indentifying the type, * proper evaluateXXX method can be determined, * based on the following table: *

 * getType()   |  method to call
 * ------------+----------------------
 * 0           | evaluate_boolean(...)
 * 1           | evaluate_byte(...)
 * 2           | evaluate_char(...)
 * 3           | evaluate_short(...)
 * 4           | evaluate_int(...)
 * 5           | evaluate_long(...)
 * 6           | evaluate_float(...)
 * 7           | evaluate_double(...)
 * 8           | evaluate(...)         <- result is Object (universal method)
 * 9           | evaluate_void(...)
 * -----------------------------------
 * 
*

Note: If a wrong evaluateXXX() method is called, it will return zero, * and, in debug version of JEL (jel_g.jar) only, a warning will be * printed to stderr. *

There is a possibility to enforce resulting type of the expression at * compile time (see gnu.jel.Evaluator). * Use it to avoid unnecesary type checks. * @see gnu.jel.Library * @see gnu.jel.Evaluator */ public abstract class CompiledExpression { /** * Returns type of the expression result. *

The type is encoded in integer. Following table could help * in determining what it is : *

   * getType()   |  method to call
   * ------------+-----------------
   * 0           | boolean
   * 1           | byte
   * 2           | char
   * 3           | short
   * 4           | int
   * 5           | long
   * 6           | float
   * 7           | double
   * 8           | Object
   * 9           | void
   * 
*

The reason not to introduce the family of, say, TYPE_XXX constants * is to save space. There are so many things connected with these * particular numbers in code generator that it could be a pain to change * their meaning. Also, this shoul never be necessary because these * are ALL Java 1.X primitive types. * @return the type of the expression, encoded in integer. */ public abstract int getType(); /** * Returns the type of the expression result. *

If the result has primitive type the corresponding wrapper * class is returned (please note that it is just a wrapper class like * java.lang.Integer instead of exact primitive type class * java.lang.Integer.TYPE). This corresponds to the wrapping done * in non-specialized evaluate() method. *

When the result is an object, the returned value is the most * specific reference to the class of that object (which is always * a subclass of the returned class) available at compile time. *

The precision of determining the result type this way mainly * depends on the design of the user's function namespace (defined * by gnu.jel.Library class). It is possible to design a library in * such a way that the best approximation to the result type obtainable * at compile time would be the java.lang.Object class, which will * be returned by this method, thus, providing no useful information * about the actual type. *

Please note again that the guaranteed exact type of the result can't be * determined at compile time and can be quiered only after evaluating * the expression (directly from resulting object). *

The only guarantee * this method provides is that a variable of the returned expression type * can be assigned by a reference, resulting from a call to evaluate. */ public abstract Class getTypeC(); /** * Evaluates the expression, representing result as an object. *

If the result of evaluation is Java primitive type it gets wrapped * into corresponding reflection object , i.e. * int -> java.lang.Integer, * boolean -> java.lang.Boolean,... * @param dl Array of the instance references to the objects in dynamic * library. See description of this class above for more details. * @return the result fo computation. * @exception Throwable if any runtime error have occured (i.e. division * by 0) * @see gnu.jel.Evaluator#compile * @see gnu.jel.Library */ public Object evaluate(Object[] dl) throws Throwable { int type=getType(); Object res=null; switch (type) { case 0: res=new Boolean(evaluate_boolean(dl)); break; case 1: res=new Byte(evaluate_byte(dl)); break; case 2: res=new Character(evaluate_char(dl)); break; case 3: res=new Short(evaluate_short(dl)); break; case 4: res=new Integer(evaluate_int(dl)); break; case 5: res=new Long(evaluate_long(dl)); break; case 6: res=new Float(evaluate_float(dl)); break; case 7: res=new Double(evaluate_double(dl)); break; case 9: evaluate_void(dl); break; default: if (Debug.enabled) Debug.check(false,"WrongTypeReturned from "+ "CompiledExpression.getType()."); }; return res; }; /** * Evaluates the expression whose result has type boolean. *

If the type of the result is not a boolean this function * returns always false, debug version will print a warning to stderr. * @param dl Array of the instance references to the objects in dynamic * library. See description of this class above for more details. * @return the result fo computation. * @exception Throwable if any runtime error have occured (i.e. division * by 0) * @see gnu.jel.Evaluator#compile * @see gnu.jel.Library */ public boolean evaluate_boolean(Object[] dl) throws Throwable { if (Debug.enabled) Debug.println("Wrong evaluateXXXX() method called,"+ " check value of getType()."); return false; }; /** * Evaluates the expression whose result has type byte. *

If the type of the result is not a byte this function returns * always 0, debug version will print a warning to stderr. * @param dl Array of the instance references to the objects in dynamic * library. See description of this class above for more details. * @return the result fo computation. * @exception Throwable if any runtime error have occured (i.e. division * by 0) * @see gnu.jel.Evaluator#compile * @see gnu.jel.Library */ public byte evaluate_byte(Object[] dl) throws Throwable { if (Debug.enabled) Debug.println("Wrong evaluateXXXX() method called,"+ " check value of getType()."); return 0; }; /** * Evaluates the expression whose result has type short. *

If the type of the result is not a short this function returns * always 0, debug version will print a warning to stderr. * @param dl Array of the instance references to the objects in dynamic * library. See description of this class above for more details. * @return the result fo computation. * @exception Throwable if any runtime error have occured (i.e. division * by 0) * @see gnu.jel.Evaluator#compile * @see gnu.jel.Library */ public short evaluate_short(Object[] dl) throws Throwable { if (Debug.enabled) Debug.println("Wrong evaluateXXXX() method called,"+ " check value of getType()."); return 0; }; /** * Evaluates the expression whose result has type char. *

If the type of the result is not a char this function returns * always '?', debug version will print a warning to stderr. * @param dl Array of the instance references to the objects in dynamic * library. See description of this class above for more details. * @return the result fo computation. * @exception Throwable if any runtime error have occured (i.e. division * by 0) * @see gnu.jel.Evaluator#compile * @see gnu.jel.Library */ public char evaluate_char(Object[] dl) throws Throwable { if (Debug.enabled) Debug.println("Wrong evaluateXXXX() method called,"+ " check value of getType()."); return '?'; }; /** * Evaluates the expression whose result has type int. *

If the type of the result is not a int this function returns * always 0, debug version will print a warning to stderr. * @param dl Array of the instance references to the objects in dynamic * library. See description of this class above for more details. * @return the result fo computation. * @exception Throwable if any runtime error have occured (i.e. division * by 0) * @see gnu.jel.Evaluator#compile * @see gnu.jel.Library */ public int evaluate_int(Object[] dl) throws Throwable { if (Debug.enabled) Debug.println("Wrong evaluateXXXX() method called,"+ " check value of getType()."); return 0; }; /** * Evaluates the expression whose result has type long. *

If the type of the result is not a long this function returns * always 0, debug version will print a warning to stderr. * @param dl Array of the instance references to the objects in dynamic * library. See description of this class above for more details. * @return the result fo computation. * @exception Throwable if any runtime error have occured (i.e. division * by 0) * @see gnu.jel.Evaluator#compile * @see gnu.jel.Library */ public long evaluate_long(Object[] dl) throws Throwable { if (Debug.enabled) Debug.println("Wrong evaluateXXXX() method called,"+ " check value of getType()."); return 0L; }; /** * Evaluates the expression whose result has type float. *

If the type of the result is not a float this function returns * always 0.0, debug version will print a warning to stderr. * @param dl Array of the instance references to the objects in dynamic * library. See description of this class above for more details. * @return the result fo computation. * @exception Throwable if any runtime error have occured (i.e. division * by 0) * @see gnu.jel.Evaluator#compile * @see gnu.jel.Library */ public float evaluate_float(Object[] dl) throws Throwable { if (Debug.enabled) Debug.println("Wrong evaluateXXXX() method called,"+ " check value of getType()."); return 0.0F; }; /** * Evaluates the expression whose result has type double. *

If the type of the result is not a double this function * returns always 0.0, debug version will print a warning to stderr. * @param dl Array of the instance references to the objects in dynamic * library. See description of this class above for more details. * @return the result fo computation. * @exception Throwable if any runtime error have occured (i.e. division * by 0) * @see gnu.jel.Evaluator#compile * @see gnu.jel.Library */ public double evaluate_double(Object[] dl) throws Throwable { if (Debug.enabled) Debug.println("Wrong evaluateXXXX() method called,"+ " check value of getType()."); return 0.0D; }; /** * Evaluates the expression whose result has type void. *

If the type of the result is not a void debug version * will print a warning to stderr. * @param dl Array of the instance references to the objects in dynamic * library. See description of this class above for more details. * @exception Throwable if any runtime error have occured (i.e. division * by 0) * @see gnu.jel.Evaluator#compile * @see gnu.jel.Library */ public void evaluate_void(Object[] dl) throws Throwable { if (Debug.enabled) Debug.println("Wrong evaluateXXXX() method called,"+ " check value of getType()."); return; }; // String and object comparisons private static java.text.Collator collator=null; public static int compare(String s1,String s2) { if (collator==null) collator = java.text.Collator.getInstance(); return collator.compare(s1,s2); }; }; source/src/java/gnu/jel/OPbinary.java0000644000175000017500000002630312714113765016520 0ustar olesoles/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * This file is part of the Java Expressions Library (JEL). * For more information about JEL visit : http://fti.dn.ua/JEL/ * * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2006, 2007, 2009 Konstantin L. Metlov * * 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 . */ package gnu.jel; import gnu.jel.debug.Debug; import java.util.Stack; /** * A tree node, representing binary operation. */ public class OPbinary extends OP { /** code of this operation */ public int code; /** index into ops array to get code for this op. */ private int opsIDX; // Names of binary operations by ID in the readable form. private final static String[] opNames; /** binary promotions of base types */ protected final static byte[][] promotions; // code chunks to implement the ops private final static int[][] ops; // type of operands promotion by the opcode private static final byte[] promotionTypes; static { promotions=(byte[][])TableKeeper.getTable("promotions"); ops=(int[][])TableKeeper.getTable("ops"); promotionTypes=(byte[])TableKeeper.getTable("promotionTypes"); opNames=(String[])TableKeeper.getTable("binOpNames"); }; /** * Constructs a new binary operation. *

Codes are following: *

   * 0   --  addition
   * 1   --  substraction
   * 2   --  multiplication
   * 3   --  division
   * 4   --  remainder
   * 5   --  bitwise AND
   * 6   --  bitwise OR
   * 7   --  bitwise and logical XOR
   * 8   --  comparizon for equality
   * 9   --  comparizon for non-equality
   * 10  --  comparizon for "less" <
   * 11  --  comparizon for "greater or equal" >=
   * 12  --  comparizon for "greater" >
   * 13  --  comparizon for "less or equal" <=
   * 14  --  bitwise left shift <<
   * 15  --  bitwise right signed shift >>
   * 16  --  bitwise right unsigned shift >>>
   * 17  --  logical conjunction operator (AND)
   * 18  --  logical disjunction operator (OR)
   * 19  --  array element access operation
   * 20  --  reserved (used internally for string concatenation)
   * 
* @param paramOPs stack holding the operands * @param opcode is the operation code */ public OPbinary(Stack paramOPs, int opcode) throws CompilationException { if (Debug.enabled) Debug.check((opcode>=0) && (opcode op2Type=chi[1].resType; int op1ID=chi[0].resID; Class op1Type=chi[0].resType; // separate out string concatenation if (((op1ID==10) || (unwrapType[op1ID]==11)) && (opcode==0)) opcode=20; this.code=opcode; // Debug.println("opcode="+opcode+" op1ID="+op1ID+" op2ID="+op2ID); // perform the promotion of operands and determine the index // variables opsIDX, resID, optionally resType (if resID=8) and // the following will be defined int op2cvtID=op2ID,op1cvtID=op1ID; resID=-1; boolean second_narrowing=false; int op1IDuwrp=unwrapType[op1ID]; int op2IDuwrp=unwrapType[op2ID]; switch (promotionTypes[opcode]) { case 0: // binary promotion with boolean result resID=0; case 1: // binary promotion op1cvtID=op2cvtID=opsIDX= promotions[op1IDuwrp][op2IDuwrp]; if (resID<0) resID=opsIDX; if (opsIDX==-1) { // types are incompatible (can't promote) Object[] paramsExc={op1Type,op2Type,opNames[opcode]}; throw new CompilationException(15,paramsExc); }; break; case 3: // array promotion resType=(op1Type!=null?op1Type.getComponentType():null); if (resType==null) throw new CompilationException(18,null); resID=typeID(resType); opsIDX=(resID>=8?8:resID); case 2: // unary promotion of the first operand, second to int if (resID<0) { resID=op1cvtID=opsIDX= OPunary.unary_prmtns[op1IDuwrp]; second_narrowing=true; }; // integral types mask // 7 6 5 4 3 2 1 0 // 0 0 1 1 1 1 1 0 = 0x3E if (((0x3E>>op2IDuwrp) & 1)==0) { // type is not integral Object[] paramsExc={opNames[opcode],op2Type}; throw new CompilationException(27,paramsExc); }; op2cvtID=4; break; case 4: // string concatenation promotion opsIDX=(op2ID>11?8:op2ID); op1cvtID=10; // TSB resID=10; // TSB break; default: if (Debug.enabled) Debug.println("Wrong promotion type for binary OP "+ promotionTypes[opcode]); }; // check if the OP can be implemented if (ops[opcode][opsIDX]==0xFF) { // operation is not defined on types Object[] paramsExc={opNames[opcode],op1Type,op2Type}; throw new CompilationException(16,paramsExc); }; // insert type conversion opcode if ((op1ID!=op1cvtID) && (op1cvtID!=8)) { paramOPs.push(chi[0]); chi[0]=new OPunary(paramOPs,op1cvtID,null,op1cvtID==10); // can narrow to TSB }; if ((op2ID!=op2cvtID) && (op2cvtID!=8)) { paramOPs.push(chi[1]); chi[1]=new OPunary(paramOPs,op2cvtID,null,second_narrowing); }; if (resID!=8) resType=specialTypes[resID]; }; public void compile(ClassFile cf) { if ((code==17) || (code==18)) { chi[0].compile(cf); cf.code(code-(17 - 0xF4)); // logical_param AND/OR chi[1].compile(cf); cf.code(code-(17 - 0xF6)); // logical_end AND/OR } else { chi[0].compile(cf); cf.code(0xFA); // ensure value; chi[1].compile(cf); cf.code(0xFA); // ensure value; cf.code(ops[code][opsIDX] & 0xFFFFFFFFL); // & is needed to prevent sign extension when converting "int" ops // element into "long" argument of code. cf.noteStk(chi[0].resID,-1); cf.noteStk(chi[1].resID,-1); if (cf.currJump==0) // jumps do not load anything to the stack cf.noteStk(-1,resID); }; }; public Object eval() throws Exception { Object c1w=null; boolean ep1=false; int c1ID=chi[0].resID; Object c2w=null; boolean ep2=false; int c2ID=chi[1].resID; try { c1w=chi[0].eval(); } catch (Exception e) { ep1=true; }; try { c2w=chi[1].eval(); } catch (Exception e) { ep2=true; }; try { if (ep1 || ep2 || (code==19)) // array access can't be evaluated. throw new Exception(); if (code==20) { ((StringBuffer)c1w).append(String.valueOf(c2w)); } else if ((c1ID>=8) || (c2ID>=8)) { // the only way the objects appear in this context // are the comparisons if (Debug.enabled) { Debug.check((code>=8)||(code<=13), "only comparisons and concatenation binops can "+ "operate on objects."); Debug.check(c1ID!=10, "No TSB in this context 1"); Debug.check(c1ID!=10, "No TSB in this context 2"); }; // only string literal comparisons are interpreted if ((c1ID!=11) || (c2ID!=11)) throw new Exception(); // compare the strings int res=CompiledExpression.compare((String)c1w,(String)c2w); c1w=((0x3172A>>>(3*(code-8)))&((res>0)?1:((res<0)?4:2)))>0 ?Boolean.TRUE:Boolean.FALSE; } else { // binary on primitive types // Widen Number n1=widen(c1w,c1ID); Number n2=widen(c2w,c2ID); // Perform boolean boolres=false; boolean resbool=false; if ((opsIDX>=6) && (opsIDX<=7)) { // operations on floating point double d1=n1.doubleValue(),d2=n2.doubleValue(); boolean wrop=false; switch (code) { case 0 : d1=d1+d2; break; //PL case 1 : d1=d1-d2; break; //MI case 2 : d1=d1*d2; break; //MU case 3 : d1=d1/d2; break; //DI case 4 : d1=d1%d2; break; //RE case 5 : wrop=true;break; //AN case 6 : wrop=true;break; //OR case 7 : wrop=true;break; //XO case 8 : boolres=true; resbool=(d1==d2); break; //EQ case 9 : boolres=true; resbool=(d1!=d2); break; //NE case 10: boolres=true; resbool=(d1=d2); break; //GE case 12: boolres=true; resbool=(d1>d2); break; //GT case 13: boolres=true; resbool=(d1<=d2); break; //LE default : wrop=true; }; if (Debug.enabled && wrop) Debug.println("Wrong operation on float ("+code+")."); if (!boolres) n1=new Double(d1); else { // booleans are represented by longs temporarily if (resbool) n1=new Long(1L); else n1=new Long(0); }; } else { // operations on integers long l1=n1.longValue(),l2=n2.longValue(); switch (code) { case 0: l1=l1+l2;break; //PL case 1: l1=l1-l2;break; //MI case 2: l1=l1*l2; break; //MU case 3: l1=l1/l2; break; //DI case 4: l1=l1%l2; break; //RE case 17: case 5: l1=l1&l2; break; //AN case 18: case 6: l1=l1|l2; break; //OR case 7: l1=l1^l2; break; //XO case 8 : boolres=true; l1=(l1==l2?1L:0L); break; //EQ case 9 : boolres=true; l1=(l1!=l2?1L:0L); break; //NE case 10: boolres=true; l1=(l1< l2?1L:0L); break; //LT case 11: boolres=true; l1=(l1>=l2?1L:0L); break; //GE case 12: boolres=true; l1=(l1> l2?1L:0L); break; //GT case 13: boolres=true; l1=(l1<=l2?1L:0L); break; //LE case 14: l1=l1<>l2; break; // RS case 16: { // for this kind of shifts the bit width of variable is // important if (resID==4) //=because there is unary numeric promotion before op l1=(int)l1>>>l2; else l1=l1>>>l2; break; } // RUS default : if (Debug.enabled) Debug.println("Wrong operation on integer ("+code+")."); }; n1=new Long(l1); }; // Narrow if (boolres) { c1w=narrow(n1,0); } else c1w=narrow(n1,resID); }; return c1w; } catch (Exception thr) { // if can't evaluate -- replace operands at least if (!ep1) chi[0]=new OPload(chi[0],c1w); if (!ep2) chi[1]=new OPload(chi[1],c2w); throw thr; // Debug.reportThrowable(thr); // IGNORE } }; }; source/src/java/gnu/jel/reflect/0000755000175000017500000000000012714113765015552 5ustar olesolessource/src/java/gnu/jel/reflect/Byte.java0000644000175000017500000000214312714113765017320 0ustar olesoles/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * This file is part of the Java Expressions Library (JEL). * For more information about JEL visit : http://fti.dn.ua/JEL/ * * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2006, 2007, 2009 Konstantin L. Metlov * * 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 . */ package gnu.jel.reflect; /** * Denotes the object as being automatically convertible to * java byte type. */ public interface Byte { public byte getValue(); }; source/src/java/gnu/jel/reflect/Double.java0000644000175000017500000000215112714113765017626 0ustar olesoles/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * This file is part of the Java Expressions Library (JEL). * For more information about JEL visit : http://fti.dn.ua/JEL/ * * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2006, 2007, 2009 Konstantin L. Metlov * * 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 . */ package gnu.jel.reflect; /** * Denotes the object as being automatically convertible to * java double type. */ public interface Double { public double getValue(); }; source/src/java/gnu/jel/reflect/Character.java0000644000175000017500000000215012714113765020307 0ustar olesoles/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * This file is part of the Java Expressions Library (JEL). * For more information about JEL visit : http://fti.dn.ua/JEL/ * * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2006, 2007, 2009 Konstantin L. Metlov * * 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 . */ package gnu.jel.reflect; /** * Denotes the object as being automatically convertible to * java char type. */ public interface Character { public char getValue(); }; source/src/java/gnu/jel/reflect/Float.java0000644000175000017500000000214612714113765017465 0ustar olesoles/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * This file is part of the Java Expressions Library (JEL). * For more information about JEL visit : http://fti.dn.ua/JEL/ * * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2006, 2007, 2009 Konstantin L. Metlov * * 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 . */ package gnu.jel.reflect; /** * Denotes the object as being automatically convertible to * java float type. */ public interface Float { public float getValue(); }; source/src/java/gnu/jel/reflect/Boolean.java0000644000175000017500000000215412714113765017776 0ustar olesoles/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * This file is part of the Java Expressions Library (JEL). * For more information about JEL visit : http://fti.dn.ua/JEL/ * * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2006, 2007, 2009 Konstantin L. Metlov * * 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 . */ package gnu.jel.reflect; /** * Denotes the object as being automatically convertible to * java boolean type. */ public interface Boolean { public boolean getValue(); }; source/src/java/gnu/jel/reflect/String.java0000644000175000017500000000216112714113765017663 0ustar olesoles/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * This file is part of the Java Expressions Library (JEL). * For more information about JEL visit : http://fti.dn.ua/JEL/ * * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2006, 2007, 2009 Konstantin L. Metlov * * 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 . */ package gnu.jel.reflect; /** * Denotes the object as being automatically convertible to * java String type using its .toString() method. */ public interface String { }; source/src/java/gnu/jel/reflect/Short.java0000644000175000017500000000214612714113765017517 0ustar olesoles/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * This file is part of the Java Expressions Library (JEL). * For more information about JEL visit : http://fti.dn.ua/JEL/ * * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2006, 2007, 2009 Konstantin L. Metlov * * 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 . */ package gnu.jel.reflect; /** * Denotes the object as being automatically convertible to * java short type. */ public interface Short { public short getValue(); }; source/src/java/gnu/jel/reflect/Long.java0000644000175000017500000000214312714113765017314 0ustar olesoles/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * This file is part of the Java Expressions Library (JEL). * For more information about JEL visit : http://fti.dn.ua/JEL/ * * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2006, 2007, 2009 Konstantin L. Metlov * * 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 . */ package gnu.jel.reflect; /** * Denotes the object as being automatically convertible to * java long type. */ public interface Long { public long getValue(); }; source/src/java/gnu/jel/reflect/Integer.java0000644000175000017500000000214412714113765020013 0ustar olesoles/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * This file is part of the Java Expressions Library (JEL). * For more information about JEL visit : http://fti.dn.ua/JEL/ * * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2006, 2007, 2009 Konstantin L. Metlov * * 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 . */ package gnu.jel.reflect; /** * Denotes the object as being automatically convertible to * java int type. */ public interface Integer { public int getValue(); }; source/src/java/gnu/jel/TableKeeper.java0000644000175000017500000000665412714113765017167 0ustar olesoles/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * This file is part of the Java Expressions Library (JEL). * For more information about JEL visit : http://fti.dn.ua/JEL/ * * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2006, 2007, 2009 Konstantin L. Metlov * * 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 . */ package gnu.jel; import java.util.*; import java.io.*; import gnu.jel.debug.Debug; public class TableKeeper { private static final Hashtable tables; private static final ResourceBundle msgs; static { Hashtable temp=new Hashtable(); PropertyResourceBundle resB=null; try { Class c=Class.forName("gnu.jel.DVMap"); // Read messages resB= new PropertyResourceBundle(c.getResourceAsStream("JEL.properties")); // Read tables ObjectInputStream ios= new ObjectInputStream(c.getResourceAsStream("tables.dat")); @SuppressWarnings("unchecked") Hashtable temp1=(Hashtable)ios.readObject(); temp=temp1; // work around the serialization bug that classes representing the // primitive types can be serialized but can not be deserealized String[] specialTypesStr=(String[]) temp.get("specialTypes"); String[] specialClassesAddStr=(String[]) temp.get("specialClasses"); Class[] specialTypes=new Class[specialTypesStr.length]; Class[] specialClasses=new Class[specialTypesStr.length+ specialClassesAddStr.length]; for(int i=10; i) Class.forName(specialTypesStr[i+20]).getField("TYPE").get(null); // specialTypes[8]=null, // Generic reference // 8 specialClasses[9]=specialTypes[9]=Void.TYPE; // 9 temp.put("specialTypes",specialTypes); Class[] specialClassesAdd=new Class[specialClassesAddStr.length]; for (int i=0; i