diff --git a/.classpath b/.classpath
index b10b8d9..78dc779 100644
--- a/.classpath
+++ b/.classpath
@@ -3,5 +3,6 @@
+
diff --git a/.externalToolBuilders/SableCC.launch b/.externalToolBuilders/SableCC.launch
new file mode 100644
index 0000000..2ea516a
--- /dev/null
+++ b/.externalToolBuilders/SableCC.launch
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.gitignore b/.gitignore
index c1a0fd5..13c38a1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,4 +2,9 @@
/src/arden/compiler/analysis
/src/arden/compiler/lexer
/src/arden/compiler/node
-/src/arden/compiler/parser
\ No newline at end of file
+/src/arden/compiler/parser
+/src/arden/constants/analysis
+/src/arden/constants/lexer
+/src/arden/constants/node
+/src/arden/constants/parser
+/dist/
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..97aae7d
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "resource/examples"]
+ path = resource/examples
+ url = https://github.com/hflicka/example-mlms.git
diff --git a/.project b/.project
index 530568f..7e72825 100644
--- a/.project
+++ b/.project
@@ -5,6 +5,16 @@
+
+ org.eclipse.ui.externaltools.ExternalToolBuilder
+ full,incremental,
+
+
+ LaunchConfigHandle
+ <project>/.externalToolBuilders/SableCC.launch
+
+
+
org.eclipse.jdt.core.javabuilder
diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs
index 83ba08d..f878c2a 100644
--- a/.settings/org.eclipse.jdt.core.prefs
+++ b/.settings/org.eclipse.jdt.core.prefs
@@ -1,4 +1,3 @@
-#Wed Dec 23 16:26:41 CET 2009
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
@@ -7,8 +6,78 @@ org.eclipse.jdt.core.compiler.compliance=1.6
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
+org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning
+org.eclipse.jdt.core.compiler.problem.deadCode=warning
+org.eclipse.jdt.core.compiler.problem.deprecation=warning
+org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
+org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
+org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
+org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore
+org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled
+org.eclipse.jdt.core.compiler.problem.fieldHiding=ignore
+org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning
+org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=error
+org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning
+org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=disabled
+org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning
+org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=ignore
+org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore
+org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore
+org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning
+org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore
+org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=ignore
+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=ignore
+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled
+org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning
+org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=ignore
+org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning
+org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning
+org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore
+org.eclipse.jdt.core.compiler.problem.nullReference=warning
+org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning
+org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore
+org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=ignore
+org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore
+org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning
+org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore
+org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=ignore
+org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore
+org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore
+org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore
+org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
+org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
+org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled
+org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
+org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore
+org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
+org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=enabled
+org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning
+org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore
+org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning
+org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore
+org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=ignore
+org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.unusedImport=warning
+org.eclipse.jdt.core.compiler.problem.unusedLabel=warning
+org.eclipse.jdt.core.compiler.problem.unusedLocal=warning
+org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=ignore
+org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore
+org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled
+org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
+org.eclipse.jdt.core.compiler.problem.unusedWarningToken=ignore
+org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
org.eclipse.jdt.core.compiler.source=1.6
org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
diff --git a/LICENSE b/LICENSE
deleted file mode 100644
index 139deb6..0000000
--- a/LICENSE
+++ /dev/null
@@ -1,471 +0,0 @@
-I would like to publish this compiler using the BSD license,
-but this is not possible because it's based on the
-Arden Syntax parser from the EGADSS Arden Compiler, which is
-using the GNU General Public License.
-
-However, I still use the BSD license for my own source code files,
-hoping that someone will write a new parser using a permissive license (e.g. BSD).
-But until this happens, this Arden Compiler as a whole is using the GNU GPL.
-
-Daniel Grunwald, 4th May 2010
-
-
- GNU LESSER GENERAL PUBLIC LICENSE
- Version 2.1, February 1999
-
- Copyright (C) 1991, 1999 Free Software Foundation, Inc.
- 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
-[This is the first released version of the Lesser GPL. It also counts
- as the successor of the GNU Library Public License, version 2, hence
- the version number 2.1.]
-
- Preamble
-
- The licenses for most software are designed to take away your
-freedom to share and change it. By contrast, the GNU General Public
-Licenses are intended to guarantee your freedom to share and change
-free software--to make sure the software is free for all its users.
-
- This license, the Lesser General Public License, applies to some
-specially designated software packages--typically libraries--of the
-Free Software Foundation and other authors who decide to use it. You
-can use it too, but we suggest you first think carefully about whether
-this license or the ordinary General Public License is the better
-strategy to use in any particular case, based on the explanations below.
-
- When we speak of free software, we are referring to freedom of use,
-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 this service if you wish); that you receive source code or can get
-it if you want it; that you can change the software and use pieces of
-it in new free programs; and that you are informed that you can do
-these things.
-
- To protect your rights, we need to make restrictions that forbid
-distributors to deny you these rights or to ask you to surrender these
-rights. These restrictions translate to certain responsibilities for
-you if you distribute copies of the library or if you modify it.
-
- For example, if you distribute copies of the library, whether gratis
-or for a fee, you must give the recipients all the rights that we gave
-you. You must make sure that they, too, receive or can get the source
-code. If you link other code with the library, you must provide
-complete object files to the recipients, so that they can relink them
-with the library after making changes to the library and recompiling
-it. And you must show them these terms so they know their rights.
-
- We protect your rights with a two-step method: (1) we copyright the
-library, and (2) we offer you this license, which gives you legal
-permission to copy, distribute and/or modify the library.
-
- To protect each distributor, we want to make it very clear that
-there is no warranty for the free library. Also, if the library is
-modified by someone else and passed on, the recipients should know
-that what they have is not the original version, so that the original
-author's reputation will not be affected by problems that might be
-introduced by others.
-
- Finally, software patents pose a constant threat to the existence of
-any free program. We wish to make sure that a company cannot
-effectively restrict the users of a free program by obtaining a
-restrictive license from a patent holder. Therefore, we insist that
-any patent license obtained for a version of the library must be
-consistent with the full freedom of use specified in this license.
-
- Most GNU software, including some libraries, is covered by the
-ordinary GNU General Public License. This license, the GNU Lesser
-General Public License, applies to certain designated libraries, and
-is quite different from the ordinary General Public License. We use
-this license for certain libraries in order to permit linking those
-libraries into non-free programs.
-
- When a program is linked with a library, whether statically or using
-a shared library, the combination of the two is legally speaking a
-combined work, a derivative of the original library. The ordinary
-General Public License therefore permits such linking only if the
-entire combination fits its criteria of freedom. The Lesser General
-Public License permits more lax criteria for linking other code with
-the library.
-
- We call this license the "Lesser" General Public License because it
-does Less to protect the user's freedom than the ordinary General
-Public License. It also provides other free software developers Less
-of an advantage over competing non-free programs. These disadvantages
-are the reason we use the ordinary General Public License for many
-libraries. However, the Lesser license provides advantages in certain
-special circumstances.
-
- For example, on rare occasions, there may be a special need to
-encourage the widest possible use of a certain library, so that it becomes
-a de-facto standard. To achieve this, non-free programs must be
-allowed to use the library. A more frequent case is that a free
-library does the same job as widely used non-free libraries. In this
-case, there is little to gain by limiting the free library to free
-software only, so we use the Lesser General Public License.
-
- In other cases, permission to use a particular library in non-free
-programs enables a greater number of people to use a large body of
-free software. For example, permission to use the GNU C Library in
-non-free programs enables many more people to use the whole GNU
-operating system, as well as its variant, the GNU/Linux operating
-system.
-
- Although the Lesser General Public License is Less protective of the
-users' freedom, it does ensure that the user of a program that is
-linked with the Library has the freedom and the wherewithal to run
-that program using a modified version of the Library.
-
- The precise terms and conditions for copying, distribution and
-modification follow. Pay close attention to the difference between a
-"work based on the library" and a "work that uses the library". The
-former contains code derived from the library, whereas the latter must
-be combined with the library in order to run.
-
- GNU LESSER GENERAL PUBLIC LICENSE
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
- 0. This License Agreement applies to any software library or other
-program which contains a notice placed by the copyright holder or
-other authorized party saying it may be distributed under the terms of
-this Lesser General Public License (also called "this License").
-Each licensee is addressed as "you".
-
- A "library" means a collection of software functions and/or data
-prepared so as to be conveniently linked with application programs
-(which use some of those functions and data) to form executables.
-
- The "Library", below, refers to any such software library or work
-which has been distributed under these terms. A "work based on the
-Library" means either the Library or any derivative work under
-copyright law: that is to say, a work containing the Library or a
-portion of it, either verbatim or with modifications and/or translated
-straightforwardly into another language. (Hereinafter, translation is
-included without limitation in the term "modification".)
-
- "Source code" for a work means the preferred form of the work for
-making modifications to it. For a library, complete source code means
-all the source code for all modules it contains, plus any associated
-interface definition files, plus the scripts used to control compilation
-and installation of the library.
-
- Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope. The act of
-running a program using the Library is not restricted, and output from
-such a program is covered only if its contents constitute a work based
-on the Library (independent of the use of the Library in a tool for
-writing it). Whether that is true depends on what the Library does
-and what the program that uses the Library does.
-
- 1. You may copy and distribute verbatim copies of the Library's
-complete source code as you receive it, in any medium, provided that
-you conspicuously and appropriately publish on each copy an
-appropriate copyright notice and disclaimer of warranty; keep intact
-all the notices that refer to this License and to the absence of any
-warranty; and distribute a copy of this License along with the
-Library.
-
- You may charge a fee for the physical act of transferring a copy,
-and you may at your option offer warranty protection in exchange for a
-fee.
-
- 2. You may modify your copy or copies of the Library or any portion
-of it, thus forming a work based on the Library, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
- a) The modified work must itself be a software library.
-
- b) You must cause the files modified to carry prominent notices
- stating that you changed the files and the date of any change.
-
- c) You must cause the whole of the work to be licensed at no
- charge to all third parties under the terms of this License.
-
- d) If a facility in the modified Library refers to a function or a
- table of data to be supplied by an application program that uses
- the facility, other than as an argument passed when the facility
- is invoked, then you must make a good faith effort to ensure that,
- in the event an application does not supply such function or
- table, the facility still operates, and performs whatever part of
- its purpose remains meaningful.
-
- (For example, a function in a library to compute square roots has
- a purpose that is entirely well-defined independent of the
- application. Therefore, Subsection 2d requires that any
- application-supplied function or table used by this function must
- be optional: if the application does not supply it, the square
- root function must still compute square roots.)
-
-These requirements apply to the modified work as a whole. If
-identifiable sections of that work are not derived from the Library,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works. But when you
-distribute the same sections as part of a whole which is a work based
-on the Library, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote
-it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Library.
-
-In addition, mere aggregation of another work not based on the Library
-with the Library (or with a work based on the Library) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
- 3. You may opt to apply the terms of the ordinary GNU General Public
-License instead of this License to a given copy of the Library. To do
-this, you must alter all the notices that refer to this License, so
-that they refer to the ordinary GNU General Public License, version 2,
-instead of to this License. (If a newer version than version 2 of the
-ordinary GNU General Public License has appeared, then you can specify
-that version instead if you wish.) Do not make any other change in
-these notices.
-
- Once this change is made in a given copy, it is irreversible for
-that copy, so the ordinary GNU General Public License applies to all
-subsequent copies and derivative works made from that copy.
-
- This option is useful when you wish to copy part of the code of
-the Library into a program that is not a library.
-
- 4. You may copy and distribute the Library (or a portion or
-derivative of it, under Section 2) in object code or executable form
-under the terms of Sections 1 and 2 above provided that you accompany
-it with the complete corresponding machine-readable source code, which
-must be distributed under the terms of Sections 1 and 2 above on a
-medium customarily used for software interchange.
-
- If distribution of object code is made by offering access to copy
-from a designated place, then offering equivalent access to copy the
-source code from the same place satisfies the requirement to
-distribute the source code, even though third parties are not
-compelled to copy the source along with the object code.
-
- 5. A program that contains no derivative of any portion of the
-Library, but is designed to work with the Library by being compiled or
-linked with it, is called a "work that uses the Library". Such a
-work, in isolation, is not a derivative work of the Library, and
-therefore falls outside the scope of this License.
-
- However, linking a "work that uses the Library" with the Library
-creates an executable that is a derivative of the Library (because it
-contains portions of the Library), rather than a "work that uses the
-library". The executable is therefore covered by this License.
-Section 6 states terms for distribution of such executables.
-
- When a "work that uses the Library" uses material from a header file
-that is part of the Library, the object code for the work may be a
-derivative work of the Library even though the source code is not.
-Whether this is true is especially significant if the work can be
-linked without the Library, or if the work is itself a library. The
-threshold for this to be true is not precisely defined by law.
-
- If such an object file uses only numerical parameters, data
-structure layouts and accessors, and small macros and small inline
-functions (ten lines or less in length), then the use of the object
-file is unrestricted, regardless of whether it is legally a derivative
-work. (Executables containing this object code plus portions of the
-Library will still fall under Section 6.)
-
- Otherwise, if the work is a derivative of the Library, you may
-distribute the object code for the work under the terms of Section 6.
-Any executables containing that work also fall under Section 6,
-whether or not they are linked directly with the Library itself.
-
- 6. As an exception to the Sections above, you may also combine or
-link a "work that uses the Library" with the Library to produce a
-work containing portions of the Library, and distribute that work
-under terms of your choice, provided that the terms permit
-modification of the work for the customer's own use and reverse
-engineering for debugging such modifications.
-
- You must give prominent notice with each copy of the work that the
-Library is used in it and that the Library and its use are covered by
-this License. You must supply a copy of this License. If the work
-during execution displays copyright notices, you must include the
-copyright notice for the Library among them, as well as a reference
-directing the user to the copy of this License. Also, you must do one
-of these things:
-
- a) Accompany the work with the complete corresponding
- machine-readable source code for the Library including whatever
- changes were used in the work (which must be distributed under
- Sections 1 and 2 above); and, if the work is an executable linked
- with the Library, with the complete machine-readable "work that
- uses the Library", as object code and/or source code, so that the
- user can modify the Library and then relink to produce a modified
- executable containing the modified Library. (It is understood
- that the user who changes the contents of definitions files in the
- Library will not necessarily be able to recompile the application
- to use the modified definitions.)
-
- b) Use a suitable shared library mechanism for linking with the
- Library. A suitable mechanism is one that (1) uses at run time a
- copy of the library already present on the user's computer system,
- rather than copying library functions into the executable, and (2)
- will operate properly with a modified version of the library, if
- the user installs one, as long as the modified version is
- interface-compatible with the version that the work was made with.
-
- c) Accompany the work with a written offer, valid for at
- least three years, to give the same user the materials
- specified in Subsection 6a, above, for a charge no more
- than the cost of performing this distribution.
-
- d) If distribution of the work is made by offering access to copy
- from a designated place, offer equivalent access to copy the above
- specified materials from the same place.
-
- e) Verify that the user has already received a copy of these
- materials or that you have already sent this user a copy.
-
- For an executable, the required form of the "work that uses the
-Library" must include any data and utility programs needed for
-reproducing the executable from it. However, as a special exception,
-the materials to be distributed need not include anything that is
-normally distributed (in either source or binary form) with the major
-components (compiler, kernel, and so on) of the operating system on
-which the executable runs, unless that component itself accompanies
-the executable.
-
- It may happen that this requirement contradicts the license
-restrictions of other proprietary libraries that do not normally
-accompany the operating system. Such a contradiction means you cannot
-use both them and the Library together in an executable that you
-distribute.
-
- 7. You may place library facilities that are a work based on the
-Library side-by-side in a single library together with other library
-facilities not covered by this License, and distribute such a combined
-library, provided that the separate distribution of the work based on
-the Library and of the other library facilities is otherwise
-permitted, and provided that you do these two things:
-
- a) Accompany the combined library with a copy of the same work
- based on the Library, uncombined with any other library
- facilities. This must be distributed under the terms of the
- Sections above.
-
- b) Give prominent notice with the combined library of the fact
- that part of it is a work based on the Library, and explaining
- where to find the accompanying uncombined form of the same work.
-
- 8. You may not copy, modify, sublicense, link with, or distribute
-the Library except as expressly provided under this License. Any
-attempt otherwise to copy, modify, sublicense, link with, or
-distribute the Library is void, and will automatically terminate your
-rights under this License. However, parties who have received copies,
-or rights, from you under this License will not have their licenses
-terminated so long as such parties remain in full compliance.
-
- 9. You are not required to accept this License, since you have not
-signed it. However, nothing else grants you permission to modify or
-distribute the Library or its derivative works. These actions are
-prohibited by law if you do not accept this License. Therefore, by
-modifying or distributing the Library (or any work based on the
-Library), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Library or works based on it.
-
- 10. Each time you redistribute the Library (or any work based on the
-Library), the recipient automatically receives a license from the
-original licensor to copy, distribute, link with or modify the Library
-subject to these terms and conditions. You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties with
-this License.
-
- 11. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-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
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Library at all. For example, if a patent
-license would not permit royalty-free redistribution of the Library by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Library.
-
-If any portion of this section is held invalid or unenforceable under any
-particular circumstance, the balance of the section is intended to apply,
-and the section as a whole is intended to apply in other circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system which is
-implemented by public license practices. Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-
- 12. If the distribution and/or use of the Library is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Library under this License may add
-an explicit geographical distribution limitation excluding those countries,
-so that distribution is permitted only in or among countries not thus
-excluded. In such case, this License incorporates the limitation as if
-written in the body of this License.
-
- 13. The Free Software Foundation may publish revised and/or new
-versions of the Lesser 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 Library
-specifies a version number of this License which applies to it and
-"any later version", you have the option of following the terms and
-conditions either of that version or of any later version published by
-the Free Software Foundation. If the Library does not specify a
-license version number, you may choose any version ever published by
-the Free Software Foundation.
-
- 14. If you wish to incorporate parts of the Library into other free
-programs whose distribution conditions are incompatible with these,
-write to the author to ask for permission. For software which is
-copyrighted by the Free Software Foundation, write to the Free
-Software Foundation; we sometimes make exceptions for this. Our
-decision will be guided by the two goals of preserving the free status
-of all derivatives of our free software and of promoting the sharing
-and reuse of software generally.
-
- NO WARRANTY
-
- 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
-WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
-EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
-OTHER PARTIES PROVIDE THE LIBRARY "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
-LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
-THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
-
- 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
-WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
-AND/OR REDISTRIBUTE THE LIBRARY 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
-LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
-SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
-DAMAGES.
-
- END OF TERMS AND CONDITIONS
-
diff --git a/LICENSE.md b/LICENSE.md
new file mode 100644
index 0000000..4363319
--- /dev/null
+++ b/LICENSE.md
@@ -0,0 +1,705 @@
+License of Arden2ByteCode
+=========================
+
+
+Note to License Used
+--------------------
+
+I would like to publish this compiler using the BSD license,
+but this is not possible because it's based on the
+Arden Syntax parser from the EGADSS Arden Compiler, which is
+using the GNU General Public License.
+
+However, I still use the BSD license for my own source code files,
+hoping that someone will write a new parser using a permissive license (e.g. BSD).
+But until this happens, this Arden Compiler as a whole is using the GNU GPL.
+
+Daniel Grunwald, 4th May 2010
+
+
+Libraries Used in Arden2ByteCode
+--------------------------------
+
+Arden2ByteCode as of the repository forked by Hannes Flicka
+(hflicka on GitHub) uses the JewelCLI binary distribution which
+is licensed under the terms of the Apache License version 2.0.
+The Apache License is found in the accompanying file `jewelcli-license.txt`
+
+
+Arden2ByteCode License Text
+---------------------------
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+ software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+ to take away your freedom to share and change the works. By contrast,
+ the GNU General Public License is intended to guarantee your freedom to
+ share and change all versions of a program--to make sure it remains free
+ software for all its users. We, the Free Software Foundation, use the
+ GNU General Public License for most of our software; it applies also to
+ any other work released this way by its authors. You can apply it to
+ your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+ price. Our General Public Licenses are designed to make sure that you
+ have the freedom to distribute copies of free software (and charge for
+ them if you wish), that you receive source code or can get it if you
+ want it, that you can change the software or use pieces of it in new
+ free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+ these rights or asking you to surrender the rights. Therefore, you have
+ certain responsibilities if you distribute copies of the software, or if
+ you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+ gratis or for a fee, you must pass on to the recipients the same
+ freedoms that you received. You must make sure that they, too, receive
+ or can get the source code. And you must show them these terms so they
+ know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+ (1) assert copyright on the software, and (2) offer you this License
+ giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+ that there is no warranty for this free software. For both users' and
+ authors' sake, the GPL requires that modified versions be marked as
+ changed, so that their problems will not be attributed erroneously to
+ authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+ modified versions of the software inside them, although the manufacturer
+ can do so. This is fundamentally incompatible with the aim of
+ protecting users' freedom to change the software. The systematic
+ pattern of such abuse occurs in the area of products for individuals to
+ use, which is precisely where it is most unacceptable. Therefore, we
+ have designed this version of the GPL to prohibit the practice for those
+ products. If such problems arise substantially in other domains, we
+ stand ready to extend this provision to those domains in future versions
+ of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+ States should not allow patents to restrict development and use of
+ software on general-purpose computers, but in those that do, we wish to
+ avoid the special danger that patents applied to a free program could
+ make it effectively proprietary. To prevent this, the GPL assures that
+ patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+ modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+ works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+ License. Each licensee is addressed as "you". "Licensees" and
+ "recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+ in a fashion requiring copyright permission, other than the making of an
+ exact copy. The resulting work is called a "modified version" of the
+ earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+ on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+ permission, would make you directly or secondarily liable for
+ infringement under applicable copyright law, except executing it on a
+ computer or modifying a private copy. Propagation includes copying,
+ distribution (with or without modification), making available to the
+ public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+ parties to make or receive copies. Mere interaction with a user through
+ a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+ to the extent that it includes a convenient and prominently visible
+ feature that (1) displays an appropriate copyright notice, and (2)
+ tells the user that there is no warranty for the work (except to the
+ extent that warranties are provided), that licensees may convey the
+ work under this License, and how to view a copy of this License. If
+ the interface presents a list of user commands or options, such as a
+ menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+ for making modifications to it. "Object code" means any non-source
+ form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+ standard defined by a recognized standards body, or, in the case of
+ interfaces specified for a particular programming language, one that
+ is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+ than the work as a whole, that (a) is included in the normal form of
+ packaging a Major Component, but which is not part of that Major
+ Component, and (b) serves only to enable use of the work with that
+ Major Component, or to implement a Standard Interface for which an
+ implementation is available to the public in source code form. A
+ "Major Component", in this context, means a major essential component
+ (kernel, window system, and so on) of the specific operating system
+ (if any) on which the executable work runs, or a compiler used to
+ produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+ the source code needed to generate, install, and (for an executable
+ work) run the object code and to modify the work, including scripts to
+ control those activities. However, it does not include the work's
+ System Libraries, or general-purpose tools or generally available free
+ programs which are used unmodified in performing those activities but
+ which are not part of the work. For example, Corresponding Source
+ includes interface definition files associated with source files for
+ the work, and the source code for shared libraries and dynamically
+ linked subprograms that the work is specifically designed to require,
+ such as by intimate data communication or control flow between those
+ subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+ can regenerate automatically from other parts of the Corresponding
+ Source.
+
+ The Corresponding Source for a work in source code form is that
+ same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+ copyright on the Program, and are irrevocable provided the stated
+ conditions are met. This License explicitly affirms your unlimited
+ permission to run the unmodified Program. The output from running a
+ covered work is covered by this License only if the output, given its
+ content, constitutes a covered work. This License acknowledges your
+ rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+ convey, without conditions so long as your license otherwise remains
+ in force. You may convey covered works to others for the sole purpose
+ of having them make modifications exclusively for you, or provide you
+ with facilities for running those works, provided that you comply with
+ the terms of this License in conveying all material for which you do
+ not control copyright. Those thus making or running the covered works
+ for you must do so exclusively on your behalf, under your direction
+ and control, on terms that prohibit them from making any copies of
+ your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+ the conditions stated below. Sublicensing is not allowed; section 10
+ makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+ measure under any applicable law fulfilling obligations under article
+ 11 of the WIPO copyright treaty adopted on 20 December 1996, or
+ similar laws prohibiting or restricting circumvention of such
+ measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+ circumvention of technological measures to the extent such circumvention
+ is effected by exercising rights under this License with respect to
+ the covered work, and you disclaim any intention to limit operation or
+ modification of the work as a means of enforcing, against the work's
+ users, your or third parties' legal rights to forbid circumvention of
+ technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+ receive it, in any medium, provided that you conspicuously and
+ appropriately publish on each copy an appropriate copyright notice;
+ keep intact all notices stating that this License and any
+ non-permissive terms added in accord with section 7 apply to the code;
+ keep intact all notices of the absence of any warranty; and give all
+ recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+ and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+ produce it from the Program, in the form of source code under the
+ terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+ works, which are not by their nature extensions of the covered work,
+ and which are not combined with it such as to form a larger program,
+ in or on a volume of a storage or distribution medium, is called an
+ "aggregate" if the compilation and its resulting copyright are not
+ used to limit the access or legal rights of the compilation's users
+ beyond what the individual works permit. Inclusion of a covered work
+ in an aggregate does not cause this License to apply to the other
+ parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+ of sections 4 and 5, provided that you also convey the
+ machine-readable Corresponding Source under the terms of this License,
+ in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+ from the Corresponding Source as a System Library, need not be
+ included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+ tangible personal property which is normally used for personal, family,
+ or household purposes, or (2) anything designed or sold for incorporation
+ into a dwelling. In determining whether a product is a consumer product,
+ doubtful cases shall be resolved in favor of coverage. For a particular
+ product received by a particular user, "normally used" refers to a
+ typical or common use of that class of product, regardless of the status
+ of the particular user or of the way in which the particular user
+ actually uses, or expects or is expected to use, the product. A product
+ is a consumer product regardless of whether the product has substantial
+ commercial, industrial or non-consumer uses, unless such uses represent
+ the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+ procedures, authorization keys, or other information required to install
+ and execute modified versions of a covered work in that User Product from
+ a modified version of its Corresponding Source. The information must
+ suffice to ensure that the continued functioning of the modified object
+ code is in no case prevented or interfered with solely because
+ modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+ specifically for use in, a User Product, and the conveying occurs as
+ part of a transaction in which the right of possession and use of the
+ User Product is transferred to the recipient in perpetuity or for a
+ fixed term (regardless of how the transaction is characterized), the
+ Corresponding Source conveyed under this section must be accompanied
+ by the Installation Information. But this requirement does not apply
+ if neither you nor any third party retains the ability to install
+ modified object code on the User Product (for example, the work has
+ been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+ requirement to continue to provide support service, warranty, or updates
+ for a work that has been modified or installed by the recipient, or for
+ the User Product in which it has been modified or installed. Access to a
+ network may be denied when the modification itself materially and
+ adversely affects the operation of the network or violates the rules and
+ protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+ in accord with this section must be in a format that is publicly
+ documented (and with an implementation available to the public in
+ source code form), and must require no special password or key for
+ unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+ License by making exceptions from one or more of its conditions.
+ Additional permissions that are applicable to the entire Program shall
+ be treated as though they were included in this License, to the extent
+ that they are valid under applicable law. If additional permissions
+ apply only to part of the Program, that part may be used separately
+ under those permissions, but the entire Program remains governed by
+ this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+ remove any additional permissions from that copy, or from any part of
+ it. (Additional permissions may be written to require their own
+ removal in certain cases when you modify the work.) You may place
+ additional permissions on material, added by you to a covered work,
+ for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+ add to a covered work, you may (if authorized by the copyright holders of
+ that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+ restrictions" within the meaning of section 10. If the Program as you
+ received it, or any part of it, contains a notice stating that it is
+ governed by this License along with a term that is a further
+ restriction, you may remove that term. If a license document contains
+ a further restriction but permits relicensing or conveying under this
+ License, you may add to a covered work material governed by the terms
+ of that license document, provided that the further restriction does
+ not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+ must place, in the relevant source files, a statement of the
+ additional terms that apply to those files, or a notice indicating
+ where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+ form of a separately written license, or stated as exceptions;
+ the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+ provided under this License. Any attempt otherwise to propagate or
+ modify it is void, and will automatically terminate your rights under
+ this License (including any patent licenses granted under the third
+ paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+ license from a particular copyright holder is reinstated (a)
+ provisionally, unless and until the copyright holder explicitly and
+ finally terminates your license, and (b) permanently, if the copyright
+ holder fails to notify you of the violation by some reasonable means
+ prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+ reinstated permanently if the copyright holder notifies you of the
+ violation by some reasonable means, this is the first time you have
+ received notice of violation of this License (for any work) from that
+ copyright holder, and you cure the violation prior to 30 days after
+ your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+ licenses of parties who have received copies or rights from you under
+ this License. If your rights have been terminated and not permanently
+ reinstated, you do not qualify to receive new licenses for the same
+ material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+ run a copy of the Program. Ancillary propagation of a covered work
+ occurring solely as a consequence of using peer-to-peer transmission
+ to receive a copy likewise does not require acceptance. However,
+ nothing other than this License grants you permission to propagate or
+ modify any covered work. These actions infringe copyright if you do
+ not accept this License. Therefore, by modifying or propagating a
+ covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+ receives a license from the original licensors, to run, modify and
+ propagate that work, subject to this License. You are not responsible
+ for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+ organization, or substantially all assets of one, or subdividing an
+ organization, or merging organizations. If propagation of a covered
+ work results from an entity transaction, each party to that
+ transaction who receives a copy of the work also receives whatever
+ licenses to the work the party's predecessor in interest had or could
+ give under the previous paragraph, plus a right to possession of the
+ Corresponding Source of the work from the predecessor in interest, if
+ the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+ rights granted or affirmed under this License. For example, you may
+ not impose a license fee, royalty, or other charge for exercise of
+ rights granted under this License, and you may not initiate litigation
+ (including a cross-claim or counterclaim in a lawsuit) alleging that
+ any patent claim is infringed by making, using, selling, offering for
+ sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+ License of the Program or a work on which the Program is based. The
+ work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+ owned or controlled by the contributor, whether already acquired or
+ hereafter acquired, that would be infringed by some manner, permitted
+ by this License, of making, using, or selling its contributor version,
+ but do not include claims that would be infringed only as a
+ consequence of further modification of the contributor version. For
+ purposes of this definition, "control" includes the right to grant
+ patent sublicenses in a manner consistent with the requirements of
+ this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+ patent license under the contributor's essential patent claims, to
+ make, use, sell, offer for sale, import and otherwise run, modify and
+ propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+ agreement or commitment, however denominated, not to enforce a patent
+ (such as an express permission to practice a patent or covenant not to
+ sue for patent infringement). To "grant" such a patent license to a
+ party means to make such an agreement or commitment not to enforce a
+ patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+ and the Corresponding Source of the work is not available for anyone
+ to copy, free of charge and under the terms of this License, through a
+ publicly available network server or other readily accessible means,
+ then you must either (1) cause the Corresponding Source to be so
+ available, or (2) arrange to deprive yourself of the benefit of the
+ patent license for this particular work, or (3) arrange, in a manner
+ consistent with the requirements of this License, to extend the patent
+ license to downstream recipients. "Knowingly relying" means you have
+ actual knowledge that, but for the patent license, your conveying the
+ covered work in a country, or your recipient's use of the covered work
+ in a country, would infringe one or more identifiable patents in that
+ country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+ arrangement, you convey, or propagate by procuring conveyance of, a
+ covered work, and grant a patent license to some of the parties
+ receiving the covered work authorizing them to use, propagate, modify
+ or convey a specific copy of the covered work, then the patent license
+ you grant is automatically extended to all recipients of the covered
+ work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+ the scope of its coverage, prohibits the exercise of, or is
+ conditioned on the non-exercise of one or more of the rights that are
+ specifically granted under this License. You may not convey a covered
+ work if you are a party to an arrangement with a third party that is
+ in the business of distributing software, under which you make payment
+ to the third party based on the extent of your activity of conveying
+ the work, and under which the third party grants, to any of the
+ parties who would receive the covered work from you, a discriminatory
+ patent license (a) in connection with copies of the covered work
+ conveyed by you (or copies made from those copies), or (b) primarily
+ for and in connection with specific products or compilations that
+ contain the covered work, unless you entered into that arrangement,
+ or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+ any implied license or other defenses to infringement that may
+ otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+ otherwise) that contradict the conditions of this License, they do not
+ excuse you from the conditions of this License. If you cannot convey a
+ covered work so as to satisfy simultaneously your obligations under this
+ License and any other pertinent obligations, then as a consequence you may
+ not convey it at all. For example, if you agree to terms that obligate you
+ to collect a royalty for further conveying from those to whom you convey
+ the Program, the only way you could satisfy both those terms and this
+ License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+ permission to link or combine any covered work with a work licensed
+ under version 3 of the GNU Affero General Public License into a single
+ combined work, and to convey the resulting work. The terms of this
+ License will continue to apply to the part which is the covered work,
+ but the special requirements of the GNU Affero General Public License,
+ section 13, concerning interaction through a network will apply to the
+ combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+ the GNU General Public License from time to time. Such new versions will
+ be similar in spirit to the present version, but may differ in detail to
+ address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+ Program specifies that a certain numbered version of the GNU General
+ Public License "or any later version" applies to it, you have the
+ option of following the terms and conditions either of that numbered
+ version or of any later version published by the Free Software
+ Foundation. If the Program does not specify a version number of the
+ GNU General Public License, you may choose any version ever published
+ by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+ versions of the GNU General Public License can be used, that proxy's
+ public statement of acceptance of a version permanently authorizes you
+ to choose that version for the Program.
+
+ Later license versions may give you additional or different
+ permissions. However, no additional obligations are imposed on any
+ author or copyright holder as a result of your choosing to follow a
+ later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+ APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+ HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+ OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+ THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+ IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+ WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+ THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+ GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+ USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+ DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+ PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+ EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+ above cannot be given local legal effect according to their terms,
+ reviewing courts shall apply local law that most closely approximates
+ an absolute waiver of all civil liability in connection with the
+ Program, unless a warranty or assumption of liability accompanies a
+ copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+ possible use to the public, the best way to achieve this is to make it
+ free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+ to attach them to the start of each source file to most effectively
+ state the exclusion of warranty; and each file should have at least
+ the "copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+
+ Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+ notice like this when it starts in an interactive mode:
+
+ Copyright (C)
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+ The hypothetical commands `show w' and `show c' should show the appropriate
+ parts of the General Public License. Of course, your program's commands
+ might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+ if any, to sign a "copyright disclaimer" for the program, if necessary.
+ For more information on this, and how to apply and follow the GNU GPL, see
+ .
+
+ The GNU General Public License does not permit incorporating your program
+ into proprietary programs. If your program is a subroutine library, you
+ may consider it more useful to permit linking proprietary applications with
+ the library. If this is what you want to do, use the GNU Lesser General
+ Public License instead of this License. But first, please read
+ .
diff --git a/README b/README
deleted file mode 100644
index cb57ee9..0000000
--- a/README
+++ /dev/null
@@ -1,44 +0,0 @@
-Copyright 2009-2010, Daniel Grunwald
-Portions (arden.scc) Copyright 2004, University of British Columbia
-See LICENSE.txt for licensing information.
-
-
-To compile the compiler, you first need to generate the parser using
-the SableCC parser generator.
-To do this, run
-"java -classpath ../tools/sablecc.jar org.sablecc.sablecc.SableCC arden.scc"
-in the arden2bytecode/src directory.
-This will create the directories "analysis","lexer","node","parser" within
-arden2bytecode/src/arden.
-
-When the input grammar is changed, you will need to re-generate the parser.
-Before regenerating the parser, you should delete the old "analysis","lexer",
-"node","parser" directories to ensure there aren't any old files left behind.
-
-
-To configure SableCC as external tool in Eclipse:
- 1. Create an external tool configuration:
- Location: javaw.exe (from your Java runtime)
- Working directory: ${container_loc}
- Arguments: -classpath ${project_loc}\tools\sablecc.jar org.sablecc.sablecc.SableCC ${resource_name}
- 2. Select the file "arden.scc" and run SableCC.
- 3. Right-click "src" and press Refresh so that Eclipse loads the generated files.
-
-
-I believe this compiler fully implements Arden Syntax 2.5 with the following exceptions:
-
-Languages features not implemented:
- From Arden Syntax 2.1 specification:
- 10.2.4.6 Event Call
- 11.2.2 Event Statement
- 13 Evoke Slot
- From Arden Syntax 2.5 specification:
- 11.2.5.2 Message As statement
- 11.2.5.6 Destination As statement
- A6.2 "Time of" always returns null for objects. (correct would be: if all attributes of an object share a common primary time, the time of operator will return that time when applied to the object)
- Timezones for ArdenTime values.
- Some string formatting specificiers are not implemented.
- There is no way to use Arden variables within mapping clauses.
- Citation/links slots are not syntax checked.
- The compiler does not check that no languages features newer than the specified 'Arden Version' are used.
-
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..9526434
--- /dev/null
+++ b/README.md
@@ -0,0 +1,68 @@
+Arden2ByteCode - Compiler for Arden Syntax with Java Bytecode output
+====================================================================
+
+Copyright 2009-2010, Daniel Grunwald , 2011-2012, Hannes Flicka
+Portions (arden.scc) Copyright 2004, University of British Columbia
+See LICENSE.txt for licensing information.
+
+Building Notes
+--------------
+
+To compile Arden2ByteCode, you first need to generate the parser using
+the SableCC parser generator.
+To do this, run
+`java -classpath ../tools/sablecc.jar org.sablecc.sablecc.SableCC arden.scc`
+in the arden2bytecode/src directory.
+This will create the directories `analysis`,`lexer`,`node`,`parser` within
+`arden2bytecode/src/arden`.
+
+When the input grammar is changed, you will need to re-generate the parser.
+Before regenerating the parser, you should delete the old `analysis`,`lexer`,
+`node`,`parser` directories to ensure there aren't any old files left behind.
+
+If you use Eclipse to build, compiling the parser is done automatically.
+The Eclipse project has a SableCC builder in Project -> Properties -> Builders.
+The SableCC builder of the project basically starts the Ant task `sableCC`
+contained in build.xml.
+As building the parser has only to be done initially and after changes of
+the grammar, you can disable the SableCC builder if you want to save time.
+
+If you use Ant to build, SableCC is started automatically. Again, if you want
+to save time, you can disable the `sableCC` target by removing the `sableCC`
+dependency from the `compile` target.
+
+
+Building Howto
+--------------
+
+To build with Eclipse, import the project and choose
+Project -> Build project... from the menu.
+
+To build with Ant, cd into the source root and type `ant` at the command
+prompt.
+
+This is explained in detail in the project's wiki at GitHub:
+https://github.com/hflicka/arden2bytecode/wiki/Getting-Started-with-Arden2ByteCode
+
+
+Notes to the Present Implementation
+-----------------------------------
+
+Daniel:
+I believe this compiler fully implements Arden Syntax 2.5 with the following exceptions:
+
+Languages features not implemented:
+
+* From Arden Syntax 2.1 specification:
+ * 10.2.4.6 Event Call
+ * 11.2.2 Event Statement
+ * 13 Evoke Slot
+* From Arden Syntax 2.5 specification:
+ * 11.2.5.2 Message As statement
+ * 11.2.5.6 Destination As statement
+ * A6.2 "Time of" always returns null for objects. (correct would be: if all attributes of an object share a common primary time, the time of operator will return that time when applied to the object)
+ * Timezones for ArdenTime values.
+ * Some string formatting specificiers are not implemented.
+ * There is no way to use Arden variables within mapping clauses.
+ * Citation/links slots are not syntax checked.
+ * The compiler does not check that no languages features newer than the specified 'Arden Version' are used.
diff --git a/build.xml b/build.xml
new file mode 100644
index 0000000..841f8bb
--- /dev/null
+++ b/build.xml
@@ -0,0 +1,252 @@
+
+
+
+ arden2bytecode ant build script.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ @echo off
+ java -jar "%~dp0${jar.filename}" %*
+ rem pause
+
+ #!/bin/sh
+ java -jar "$( cd -P "$( dirname "$0" )" && pwd )/${jar.filename}" "$@"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/jewelcli-license.txt b/jewelcli-license.txt
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/jewelcli-license.txt
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/lib/jewelcli-0.6.jar b/lib/jewelcli-0.6.jar
new file mode 100644
index 0000000..17d6c6e
Binary files /dev/null and b/lib/jewelcli-0.6.jar differ
diff --git a/resource/arden2bytecode.config b/resource/arden2bytecode.config
new file mode 100644
index 0000000..93f76fe
--- /dev/null
+++ b/resource/arden2bytecode.config
@@ -0,0 +1 @@
+# arden2bytecode config file
diff --git a/resource/examples b/resource/examples
new file mode 160000
index 0000000..57da760
--- /dev/null
+++ b/resource/examples
@@ -0,0 +1 @@
+Subproject commit 57da7600adcd46f0f8e1194e81e8303d7fbf2674
diff --git a/run.bat b/run.bat
new file mode 100644
index 0000000..a7ac90b
--- /dev/null
+++ b/run.bat
@@ -0,0 +1,4 @@
+@echo off
+set PWD=%~dp0
+java -cp "%PWD%bin;%PWD%lib\jewelcli-0.6.jar" arden.MainClass %*
+pause
diff --git a/src/arden.scc b/src/arden.scc
index f6bfae8..a8c6bbc 100644
--- a/src/arden.scc
+++ b/src/arden.scc
@@ -638,7 +638,7 @@ logic_assignment =
identifier_becomes =
{id} identifier_or_object_ref assign
- | {let} let identifier be
+ | {let} let identifier_or_object_ref be
| {now} now assign;
identifier_or_object_ref =
diff --git a/src/arden/CommandLineOptions.java b/src/arden/CommandLineOptions.java
new file mode 100644
index 0000000..3c9bbca
--- /dev/null
+++ b/src/arden/CommandLineOptions.java
@@ -0,0 +1,96 @@
+// arden2bytecode
+// Copyright (c) 2010, Daniel Grunwald
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are
+// permitted provided that the following conditions are met:
+//
+// - Redistributions of source code must retain the above copyright notice, this list
+// of conditions and the following disclaimer.
+//
+// - Redistributions in binary form must reproduce the above copyright notice, this list
+// of conditions and the following disclaimer in the documentation and/or other materials
+// provided with the distribution.
+//
+// - Neither the name of the owner nor the names of its contributors may be used to
+// endorse or promote products derived from this software without specific prior written
+// permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS &AS IS& AND ANY EXPRESS
+// OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package arden;
+
+import java.util.List;
+
+import uk.co.flamingpenguin.jewel.cli.CommandLineInterface;
+import uk.co.flamingpenguin.jewel.cli.Option;
+import uk.co.flamingpenguin.jewel.cli.Unparsed;
+
+@CommandLineInterface(application="arden2bytecode")
+public interface CommandLineOptions {
+ @Option(shortName = "r",
+ description = "Run MLM file or already compiled MLM class file.")
+ boolean getRun();
+
+ @Option(shortName = "c",
+ description = "Compile input file.")
+ boolean getCompile();
+
+ @Option(shortName = "v",
+ description = "Verbose mode.")
+ boolean getVerbose();
+
+ @Option(shortName = "n",
+ description = "Don't print logo.")
+ boolean getNologo();
+
+ @Option(helpRequest = true,
+ description = "Display help.",
+ shortName = {"h", "?"})
+ boolean getHelp();
+
+ @Unparsed
+ List getFiles();
+ boolean isFiles();
+
+ @Option(shortName = "o",
+ description = "Output file name to compile .MLM file to. \n" +
+ "\t You can also specify a directory in order to compile multiple MLMs.")
+ String getOutput();
+ boolean isOutput();
+
+ @Option(shortName = "a",
+ description = "Arguments to MLM if running a MLM.")
+ List getArguments();
+ boolean isArguments();
+
+ @Option(shortName = "e",
+ description = "Set arguments to execution environment if \n\t running a MLM. \n" +
+ "\t In case of using JDBC, this may be a connection URL e.g. \n" +
+ "\t \"jdbc:mysql://host:port/database?options\".",
+ defaultValue = "stdio")
+ String getEnvironment();
+ boolean isEnvironment();
+
+ @Option(shortName = "d",
+ description = "Class name of database driver to load \n" +
+ "\t (e.g. \"com.mysql.jdbc.Driver\").")
+ String getDbdriver();
+ boolean isDbdriver();
+
+ @Option(shortName = "p",
+ description = "Additional classpath. \n"
+ + "\t E.g. a database driver like \"mysql-connector-java-[version]-bin.jar\".")
+ String getClasspath();
+ boolean isClasspath();
+
+ @Option(description = "Run daemon that invokes MLMs when they are scheduled")
+ boolean getDaemon();
+}
diff --git a/src/arden/MainClass.java b/src/arden/MainClass.java
index 7cfafdd..f062371 100644
--- a/src/arden/MainClass.java
+++ b/src/arden/MainClass.java
@@ -1,5 +1,5 @@
-// arden2bytecode
-// Copyright (c) 2010, Daniel Grunwald
+// Arden2ByteCode
+// Copyright (c) 2010, Daniel Grunwald, Hannes Flicka
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
@@ -27,54 +27,413 @@
package arden;
+import java.io.BufferedOutputStream;
+import java.io.File;
import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
-import arden.compiler.CompiledMlm;
+import uk.co.flamingpenguin.jewel.cli.ArgumentValidationException;
+import uk.co.flamingpenguin.jewel.cli.CliFactory;
import arden.compiler.Compiler;
import arden.compiler.CompilerException;
+import arden.compiler.CompiledMlm;
+import arden.constants.ConstantParser;
+import arden.constants.ConstantParser.ConstantParserException;
import arden.runtime.ArdenValue;
import arden.runtime.ExecutionContext;
+import arden.runtime.ExpressionHelpers;
+import arden.runtime.MedicalLogicModule;
+import arden.runtime.StdIOExecutionContext;
+import arden.runtime.jdbc.JDBCExecutionContext;
public class MainClass {
+ public final static String MLM_FILE_EXTENSION = ".mlm";
+
+ private final static String COMPILED_MLM_FILE_EXTENSION = ".class";
- public static void main(String[] args) {
- System.out.println("arden2bytecode Interpreter example");
- System.out.println("Copyright 2010 Daniel Grunwald");
- System.out.println("");
- System.out.println("This program is free software; you can redistribute it and/or modify it");
- System.out.println("under the terms of the GNU General Public License.");
- System.out.println("");
-
+ private final static Pattern JAVA_CLASS_NAME =
+ Pattern.compile("[A-Za-z$_][A-Za-z0-9$_]*(?:\\.[A-Za-z$_][A-Za-z0-9$_]*)*");
+
+ private CommandLineOptions options;
+
+ private static List handleInputFileNames(List filenames) {
+ List inputFiles = new LinkedList();
+ if ((filenames == null) || filenames.isEmpty()) {
+ return null;
+ }
+ for (String filePath : filenames) {
+ File file = new File(filePath);
+ if (file.exists()) {
+ // file exists => add to input files
+ inputFiles.add(file);
+ } else {
+ // file does not exist => could be a classname rather than a filename
+ Matcher m = JAVA_CLASS_NAME.matcher(filePath);
+ if (m.matches()) {
+ String classFileName =
+ filePath.replace('.', File.separatorChar)
+ + COMPILED_MLM_FILE_EXTENSION;
+ File classFile = new File(classFileName);
+ if (classFile.exists()) {
+ inputFiles.add(classFile);
+ } else {
+ System.err.println("File " + filePath + " and class file " + classFileName
+ + " do not exist.");
+ }
+ } else {
+ System.err.println("File \"" + filePath
+ + "\" is neither an existing file "
+ + "nor a valid class name.");
+ }
+ }
+ }
+ return inputFiles;
+ }
+
+ private CompiledMlm compileMlm(File mlmfile) {
+ if (options.getVerbose()) {
+ System.out.println("Compiling " + mlmfile.getPath() + " ...");
+ }
+
+ CompiledMlm mlm = null;
Compiler compiler = new Compiler();
- CompiledMlm mlm;
- try {
- compiler.enableDebugging(args[0]);
- mlm = compiler.compileMlm(new FileReader(args[0]));
- } catch (FileNotFoundException e) {
- e.printStackTrace();
- return;
+ try {
+ compiler.enableDebugging(mlmfile.getPath());
+ mlm = compiler.compileMlm(new FileReader(mlmfile.getPath()));
} catch (CompilerException e) {
+ System.err.println("exception compiling " + mlmfile.getPath() + ":");
+ e.printStackTrace();
+ System.exit(1);
+ } catch (FileNotFoundException e) {
+ System.err.println("file not found: " + mlmfile.getPath());
e.printStackTrace();
- return;
+ System.exit(1);
} catch (IOException e) {
+ System.err.println("IO error reading: " + mlmfile.getPath());
e.printStackTrace();
- return;
+ System.exit(1);
}
- ExecutionContext context = new ExecutionContext() {
- @Override
- public void write(ArdenValue message, String destination) {
- System.out.println(message.toString());
+ return mlm;
+ }
+
+ private ExecutionContext createExecutionContext() {
+ if (options.isEnvironment()) {
+ if (options.getEnvironment().startsWith("jdbc")) {
+ return new JDBCExecutionContext(options);
+ } else if ("stdio".equalsIgnoreCase(options.getEnvironment())) {
+ return new StdIOExecutionContext(options);
+ } else {
+ return new StdIOExecutionContext(options);
+ }
+ } else {
+ return new StdIOExecutionContext(options);
+ }
+ }
+
+ private ArdenValue[] getArguments() {
+ ArdenValue[] arguments = null;
+ if (options.isArguments()) {
+ ArdenValue ardenArg = null;
+ for (String arg : options.getArguments()) {
+ ArdenValue parsedArg = null;
+ try {
+ parsedArg = ConstantParser.parse(arg);
+ } catch (ConstantParserException e) {
+ e.printStackTrace();
+ }
+ if (ardenArg == null) {
+ ardenArg = parsedArg;
+ } else {
+ ardenArg = ExpressionHelpers.binaryComma(ardenArg, parsedArg);
+ }
}
- };
+ arguments = new ArdenValue[]{ardenArg};
+ }
+ return arguments;
+ }
+
+ private ArdenValue[] runMlm(MedicalLogicModule mlm, ExecutionContext context) {
+ ArdenValue[] arguments = getArguments();
+
+ ArdenValue[] result = null;
try {
- ArdenValue[] result = mlm.run(context, null);
- if (result != null && result.length == 1)
+ result = mlm.run(context, arguments);
+ if (result != null && result.length == 1) {
System.out.println("Return Value: " + result[0].toString());
+ } else if (result != null && result.length > 1) {
+ for (int i = 0; i < result.length; i++) {
+ System.out.println("ReturnValue[" + i + "]: " + result[i].toString());
+ }
+ } else {
+ System.out.println("There was no return value.");
+ }
} catch (InvocationTargetException e) {
e.printStackTrace();
}
+ return result;
+ }
+
+ public static String getFilenameBase(String filename) {
+ int sepindex = Math.max(filename.lastIndexOf('/'), filename.lastIndexOf('\\'));
+ int fnindex = filename.lastIndexOf('.');
+ if (fnindex < sepindex) {
+ fnindex = -1;
+ }
+ if (fnindex < 0) {
+ return filename.substring(sepindex + 1);
+ }
+ return filename.substring(sepindex + 1, fnindex);
+ }
+
+ private MedicalLogicModule getMlmFromFile(File file) {
+ String filename = file.getName();
+ MedicalLogicModule mlm = null;
+ if (filename.endsWith(COMPILED_MLM_FILE_EXTENSION)) {
+ // load compiled mlm (.class file)
+ try {
+ mlm = new CompiledMlm(file, getFilenameBase(filename));
+ } catch (IOException e) {
+ System.err.println("Error loading " +
+ file.getPath());
+ e.printStackTrace();
+ return null;
+ }
+ } else if (file.getName().endsWith(MLM_FILE_EXTENSION)) {
+ // compile .mlm file
+ mlm = compileMlm(file);
+ } else {
+ System.err.println("File \"" + file.getPath()
+ + "\" is neither .class nor .mlm file.");
+ System.err.println("Can't run such a file.");
+ return null;
+ }
+ return mlm;
+ }
+
+ private int runInputFile(File fileToRun) {
+ ExecutionContext context = createExecutionContext();
+
+ MedicalLogicModule mlm = getMlmFromFile(fileToRun);
+ if (mlm == null) {
+ return 1;
+ }
+
+ if (options.getVerbose()) {
+ System.out.println("Running MLM...");
+ System.out.println("");
+ }
+
+ // run the mlm
+ runMlm(mlm, context);
+
+ return 0;
+ }
+
+ private int compileInputFiles(List inputFiles) {
+ boolean firstFile = true;
+ for (File fileToCompile : inputFiles) {
+ CompiledMlm mlm = compileMlm(fileToCompile);
+ File outputFile = null;
+ if (options.isOutput() && firstFile) {
+ // output file name given. write to that file...
+ outputFile = new File(options.getOutput());
+ } else {
+ // output file name unknown. assume mlm name + '.class' extension
+ String assumedName = mlm.getName() + COMPILED_MLM_FILE_EXTENSION;
+ File assumed = new File(fileToCompile.getParentFile(), assumedName);
+ if (firstFile) {
+ System.err.println("warning: File " + fileToCompile.getPath()
+ + " compiled, but no output filename given. Assuming "
+ + assumed.getPath()
+ + " as output file.");
+ } else {
+ System.err.println("warning: File " + fileToCompile.getPath()
+ + " compiled, but can't write to same output file again. "
+ + "Assuming "
+ + assumed.getPath()
+ + " as output file.");
+ }
+ outputFile = assumed;
+ }
+
+ // if output file is known, compile mlm and write compiled mlm to that file.
+ if (outputFile != null) {
+ try {
+ FileOutputStream fos = new FileOutputStream(outputFile);
+ BufferedOutputStream bos = new BufferedOutputStream(fos);
+ mlm.saveClassFile(bos);
+ bos.close();
+ fos.close();
+ } catch (IOException e) {
+ System.err.println("Exception writing output file "
+ + outputFile.getPath() + ":");
+ e.printStackTrace();
+ return 1;
+ }
+ }
+ }
+ return 0;
+ }
+
+ private static void printLogo() {
+ System.out.println("Arden2ByteCode Compiler and Runtime Environment");
+ System.out.println("Copyright 2010-2011 Daniel Grunwald, Hannes Flicka");
+ System.out.println("");
+ System.out.println("This program is free software; you can redistribute it and/or modify it");
+ System.out.println("under the terms of the GNU General Public License.");
+ System.out.println("");
+ }
+
+ private void extendClasspath() {
+ String classpath = options.getClasspath();
+ String[] paths = classpath.split(File.pathSeparator);
+ List urls = new LinkedList();
+ for (String path : paths) {
+ File f = new File(path);
+ if (!f.exists()) {
+ System.err.println("error: Classpath File/Directory \""
+ + path + "\" does not exist.");
+ System.exit(1);
+ }
+ URL url = null;
+ try {
+ url = f.toURI().toURL();
+ } catch (MalformedURLException e) {
+ e.printStackTrace();
+ System.exit(1);
+ }
+ if (options.getVerbose()) {
+ System.out.println("Adding to classpath: " + url);
+ }
+ urls.add(url);
+ }
+
+ ClassLoader currentClassLoader =
+ Thread.currentThread().getContextClassLoader();
+ URLClassLoader ulc = new URLClassLoader(
+ urls.toArray(new URL[]{}),
+ currentClassLoader);
+ Thread.currentThread().setContextClassLoader(ulc);
+
+ if (options.getVerbose()) {
+ System.out.println();
+ }
+ }
+
+ private int runMlmDaemon(List inputFiles) {
+ if (inputFiles.size() < 1) {
+ System.err.println("No MLM file specified");
+ return 1;
+ }
+ List mlms = new LinkedList();
+ for (File file : inputFiles) {
+ MedicalLogicModule mlm = getMlmFromFile(file);
+ if (mlm == null) {
+ return 1;
+ }
+ mlms.add(mlm);
+ }
+ ExecutionContext context = createExecutionContext();
+ ArdenValue[] arguments = getArguments();
+ new MlmDaemon(mlms, context, arguments).run();
+ return 0;
+ }
+
+ private int handleCommandLineArgs(String[] args) {
+ // parse command line using jewelCli:
+ try {
+ options = CliFactory.parseArguments(CommandLineOptions.class, args);
+ } catch (ArgumentValidationException e) {
+ printLogo();
+ String message = e.getMessage();
+ System.err.println(message);
+
+ if (message.startsWith("Usage")) { // hack to display additional help.
+ System.err.println("All further command line arguments that "
+ + "are non-options are regarded as input \n"
+ + "files.");
+ System.err.println("For a command-line reference, see:\n"
+ + "http://arden2bytecode.sourceforge.net/docs/"
+ + "arden2bytecode-command-line-reference");
+ }
+
+ return 1;
+ }
+
+ // print logo
+ if (!options.getNologo()) {
+ printLogo();
+ }
+
+ if (options.isClasspath()) {
+ extendClasspath();
+ }
+
+ // suggest using help if no options given:
+ if (args.length < 1) {
+ System.out.println("Supply argument -h or -? to display help.");
+ System.out.println("");
+ }
+
+ // check input files to this main method:
+ List files = options.getFiles();
+ List inputFiles = handleInputFileNames(files);
+ if (inputFiles == null) {
+ System.err.println("No input files given.");
+ return 1;
+ }
+
+ // if verbose output is requested, list input files:
+ if (options.getVerbose()) {
+ for (File f : inputFiles) {
+ System.out.println("Input file: " + f.getPath());
+ }
+ System.out.println("");
+ }
+
+ // check if option -r (run) or -c (compile) was given:
+ if (options.getRun()) {
+ if (inputFiles.size() < 1) {
+ System.err.println("You should specify at least one " +
+ "MLM or compiled MLM .class file when " +
+ "trying to run an MLM.");
+ return 1;
+ }
+ for (File fileToRun : inputFiles) {
+ int result = runInputFile(fileToRun);
+ if (result != 0) {
+ return result;
+ }
+ }
+ } else if (options.getCompile()) {
+ return compileInputFiles(inputFiles);
+ } else if (options.getDaemon()) {
+ return runMlmDaemon(inputFiles);
+ } else {
+ System.err.println("You should specify -r to run the files or "
+ + "-c to compile the files.");
+ System.err.println("Specifying files without telling what to "
+ + "do with them is not implemented.");
+ return 1;
+ }
+
+ return 0;
+ }
+
+ public static void main(String[] args) {
+ int returnValue =
+ new MainClass().handleCommandLineArgs(args);
+
+ System.exit(returnValue);
}
}
diff --git a/src/arden/MlmDaemon.java b/src/arden/MlmDaemon.java
new file mode 100644
index 0000000..2469142
--- /dev/null
+++ b/src/arden/MlmDaemon.java
@@ -0,0 +1,86 @@
+package arden;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import arden.runtime.ArdenTime;
+import arden.runtime.ArdenValue;
+import arden.runtime.ExecutionContext;
+import arden.runtime.MedicalLogicModule;
+import arden.runtime.events.EvokeEvent;
+
+public class MlmDaemon implements Runnable {
+ List mlms;
+ ExecutionContext context;
+ ArdenValue[] arguments;
+
+ public MlmDaemon(List mlms, ExecutionContext context, ArdenValue[] arguments) {
+ this.mlms = mlms;
+ this.context = context;
+ this.arguments = arguments;
+ }
+
+ private SortedMap> createSchedule(List mlms) {
+ SortedMap> mlmSchedule = new TreeMap>(new ArdenTime.NaturalComparator());
+ for (MedicalLogicModule mlm : mlms) {
+ try {
+ EvokeEvent e = mlm.getEvoke(context, arguments);
+ ArdenTime currentTime = context.getCurrentTime();
+ ArdenTime nextRuntime = e.getNextRunTime(context);
+ if (nextRuntime == null || currentTime.compareTo(nextRuntime) > 0) {
+ continue;
+ }
+ List alreadyScheduled = mlmSchedule.get(nextRuntime);
+ if (alreadyScheduled == null) {
+ List toSchedule = new LinkedList();
+ toSchedule.add(mlm);
+ mlmSchedule.put(nextRuntime, toSchedule);
+ } else {
+ alreadyScheduled.add(mlm);
+ }
+ } catch (InvocationTargetException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ return mlmSchedule;
+ }
+
+ @Override
+ public void run() {
+ while (true) {
+ SortedMap> mlmSchedule = createSchedule(mlms);
+ if (mlmSchedule.isEmpty()) {
+ break;
+ }
+ ArdenTime nextRuntime = mlmSchedule.firstKey();
+ List scheduledMlms = mlmSchedule.get(nextRuntime);
+ ArdenTime currentTime = context.getCurrentTime();
+ long delay = nextRuntime.value - currentTime.value;
+ if (delay >= 0) {
+ try {
+ Thread.sleep(nextRuntime.value - currentTime.value);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ for (MedicalLogicModule mlm : scheduledMlms) {
+ try {
+ mlm.run(context, arguments);
+ } catch (InvocationTargetException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+ while (nextRuntime.compareTo(context.getCurrentTime()) >= 0) {
+ try {
+ Thread.sleep(1); // make sure at least 1 ms passes
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+}
diff --git a/src/arden/codegenerator/ExceptionTable.java b/src/arden/codegenerator/ExceptionTable.java
new file mode 100644
index 0000000..1ea4793
--- /dev/null
+++ b/src/arden/codegenerator/ExceptionTable.java
@@ -0,0 +1,51 @@
+package arden.codegenerator;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+
+final class ExceptionTable {
+ private final ConstantPool pool;
+ private ArrayList ranges = new ArrayList();
+
+ public ExceptionTable(ConstantPool pool) {
+ this.pool = pool;
+ }
+
+ public void addExceptionRange(
+ Label start,
+ Label end,
+ Label handlerBegin,
+ Class extends Throwable> exception) {
+ ranges.add(new ExceptionRange(pool.getClass(exception), start, end, handlerBegin));
+ }
+
+ public byte[] getData() {
+ try {
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ DataOutputStream dos = new DataOutputStream(bos);
+ dos.writeShort(ranges.size());
+ for (ExceptionRange range : ranges) {
+ dos.writeShort(range.start.markedPosition);
+ dos.writeShort(range.end.markedPosition);
+ dos.writeShort(range.handlerBegin.markedPosition);
+ dos.writeShort(range.catchType);
+ }
+ return bos.toByteArray();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ static class ExceptionRange {
+ int catchType;
+ Label start, end, handlerBegin;
+ public ExceptionRange(int catchType, Label start, Label end, Label handlerBegin) {
+ this.catchType = catchType;
+ this.start = start;
+ this.end = end;
+ this.handlerBegin = handlerBegin;
+ }
+ }
+}
diff --git a/src/arden/codegenerator/MethodWriter.java b/src/arden/codegenerator/MethodWriter.java
index 7bea0cc..6a2f696 100644
--- a/src/arden/codegenerator/MethodWriter.java
+++ b/src/arden/codegenerator/MethodWriter.java
@@ -50,6 +50,9 @@ public final class MethodWriter {
/** Line number table, used if debugging information should be output */
private LineNumberTable lineNumberTable;
+ /** Exception table declaring jump targets for given Exceptions */
+ private ExceptionTable exceptionTable;
+
/** Table of local variables (for use by debuggers) */
private LocalVariableTable localVariableTable;
@@ -265,7 +268,11 @@ public byte[] getCodeAttributeData() {
byte[] code = getByteCode();
data.writeInt(code.length);
data.write(code);
- data.writeShort(0); // exception_table_length
+ if (exceptionTable == null) {
+ data.writeShort(0); // exception_table_length
+ } else {
+ data.write(exceptionTable.getData());
+ }
int attributesCount = 0;
if (lineNumberTable != null)
attributesCount++;
@@ -322,6 +329,20 @@ public void sequencePoint(int lineNumber) {
lineNumberTable.addEntry(byteCode.size(), lineNumber);
}
+ /**
+ * Marks a try..catch region.
+ * @param start Beginning of region where thrown Exceptions should be handled
+ * @param end End of region where thrown Exceptions should be handled
+ * @param handler Start of Exception handling code
+ * @param exceptionType Type of Exception to be thrown
+ */
+ public void addExceptionInfo(Label start, Label end, Label handler, Class extends Throwable> exceptionType) {
+ if (exceptionTable == null) {
+ exceptionTable = new ExceptionTable(pool);
+ }
+ exceptionTable.addExceptionRange(start, end, handler, exceptionType);
+ }
+
private void emitLdc(int constantIndex) {
if (constantIndex < 256) {
emit(18); // ldc
@@ -824,6 +845,16 @@ public void mark(Label label) {
throw new IllegalArgumentException("The label already was used to mark a position.");
}
}
+
+ public void markExceptionHandler(Label label) {
+ if (label.markedPosition == -1) {
+ label.markedPosition = getCurrentPosition();
+ stackSize = -1;
+ label.stackSize = -1;
+ } else {
+ throw new IllegalArgumentException("The label already was used to mark a position.");
+ }
+ }
/** Emits the 'return' instruction. */
public void returnFromProcedure() {
diff --git a/src/arden/compiler/CallableVariable.java b/src/arden/compiler/CallableVariable.java
index b7feb09..92f5f93 100644
--- a/src/arden/compiler/CallableVariable.java
+++ b/src/arden/compiler/CallableVariable.java
@@ -48,7 +48,7 @@ final class CallableVariable extends Variable {
// instance field of type ArdenRunnable
final FieldReference mlmField;
- public CallableVariable(TIdentifier varName, FieldReference mlmField) {
+ private CallableVariable(TIdentifier varName, FieldReference mlmField) {
super(varName);
this.mlmField = mlmField;
}
diff --git a/src/arden/compiler/CodeGenerator.java b/src/arden/compiler/CodeGenerator.java
index 61c15bf..25d4147 100644
--- a/src/arden/compiler/CodeGenerator.java
+++ b/src/arden/compiler/CodeGenerator.java
@@ -29,6 +29,7 @@
import java.io.DataOutput;
import java.io.IOException;
+import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;
@@ -45,8 +46,11 @@
import arden.runtime.ArdenTime;
import arden.runtime.ArdenValue;
import arden.runtime.ExecutionContext;
+import arden.runtime.LibraryMetadata;
+import arden.runtime.MaintenanceMetadata;
import arden.runtime.MedicalLogicModule;
import arden.runtime.MedicalLogicModuleImplementation;
+import arden.runtime.events.EvokeEvent;
/**
* This class is responsible for generating the
@@ -166,6 +170,7 @@ public FieldReference getTimeLiteral(long value) {
public CodeGenerator(String mlmName, int lineNumberForStaticInitializationSequencePoint) {
this.classFileWriter = new ClassFileWriter(mlmName, MedicalLogicModuleImplementation.class);
this.lineNumberForStaticInitializationSequencePoint = lineNumberForStaticInitializationSequencePoint;
+ createParameterLessConstructor();
}
private boolean isDebuggingEnabled = false;
@@ -181,6 +186,8 @@ public void enableDebugging(String sourceFileName) {
private final Label ctorInitCodeLabel = new Label();
private int lineNumberForInitializationSequencePoint;
+ private MethodWriter parameterLessCtor;
+
public CompilerContext createConstructor(int lineNumberForInitializationSequencePoint) {
ctor = classFileWriter.createConstructor(Modifier.PUBLIC, new Class>[] { ExecutionContext.class,
MedicalLogicModule.class, ArdenValue[].class });
@@ -201,6 +208,19 @@ public CompilerContext createConstructor(int lineNumberForInitializationSequence
ctor.mark(ctorUserCodeLabel);
return new CompilerContext(this, ctor, 3);
}
+
+ public CompilerContext createParameterLessConstructor() {
+ parameterLessCtor = classFileWriter.createConstructor(Modifier.PUBLIC, new Class>[] {});
+ parameterLessCtor.loadThis();
+ try {
+ parameterLessCtor.invokeConstructor(MedicalLogicModuleImplementation.class.getConstructor());
+ } catch (SecurityException e) {
+ throw new RuntimeException(e);
+ } catch (NoSuchMethodException e) {
+ throw new RuntimeException(e);
+ }
+ return new CompilerContext(this, ctor, 3);
+ }
public CompilerContext createLogic() {
MethodWriter w = classFileWriter.createMethod("logic", Modifier.PUBLIC,
@@ -224,6 +244,96 @@ public CompilerContext createUrgency() {
w.enableLineNumberTable();
return new CompilerContext(this, w, 0);
}
+
+ public CompilerContext createPriority() {
+ MethodWriter w = classFileWriter.createMethod("getPriority", Modifier.PUBLIC, new Class>[] {}, Double.TYPE);
+ if (isDebuggingEnabled)
+ w.enableLineNumberTable();
+ return new CompilerContext(this, w, 0);
+ }
+
+ public CompilerContext createMaintenance() {
+ MethodWriter w = classFileWriter.createMethod("getMaintenanceMetadata", Modifier.PUBLIC, new Class>[] {}, MaintenanceMetadata.class);
+ if (isDebuggingEnabled)
+ w.enableLineNumberTable();
+ return new CompilerContext(this, w, 0);
+ }
+
+ public CompilerContext createLibrary() {
+ MethodWriter w = classFileWriter.createMethod("getLibraryMetadata", Modifier.PUBLIC, new Class>[] {}, LibraryMetadata.class);
+ if (isDebuggingEnabled)
+ w.enableLineNumberTable();
+ return new CompilerContext(this, w, 0);
+ }
+
+ public CompilerContext createEvokeEvent() {
+ MethodWriter w = classFileWriter.createMethod(
+ "getEvokeEvent",
+ Modifier.PUBLIC,
+ new Class>[] { ExecutionContext.class },
+ EvokeEvent.class);
+ if (isDebuggingEnabled)
+ w.enableLineNumberTable();
+ return new CompilerContext(this, w, 1);
+ }
+
+ public void createGetValue() {
+ MethodWriter w = classFileWriter.createMethod(
+ "getValue",
+ Modifier.PUBLIC,
+ new Class>[]{ String.class },
+ ArdenValue.class);
+ try {
+ Label excptBegin = new Label();
+ Label excptEnd = new Label();
+ Label end = new Label();
+ Label secHandler = new Label();
+ Label noSuchFieldHandler = new Label();
+ Label illegalArgHandler = new Label();
+ Label illegalAccHandler = new Label();
+ w.mark(excptBegin);
+ w.loadThis();
+ w.invokeInstance(Object.class.getMethod("getClass"));
+ w.loadVariable(1);
+ w.invokeInstance(Class.class.getMethod("getDeclaredField", String.class));
+ w.dup();
+ w.storeVariable(2);
+ w.loadThis();
+ w.invokeInstance(Field.class.getMethod("get", Object.class));
+ w.checkCast(ArdenValue.class);
+ w.returnObjectFromFunction();
+ w.mark(excptEnd);
+
+ w.markExceptionHandler(secHandler);
+ w.storeVariable(3);
+ w.jump(end);
+
+ w.markExceptionHandler(noSuchFieldHandler);
+ w.storeVariable(3);
+ w.jump(end);
+
+ w.markExceptionHandler(illegalArgHandler);
+ w.storeVariable(3);
+ w.jump(end);
+
+ w.markExceptionHandler(illegalAccHandler);
+ w.storeVariable(3);
+ w.jump(end);
+
+ w.mark(end);
+ w.loadNull();
+ w.returnObjectFromFunction();
+
+ w.addExceptionInfo(excptBegin, excptEnd, noSuchFieldHandler, NoSuchFieldException.class);
+ w.addExceptionInfo(excptBegin, excptEnd, secHandler, SecurityException.class);
+ w.addExceptionInfo(excptBegin, excptEnd, illegalAccHandler, IllegalAccessException.class);
+ w.addExceptionInfo(excptBegin, excptEnd, illegalArgHandler, IllegalArgumentException.class);
+ } catch (SecurityException e) {
+ throw new RuntimeException(e);
+ } catch (NoSuchMethodException e) {
+ throw new RuntimeException(e);
+ }
+ }
public FieldReference getNowField() {
if (nowField == null) {
@@ -288,6 +398,10 @@ public void deleteVariable(Variable var) {
/** Saves the class file */
public void save(DataOutput output) throws IOException {
if (!isFinished) {
+ if (parameterLessCtor != null) {
+ parameterLessCtor.returnFromProcedure();
+ }
+
if (staticInitializer != null)
staticInitializer.returnFromProcedure();
diff --git a/src/arden/compiler/CompiledMlm.java b/src/arden/compiler/CompiledMlm.java
index d37409b..1723c10 100644
--- a/src/arden/compiler/CompiledMlm.java
+++ b/src/arden/compiler/CompiledMlm.java
@@ -27,11 +27,16 @@
package arden.compiler;
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
import java.io.IOException;
+import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
+import arden.MainClass;
import arden.runtime.ArdenList;
import arden.runtime.ArdenValue;
import arden.runtime.ExecutionContext;
@@ -39,61 +44,109 @@
import arden.runtime.MaintenanceMetadata;
import arden.runtime.MedicalLogicModule;
import arden.runtime.MedicalLogicModuleImplementation;
+import arden.runtime.events.EvokeEvent;
/**
- * Represents a compiled MedicalLogicModule.
+ * Represents a compiled MedicalLogicModule with minimal Metadata (as loaded from a .class File)
*
* Allows saving the compiled bytecode into a .class file by calling the
* saveClassFile() method.
*
+ * Allows loading of MedicalLogicModuleImplementation .class file by
+ * calling loadClassFile().
+ *
* When createInstance() or run() is called, the compiled bytecode is loaded
* using the InMemoryClassLoader for execution.
*
- * @author Daniel Grunwald
+ * @author Daniel Grunwald, Hannes Flicka
*
*/
public final class CompiledMlm implements MedicalLogicModule {
- private final byte[] data;
- private final MaintenanceMetadata maintenance;
- private final LibraryMetadata library;
- private final String mlmname;
- private final double priority;
- private Constructor extends MedicalLogicModuleImplementation> ctor;
-
- CompiledMlm(byte[] data, MaintenanceMetadata maintenance, LibraryMetadata library, double priority) {
- if (data == null || maintenance == null || library == null)
- throw new NullPointerException();
+ private byte[] data;
+ Class extends MedicalLogicModuleImplementation> clazz = null;
+ private MedicalLogicModuleImplementation uninitializedInstance = null;
+ private MedicalLogicModuleImplementation initializedInstance = null;
+ private EvokeEvent evokeEvent = null;
+ private String mlmname;
+
+ public CompiledMlm(byte[] data, String mlmname) {
this.data = data;
- this.maintenance = maintenance;
- this.library = library;
- this.mlmname = maintenance.getMlmName();
- this.priority = priority;
+ this.mlmname = mlmname;
+ }
+
+ public CompiledMlm(InputStream in, String mlmname) throws IOException {
+ this((byte[]) null, mlmname);
+ loadClassData(in, in.available());
+ this.mlmname = getName();
+ }
+
+ public CompiledMlm(File mlmfile, String mlmname) throws IOException {
+ this((byte[]) null, mlmname);
+ if (this.mlmname == null) {
+ this.mlmname = MainClass.getFilenameBase(mlmfile.getName());
+ }
+ loadClassFile(mlmfile);
+ this.mlmname = getName();
}
public void saveClassFile(OutputStream os) throws IOException {
os.write(data);
}
+
+ private void loadClassFile(File file) throws IOException {
+ loadClassData(
+ new BufferedInputStream(
+ new FileInputStream(file)),
+ (int)(file.length()));
+ }
+
+ private void loadClassData(InputStream in, int len) throws IOException {
+ data = new byte[len];
+ in.read(data, 0, len);
+ }
@SuppressWarnings("unchecked")
- private synchronized Constructor extends MedicalLogicModuleImplementation> getConstructor() {
- if (ctor == null) {
- Class extends MedicalLogicModuleImplementation> clazz;
+ private Class extends MedicalLogicModuleImplementation> loadClazz() {
+ if (clazz == null) {
try {
ClassLoader classLoader = new InMemoryClassLoader(mlmname, data);
clazz = (Class extends MedicalLogicModuleImplementation>) classLoader.loadClass(mlmname);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
- // We know the class has an appropriate constructor because we
- // compiled it, so wrap all the checked exceptions that should never
- // occur.
- try {
- ctor = clazz.getConstructor(ExecutionContext.class, MedicalLogicModule.class, ArdenValue[].class);
- } catch (SecurityException e) {
- throw new RuntimeException(e);
- } catch (NoSuchMethodException e) {
- throw new RuntimeException(e);
- }
+ }
+ return clazz;
+ }
+
+ private synchronized Constructor extends MedicalLogicModuleImplementation> getConstructor() {
+ Constructor extends MedicalLogicModuleImplementation> ctor = null;
+ loadClazz();
+ // We know the class has an appropriate constructor because we
+ // compiled it, so wrap all the checked exceptions that should never
+ // occur.
+ try {
+ ctor = clazz.getConstructor(ExecutionContext.class, MedicalLogicModule.class, ArdenValue[].class);
+ } catch (SecurityException e) {
+ throw new RuntimeException(e);
+ } catch (NoSuchMethodException e) {
+ throw new RuntimeException(e);
+ }
+ return ctor;
+ }
+
+ private synchronized Constructor extends MedicalLogicModuleImplementation> getParameterlessConstructor() {
+ Constructor extends MedicalLogicModuleImplementation> ctor = null;
+ loadClazz();
+ //loadClazz();
+ // We know the class has an appropriate constructor because we
+ // compiled it, so wrap all the checked exceptions that should never
+ // occur.
+ try {
+ ctor = clazz.getConstructor();
+ } catch (SecurityException e) {
+ throw new RuntimeException(e);
+ } catch (NoSuchMethodException e) {
+ throw new RuntimeException(e);
}
return ctor;
}
@@ -127,34 +180,80 @@ public MedicalLogicModuleImplementation createInstance(ExecutionContext context,
*/
@Override
public ArdenValue[] run(ExecutionContext context, ArdenValue[] arguments) throws InvocationTargetException {
- MedicalLogicModuleImplementation impl = createInstance(context, arguments);
+ MedicalLogicModuleImplementation instance = createInstance(context, arguments);
+ initializedInstance = instance;
try {
- if (impl.logic(context))
- return impl.action(context);
+ if (instance.logic(context))
+ return instance.action(context);
else
return null;
} catch (Exception ex) {
throw new InvocationTargetException(ex);
}
+ }
+
+ /** use this method only to access static fields in the MLM implementation */
+ private MedicalLogicModuleImplementation getNonInitializedInstance() {
+ if (uninitializedInstance == null) {
+ try {
+ uninitializedInstance = getParameterlessConstructor().newInstance();
+ } catch (InstantiationException e) {
+ throw new RuntimeException(e);
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(e);
+ } catch (IllegalArgumentException e) {
+ throw new RuntimeException(e);
+ } catch (InvocationTargetException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ return uninitializedInstance;
}
-
+
@Override
public MaintenanceMetadata getMaintenance() {
- return maintenance;
+ return getNonInitializedInstance().getMaintenanceMetadata();
}
@Override
public LibraryMetadata getLibrary() {
- return library;
+ return getNonInitializedInstance().getLibraryMetadata();
+ }
+
+ @Override
+ public double getUrgency() {
+ return getNonInitializedInstance().getUrgency();
}
@Override
public String getName() {
- return mlmname;
+ return getMaintenance().getMlmName();
}
@Override
public double getPriority() {
- return priority;
+ return getNonInitializedInstance().getPriority();
+ }
+
+ /** Gets an evoke event telling when to run the MLM.
+ * As that evoke event may depend on data set in the
+ * constructor, the data section of the MLM is run */
+ @Override
+ public EvokeEvent getEvoke(ExecutionContext context, ArdenValue[] arguments) throws InvocationTargetException {
+ if (evokeEvent == null) {
+ MedicalLogicModuleImplementation instance = initializedInstance;
+ if (instance == null) {
+ instance = createInstance(context, arguments);
+ }
+ evokeEvent = instance.getEvokeEvent(context);
+ }
+ return evokeEvent;
+ }
+
+ public ArdenValue getValue(String name) {
+ if (initializedInstance != null) {
+ return initializedInstance.getValue(name);
+ }
+ return null;
}
}
diff --git a/src/arden/compiler/Compiler.java b/src/arden/compiler/Compiler.java
index 1385629..564b10d 100644
--- a/src/arden/compiler/Compiler.java
+++ b/src/arden/compiler/Compiler.java
@@ -33,9 +33,14 @@
import java.io.PushbackReader;
import java.io.Reader;
import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
import java.util.ArrayList;
+import java.util.Date;
import java.util.List;
+import arden.codegenerator.FieldReference;
+import arden.codegenerator.Label;
+import arden.codegenerator.MethodWriter;
import arden.compiler.analysis.DepthFirstAdapter;
import arden.compiler.lexer.Lexer;
import arden.compiler.lexer.LexerException;
@@ -48,6 +53,7 @@
import arden.compiler.node.AUrgUrgencySlot;
import arden.compiler.node.PActionSlot;
import arden.compiler.node.PDataSlot;
+import arden.compiler.node.PEvokeSlot;
import arden.compiler.node.PLogicSlot;
import arden.compiler.node.PUrgencySlot;
import arden.compiler.node.PUrgencyVal;
@@ -56,8 +62,11 @@
import arden.compiler.parser.Parser;
import arden.compiler.parser.ParserException;
import arden.runtime.ArdenValue;
+import arden.runtime.LibraryMetadata;
+import arden.runtime.MaintenanceMetadata;
import arden.runtime.MedicalLogicModule;
import arden.runtime.RuntimeHelpers;
+import arden.runtime.events.EvokeEvent;
/**
* The main class of the compiler.
@@ -139,12 +148,24 @@ private CompiledMlm doCompileMlm(AMlm mlm) {
.getLine());
if (isDebuggingEnabled)
codeGen.enableDebugging(sourceFileName);
-
+
compileData(codeGen, knowledge.getDataSlot());
compileLogic(codeGen, knowledge.getLogicSlot());
compileAction(codeGen, knowledge.getActionSlot());
+ compileEvoke(codeGen, knowledge.getEvokeSlot());
compileUrgency(codeGen, knowledge.getUrgencySlot());
+ try {
+ compileMaintenance(codeGen, metadata.maintenance);
+ compileLibrary(codeGen, metadata.library);
+ compilePriority(codeGen, metadata.priority);
+ } catch (NoSuchMethodException e) {
+ throw new RuntimeException(e);
+ } catch (SecurityException e) {
+ throw new RuntimeException(e);
+ }
+ codeGen.createGetValue();
+
byte[] data;
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
@@ -155,9 +176,97 @@ private CompiledMlm doCompileMlm(AMlm mlm) {
} catch (IOException e) {
throw new RuntimeException(e);
}
- return new CompiledMlm(data, metadata.maintenance, metadata.library, metadata.priority);
+ return new CompiledMlm(data, metadata.maintenance.getMlmName());
}
+ private void compileMaintenance(CodeGenerator codeGen, MaintenanceMetadata maintenance) throws NoSuchMethodException, SecurityException {
+ FieldReference maintenanceField = codeGen.createStaticFinalField(MaintenanceMetadata.class);
+ MethodWriter init = codeGen.getStaticInitializer();
+ // format = new MaintenanceMetadata(String title, String mlmName, String ardenVersion, String version, String institution, String author, String specialist, Date date, String validation)
+ init.newObject(MaintenanceMetadata.class);
+ init.dup();
+ init.loadStringConstant(maintenance.getTitle());
+ init.loadStringConstant(maintenance.getMlmName());
+ init.loadStringConstant(maintenance.getArdenVersion());
+ init.loadStringConstant(maintenance.getVersion());
+ init.loadStringConstant(maintenance.getInstitution());
+ init.loadStringConstant(maintenance.getAuthor());
+ init.loadStringConstant(maintenance.getSpecialist());
+
+ init.newObject(Date.class);
+ init.dup();
+ init.loadLongConstant(maintenance.getDate().getTime());
+ init.invokeConstructor(Date.class.getConstructor(new Class>[]{Long.TYPE}));
+
+ init.loadStringConstant(maintenance.getValidation());
+
+ init.invokeConstructor(MaintenanceMetadata.class.getConstructor(new Class>[]{String.class, String.class, String.class, String.class, String.class, String.class, String.class, Date.class, String.class}));
+ init.storeStaticField(maintenanceField);
+
+ CompilerContext context = codeGen.createMaintenance();
+ context.writer.loadStaticField(maintenanceField);
+ context.writer.returnObjectFromFunction();
+ }
+
+ private void compileLibrary(CodeGenerator codeGen, LibraryMetadata library) throws NoSuchMethodException, SecurityException {
+ FieldReference libraryField = codeGen.createStaticFinalField(LibraryMetadata.class);
+ MethodWriter init = codeGen.getStaticInitializer();
+ // format = new LibraryMetadata(String purpose, String explanation, String[] keywords, String citations, String links)
+ init.newObject(LibraryMetadata.class);
+ init.dup();
+ init.loadStringConstant(library.getPurpose());
+ init.loadStringConstant(library.getExplanation());
+ init.loadIntegerConstant(library.getKeywords().size());
+ init.newArray(String.class);
+ for (int i = 0; i < library.getKeywords().size(); i++) {
+ init.dup();
+ init.loadIntegerConstant(i);
+ init.loadStringConstant(library.getKeywords().get(i));
+ init.storeObjectToArray();
+ }
+ init.loadStringConstant(library.getCitations());
+ init.loadStringConstant(library.getLinks());
+
+ init.invokeConstructor(LibraryMetadata.class.getConstructor(new Class>[]{String.class, String.class, String[].class, String.class, String.class}));
+ init.storeStaticField(libraryField);
+
+ CompilerContext context = codeGen.createLibrary();
+ context.writer.loadStaticField(libraryField);
+ context.writer.returnObjectFromFunction();
+ }
+
+ private void compilePriority(CodeGenerator codeGen, double priority) {
+ CompilerContext context = codeGen.createPriority();
+ context.writer.loadDoubleConstant(priority);
+ context.writer.returnDoubleFromFunction();
+ }
+
+ private void compileEvoke(CodeGenerator codeGen, PEvokeSlot evokeSlot) {
+ CompilerContext context = codeGen.createEvokeEvent();
+
+ // event is a keyword, thus there cannot be another field named 'event'
+ FieldReference eventField = context.codeGenerator.createField("event", EvokeEvent.class, Modifier.PRIVATE);
+
+ Label isNull = new Label();
+
+ context.writer.loadThis();
+ context.writer.loadInstanceField(eventField);
+ context.writer.jumpIfNull(isNull);
+ context.writer.loadThis();
+ context.writer.loadInstanceField(eventField);
+ context.writer.returnObjectFromFunction();
+
+ context.writer.mark(isNull);
+ evokeSlot.apply(new EvokeCompiler(context));
+
+ // the evoke compiler is supposed to leave an EvokeEvent subclass instance on the stack
+ context.writer.dup();
+ context.writer.loadThis();
+ context.writer.swap();
+ context.writer.storeInstanceField(eventField);
+ context.writer.returnObjectFromFunction();
+ }
+
private void compileData(CodeGenerator codeGen, PDataSlot dataSlot) {
int lineNumber = ((ADataSlot) dataSlot).getDataColon().getLine();
CompilerContext context = codeGen.createConstructor(lineNumber);
@@ -182,10 +291,11 @@ private void compileAction(CodeGenerator codeGen, PActionSlot actionSlot) {
context.writer.returnObjectFromFunction();
}
- private void compileUrgency(CodeGenerator codeGen, PUrgencySlot urgencySlot) {
+ private double compileUrgency(CodeGenerator codeGen, PUrgencySlot urgencySlot) {
// urgency_slot =
// {empty}
// | {urg} urgency urgency_val semicolons;
+ double urgency = RuntimeHelpers.DEFAULT_URGENCY;
if (urgencySlot instanceof AUrgUrgencySlot) {
PUrgencyVal val = ((AUrgUrgencySlot) urgencySlot).getUrgencyVal();
CompilerContext context = codeGen.createUrgency();
@@ -194,8 +304,9 @@ private void compileUrgency(CodeGenerator codeGen, PUrgencySlot urgencySlot) {
// {num} P.number
// | {id} identifier;
if (val instanceof ANumUrgencyVal) {
- context.writer.loadDoubleConstant(ParseHelpers
- .getLiteralDoubleValue(((ANumUrgencyVal) val).getNumberLiteral()));
+ urgency = ParseHelpers
+ .getLiteralDoubleValue(((ANumUrgencyVal) val).getNumberLiteral());
+ context.writer.loadDoubleConstant(urgency);
} else if (val instanceof AIdUrgencyVal) {
TIdentifier ident = ((AIdUrgencyVal) val).getIdentifier();
Variable var = codeGen.getVariableOrShowError(ident);
@@ -210,6 +321,7 @@ private void compileUrgency(CodeGenerator codeGen, PUrgencySlot urgencySlot) {
}
context.writer.returnDoubleFromFunction();
}
+ return urgency;
}
static Method getRuntimeHelper(String name, Class>... parameterTypes) {
diff --git a/src/arden/compiler/DataCompiler.java b/src/arden/compiler/DataCompiler.java
index 6ebd98c..cb816b0 100644
--- a/src/arden/compiler/DataCompiler.java
+++ b/src/arden/compiler/DataCompiler.java
@@ -227,10 +227,13 @@ public void caseAImapDataAssignPhrase(AImapDataAssignPhrase node) {
@Override
public void caseAEmapDataAssignPhrase(AEmapDataAssignPhrase node) {
// {emap} event mapping_factor
- if (!(lhs instanceof LeftHandSideIdentifier))
- throw new RuntimeCompilerException(lhs.getPosition(), "EVENT variables must be simple identifiers");
- TIdentifier ident = ((LeftHandSideIdentifier) lhs).identifier;
- context.codeGenerator.addVariable(new EventVariable(ident, node.getMappingFactor()));
+ EventVariable e = EventVariable.getEventVariable(context.codeGenerator, lhs);
+ context.writer.sequencePoint(lhs.getPosition().getLine());
+ context.writer.loadThis();
+ context.writer.loadVariable(context.executionContextVariable);
+ context.writer.loadStringConstant(ParseHelpers.getStringForMapping(node.getMappingFactor()));
+ context.writer.invokeInstance(ExecutionContextMethods.getEvent);
+ context.writer.storeInstanceField(e.field);
}
@Override
diff --git a/src/arden/compiler/DataVariable.java b/src/arden/compiler/DataVariable.java
index 2ee15dd..fa2aade 100644
--- a/src/arden/compiler/DataVariable.java
+++ b/src/arden/compiler/DataVariable.java
@@ -40,7 +40,7 @@
* @author Daniel Grunwald
*
*/
-final class DataVariable extends Variable {
+class DataVariable extends Variable {
final FieldReference field;
public DataVariable(TIdentifier name, FieldReference field) {
diff --git a/src/arden/compiler/DepthFirstVisitorBase.java b/src/arden/compiler/DepthFirstVisitorBase.java
new file mode 100644
index 0000000..01777c6
--- /dev/null
+++ b/src/arden/compiler/DepthFirstVisitorBase.java
@@ -0,0 +1,45 @@
+// arden2bytecode
+// Copyright (c) 2010, Daniel Grunwald
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are
+// permitted provided that the following conditions are met:
+//
+// - Redistributions of source code must retain the above copyright notice, this list
+// of conditions and the following disclaimer.
+//
+// - Redistributions in binary form must reproduce the above copyright notice, this list
+// of conditions and the following disclaimer in the documentation and/or other materials
+// provided with the distribution.
+//
+// - Neither the name of the owner nor the names of its contributors may be used to
+// endorse or promote products derived from this software without specific prior written
+// permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS &AS IS& AND ANY EXPRESS
+// OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package arden.compiler;
+
+import arden.compiler.analysis.DepthFirstAdapter;
+import arden.compiler.node.Node;
+
+/**
+ * Base class for depth first visitors. Throws an exception for unknown nodes.
+ *
+ * @author Hannes Flicka
+ *
+ */
+class DepthFirstVisitorBase extends DepthFirstAdapter {
+
+ @Override
+ public void defaultCase(Node node) {
+ throw new RuntimeException("Unsupported node: " + node.getClass().getName());
+ }
+}
diff --git a/src/arden/compiler/DestinationVariable.java b/src/arden/compiler/DestinationVariable.java
index 38eafe0..e1edcdb 100644
--- a/src/arden/compiler/DestinationVariable.java
+++ b/src/arden/compiler/DestinationVariable.java
@@ -42,7 +42,7 @@
final class DestinationVariable extends Variable {
final FieldReference field;
- public DestinationVariable(TIdentifier name, FieldReference field) {
+ private DestinationVariable(TIdentifier name, FieldReference field) {
super(name);
this.field = field;
}
diff --git a/src/arden/compiler/EventVariable.java b/src/arden/compiler/EventVariable.java
index 7cb8f9a..26ad0f4 100644
--- a/src/arden/compiler/EventVariable.java
+++ b/src/arden/compiler/EventVariable.java
@@ -27,14 +27,29 @@
package arden.compiler;
-import arden.compiler.node.PMappingFactor;
-import arden.compiler.node.TIdentifier;
+import java.lang.reflect.Modifier;
-final class EventVariable extends Variable {
- final PMappingFactor mapping;
+import arden.codegenerator.FieldReference;
+import arden.compiler.node.TIdentifier;
+import arden.runtime.events.EvokeEvent;
- public EventVariable(TIdentifier name, PMappingFactor mapping) {
- super(name);
- this.mapping = mapping;
+final class EventVariable extends DataVariable {
+ private EventVariable(TIdentifier name, FieldReference field) {
+ super(name, field);
+ }
+
+ public static EventVariable getEventVariable(CodeGenerator codeGen, LeftHandSideResult lhs) {
+ if (!(lhs instanceof LeftHandSideIdentifier))
+ throw new RuntimeCompilerException(lhs.getPosition(), "EVENT variables must be simple identifiers");
+ TIdentifier ident = ((LeftHandSideIdentifier) lhs).identifier;
+ Variable variable = codeGen.getVariable(ident.getText());
+ if (variable instanceof EventVariable) {
+ return (EventVariable) variable;
+ } else {
+ FieldReference mlmField = codeGen.createField(ident.getText(), EvokeEvent.class, Modifier.PRIVATE);
+ EventVariable ev = new EventVariable(ident, mlmField);
+ codeGen.addVariable(ev);
+ return ev;
+ }
}
}
\ No newline at end of file
diff --git a/src/arden/compiler/EvokeCompiler.java b/src/arden/compiler/EvokeCompiler.java
new file mode 100644
index 0000000..1e3ff72
--- /dev/null
+++ b/src/arden/compiler/EvokeCompiler.java
@@ -0,0 +1,307 @@
+package arden.compiler;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import arden.compiler.node.AAnyEventOr;
+import arden.compiler.node.AAolstEventAny;
+import arden.compiler.node.ACallEvokeStatement;
+import arden.compiler.node.AEblkEvokeBlock;
+import arden.compiler.node.AEcycEvokeStatement;
+import arden.compiler.node.AEdurEvokeTime;
+import arden.compiler.node.AEfctEventAny;
+import arden.compiler.node.AElstEventList;
+import arden.compiler.node.AEmptyEvokeStatement;
+import arden.compiler.node.AEorEventList;
+import arden.compiler.node.AEorEvokeStatement;
+import arden.compiler.node.AEstmtEvokeBlock;
+import arden.compiler.node.AEtimEvokeStatement;
+import arden.compiler.node.AEvokeDuration;
+import arden.compiler.node.AEvokeSlot;
+import arden.compiler.node.AIdEventFactor;
+import arden.compiler.node.AIdateEvokeTime;
+import arden.compiler.node.AIdtEvokeTime;
+import arden.compiler.node.AOrEventOr;
+import arden.compiler.node.ASimpQualifiedEvokeCycle;
+import arden.compiler.node.ASimpleEvokeCycle;
+import arden.compiler.node.ASuntQualifiedEvokeCycle;
+import arden.compiler.node.ATofEvokeTime;
+import arden.compiler.node.PEventAny;
+import arden.compiler.node.PEventList;
+import arden.compiler.node.PEventOr;
+import arden.compiler.node.PEvokeBlock;
+import arden.compiler.node.PEvokeStatement;
+import arden.runtime.ArdenTime;
+import arden.runtime.ArdenValue;
+import arden.runtime.ExecutionContext;
+import arden.runtime.events.AnyEvokeEvent;
+import arden.runtime.events.EmptyEvokeSlot;
+import arden.runtime.events.EvokeEvent;
+import arden.runtime.events.FixedDateEvokeEvent;
+
+public class EvokeCompiler extends VisitorBase {
+ private final CompilerContext context;
+
+ public EvokeCompiler(CompilerContext context) {
+ this.context = context;
+ }
+
+ public List listEvokeBlocks(PEvokeBlock first) {
+ /*
+ evoke_block =
+ {estmt} evoke_statement
+ | {eblk} evoke_block semicolon evoke_statement;
+ * */
+ final ArrayList result = new ArrayList();
+ first.apply(new VisitorBase() {
+ @Override
+ public void caseAEblkEvokeBlock(AEblkEvokeBlock evokeBlock) {
+ evokeBlock.getEvokeBlock().apply(this);
+ result.add(evokeBlock.getEvokeStatement());
+ }
+
+ @Override
+ public void caseAEstmtEvokeBlock(AEstmtEvokeBlock node) {
+ result.add(node.getEvokeStatement());
+ }
+ });
+ return result;
+ }
+
+ public List listAnyBlocks(PEventOr first) {
+ final ArrayList result = new ArrayList();
+ first.apply(new VisitorBase() {
+ @Override
+ public void caseAOrEventOr(AOrEventOr node) {
+ node.getEventOr().apply(this);
+ result.add(node.getEventAny());
+ }
+
+ @Override
+ public void caseAAnyEventOr(AAnyEventOr node) {
+ result.add(node.getEventAny());
+ }
+ });
+ return result;
+ }
+
+ public List listOrBlocks(PEventList first) {
+ final ArrayList result = new ArrayList();
+ first.apply(new VisitorBase() {
+ @Override
+ public void caseAElstEventList(AElstEventList node) {
+ node.getEventList().apply(this);
+ result.add(node.getEventOr());
+ }
+
+ @Override
+ public void caseAEorEventList(AEorEventList node) {
+ result.add(node.getEventOr());
+ }
+ });
+ return result;
+ }
+
+ @Override
+ public void caseAEvokeSlot(AEvokeSlot evokeSlot) {
+ List statements = listEvokeBlocks(evokeSlot.getEvokeBlock());
+ if (statements.size() > 1) {
+ throw new RuntimeCompilerException(evokeSlot.getEvoke(), "not implemented yet");
+ } else if (statements.size() == 1) {
+ statements.get(0).apply(this);
+ } else {
+ throw new RuntimeCompilerException(evokeSlot.getEvoke(), "no evoke event given");
+ }
+ }
+
+ @Override
+ public void caseAEmptyEvokeStatement(AEmptyEvokeStatement stmt) {
+ context.writer.newObject(EmptyEvokeSlot.class);
+ context.writer.dup();
+ try {
+ context.writer.invokeConstructor(EmptyEvokeSlot.class.getConstructor());
+ } catch (NoSuchMethodException e) {
+ throw new RuntimeException(e);
+ } catch (SecurityException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public void caseAEtimEvokeStatement(AEtimEvokeStatement node) {
+ node.getEvokeTime().apply(this);
+ }
+
+ public void createFixedDateEvokeEvent(long datetime) {
+ context.writer.newObject(FixedDateEvokeEvent.class);
+ context.writer.dup();
+
+ context.writer.loadStaticField(context.codeGenerator.getTimeLiteral(datetime));
+ try {
+ context.writer.invokeConstructor(FixedDateEvokeEvent.class.getConstructor(ArdenTime.class));
+ } catch (NoSuchMethodException e) {
+ throw new RuntimeException(e);
+ } catch (SecurityException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public void caseAIdateEvokeTime(AIdateEvokeTime node) {
+ createFixedDateEvokeEvent(ParseHelpers.parseIsoDate(node.getIsoDate()));
+ }
+
+ @Override
+ public void caseAIdtEvokeTime(AIdtEvokeTime node) {
+ createFixedDateEvokeEvent(ParseHelpers.parseIsoDateTime(node.getIsoDateTime()));
+ }
+
+ @Override
+ public void caseAEorEvokeStatement(AEorEvokeStatement stmt) {
+ stmt.getEventOr().apply(this);
+ }
+
+ @Override
+ public void caseAElstEventList(AElstEventList node) {
+ List orBlocks = listOrBlocks(node);
+
+ if (orBlocks.size() > 1) {
+ context.writer.newObject(AnyEvokeEvent.class);
+ context.writer.dup();
+ context.writer.loadIntegerConstant(orBlocks.size());
+ context.writer.newArray(EvokeEvent.class);
+ for (int i = 0; i < orBlocks.size(); i++) {
+ context.writer.dup();
+ context.writer.loadIntegerConstant(i);
+ orBlocks.get(i).apply(this);
+ context.writer.storeObjectToArray();
+ }
+ try {
+ context.writer.invokeConstructor(AnyEvokeEvent.class.getConstructor(EvokeEvent[].class));
+ } catch (NoSuchMethodException e) {
+ throw new RuntimeException(e);
+ } catch (SecurityException e) {
+ throw new RuntimeException(e);
+ }
+ } else if (orBlocks.size() == 1) {
+ orBlocks.get(0).apply(this);
+ } else {
+ throw new RuntimeCompilerException("error parsing event list");
+ }
+ }
+
+ @Override
+ public void caseAOrEventOr(AOrEventOr node) {
+ List anyBlocks = listAnyBlocks(node);
+
+ if (anyBlocks.size() > 1) {
+ context.writer.newObject(AnyEvokeEvent.class);
+ context.writer.dup();
+ context.writer.loadIntegerConstant(anyBlocks.size());
+ context.writer.newArray(EvokeEvent.class);
+ for (int i = 0; i < anyBlocks.size(); i++) {
+ context.writer.dup();
+ context.writer.loadIntegerConstant(i);
+ anyBlocks.get(i).apply(this);
+ context.writer.storeObjectToArray();
+ }
+ try {
+ context.writer.invokeConstructor(AnyEvokeEvent.class.getConstructor(EvokeEvent[].class));
+ } catch (NoSuchMethodException e) {
+ throw new RuntimeException(e);
+ } catch (SecurityException e) {
+ throw new RuntimeException(e);
+ }
+ } else if (anyBlocks.size() == 1) {
+ anyBlocks.get(0).apply(this);
+ } else {
+ throw new RuntimeCompilerException(node.getOr(), "error parsing ");
+ }
+
+ }
+
+ @Override
+ public void caseAAnyEventOr(AAnyEventOr anyevent) {
+ anyevent.getEventAny().apply(this);
+ }
+
+ @Override
+ public void caseAAolstEventAny(AAolstEventAny node) {
+ node.getEventList().apply(this);
+ }
+
+ @Override
+ public void caseAEfctEventAny(AEfctEventAny factor) {
+ factor.getEventFactor().apply(this);
+ }
+
+ @Override
+ public void caseAIdEventFactor(AIdEventFactor id) {
+ String name = id.getIdentifier().getText();
+ Variable var = context.codeGenerator.getVariable(name);
+ if (var == null)
+ throw new RuntimeCompilerException(id.getIdentifier(), "Unknown event variable identifier: \"" + name + "\"");
+ if (!(var instanceof EventVariable)) {
+ throw new RuntimeCompilerException(id.getIdentifier(), "This is not an event variable: \"" + name + "\"");
+ }
+ var.loadValue(context, id.getIdentifier());
+ }
+
+ @Override
+ public void caseAEcycEvokeStatement(AEcycEvokeStatement stmt) {
+ stmt.getQualifiedEvokeCycle().apply(this);
+ }
+
+ @Override
+ public void caseASimpQualifiedEvokeCycle(ASimpQualifiedEvokeCycle node) {
+ node.getSimpleEvokeCycle().apply(this);
+ }
+
+ /** leaves EvokeEvent on stack */
+ @Override
+ public void caseASuntQualifiedEvokeCycle(ASuntQualifiedEvokeCycle qualifiedcycle) {
+ qualifiedcycle.getSimpleEvokeCycle().apply(this);
+ qualifiedcycle.getExpr().apply(new ExpressionCompiler(context));
+ context.writer.invokeStatic(ExpressionCompiler.getMethod("until", EvokeEvent.class, ArdenValue.class));
+ }
+
+ /** leaves EvokeEvent on stack */
+ @Override
+ public void caseASimpleEvokeCycle(ASimpleEvokeCycle simplecycle) {
+ simplecycle.getDurL().apply(this); // interval
+ simplecycle.getDurR().apply(this); // for
+ simplecycle.getEvokeTime().apply(this); // starting
+ context.writer.loadVariable(context.executionContextVariable);
+ context.writer.invokeStatic(ExpressionCompiler.getMethod("createEvokeCycle", ArdenValue.class, ArdenValue.class, EvokeEvent.class, ExecutionContext.class));
+ }
+
+ /** leaves ArdenDuration on stack */
+ @Override
+ public void caseAEvokeDuration(AEvokeDuration duration) {
+ double durValue = ParseHelpers.getLiteralDoubleValue(duration.getNumberLiteral());
+ context.writer.loadStaticField(context.codeGenerator.getNumberLiteral(durValue));
+ new ExpressionCompiler(context).compileDurationOp(duration.getDurationOp());
+ context.writer.invokeStatic(ExpressionCompiler.getMethod("createDuration", ArdenValue.class, double.class, boolean.class));
+ }
+
+ /** leaves EvokeEvent on stack */
+ @Override
+ public void caseAEdurEvokeTime(AEdurEvokeTime duration) {
+ duration.getEvokeDuration().apply(this);
+ duration.getEvokeTime().apply(this);
+ context.writer.invokeStatic(ExpressionCompiler.getMethod("after", ArdenValue.class, EvokeEvent.class));
+ }
+
+ /** takes and leaves EvokeEvent on the stack */
+ @Override
+ public void caseATofEvokeTime(ATofEvokeTime node) {
+ node.getEventAny().apply(this);
+ context.writer.loadVariable(context.executionContextVariable);
+ context.writer.invokeStatic(ExpressionCompiler.getMethod("timeOf", EvokeEvent.class, ExecutionContext.class));
+ }
+
+ @Override
+ public void caseACallEvokeStatement(ACallEvokeStatement node) {
+ context.writer.invokeStatic(ExpressionCompiler.getMethod("evokeSlotCall"));
+ }
+}
diff --git a/src/arden/compiler/ExecutionContextMethods.java b/src/arden/compiler/ExecutionContextMethods.java
index 38067bf..c521872 100644
--- a/src/arden/compiler/ExecutionContextMethods.java
+++ b/src/arden/compiler/ExecutionContextMethods.java
@@ -40,6 +40,7 @@ final class ExecutionContextMethods {
public static final Method findModule, findInterface;
public static final Method callWithDelay;
public static final Method getEventTime, getTriggerTime, getCurrentTime;
+ public static final Method getEvent;
static {
try {
@@ -53,6 +54,7 @@ final class ExecutionContextMethods {
getEventTime = ExecutionContext.class.getMethod("getEventTime");
getTriggerTime = ExecutionContext.class.getMethod("getTriggerTime");
getCurrentTime = ExecutionContext.class.getMethod("getCurrentTime");
+ getEvent = ExecutionContext.class.getMethod("getEvent", String.class);
} catch (SecurityException e) {
throw new RuntimeException(e);
} catch (NoSuchMethodException e) {
diff --git a/src/arden/compiler/ExpressionCompiler.java b/src/arden/compiler/ExpressionCompiler.java
index 7d8c7b5..59042c6 100644
--- a/src/arden/compiler/ExpressionCompiler.java
+++ b/src/arden/compiler/ExpressionCompiler.java
@@ -660,9 +660,14 @@ public void caseAAgoExprAgo(AAgoExprAgo node) {
@Override
public void caseAExprDuration(AExprDuration node) {
node.getExprFunction().apply(this);
+ PDurationOp durOp = node.getDurationOp();
+ compileDurationOp(durOp);
+ context.writer.invokeStatic(getMethod("createDuration", ArdenValue.class, double.class, boolean.class));
+ }
+
+ public void compileDurationOp(Node durOp) {
boolean isMonths;
double multiplier;
- PDurationOp durOp = node.getDurationOp();
if (durOp instanceof ADayDurationOp || durOp instanceof ADaysDurationOp) {
isMonths = false;
multiplier = 86400;
@@ -689,9 +694,8 @@ public void caseAExprDuration(AExprDuration node) {
}
context.writer.loadDoubleConstant(multiplier);
context.writer.loadIntegerConstant(isMonths ? 1 : 0);
- context.writer.invokeStatic(getMethod("createDuration", ArdenValue.class, double.class, boolean.class));
}
-
+
// expr_function =
// {expr} expr_factor
// | {ofexpr} of_func_op expr_function
diff --git a/src/arden/compiler/LeftHandSideAnalyzer.java b/src/arden/compiler/LeftHandSideAnalyzer.java
index 1640e27..a84d6a4 100644
--- a/src/arden/compiler/LeftHandSideAnalyzer.java
+++ b/src/arden/compiler/LeftHandSideAnalyzer.java
@@ -63,7 +63,7 @@ public static LeftHandSideResult analyze(Switchable node) {
// identifier_becomes =
// {id} identifier_or_object_ref assign
- // | {let} let identifier be
+ // | {let} let identifier_or_object_ref be
// | {now} now assign;
@Override
public void caseAIdIdentifierBecomes(AIdIdentifierBecomes node) {
@@ -72,7 +72,7 @@ public void caseAIdIdentifierBecomes(AIdIdentifierBecomes node) {
@Override
public void caseALetIdentifierBecomes(ALetIdentifierBecomes node) {
- result = new LeftHandSideIdentifier(node.getIdentifier());
+ node.getIdentifierOrObjectRef().apply(this);
}
@Override
diff --git a/src/arden/compiler/MetadataCompiler.java b/src/arden/compiler/MetadataCompiler.java
index ae9a7e3..e55b89d 100644
--- a/src/arden/compiler/MetadataCompiler.java
+++ b/src/arden/compiler/MetadataCompiler.java
@@ -33,6 +33,7 @@
import arden.compiler.node.*;
import arden.runtime.LibraryMetadata;
import arden.runtime.MaintenanceMetadata;
+import arden.runtime.RuntimeHelpers;
/**
* Collects metadata from the source tree.
@@ -43,7 +44,7 @@
final class MetadataCompiler extends DepthFirstAdapter {
final MaintenanceMetadata maintenance = new MaintenanceMetadata();
final LibraryMetadata library = new LibraryMetadata();
- double priority = 50;
+ double priority = RuntimeHelpers.DEFAULT_PRIORITY;
private boolean usedFileNameForMlmName;
// maintenance_body =
diff --git a/src/arden/configuration/ApplicationConfiguration.java b/src/arden/configuration/ApplicationConfiguration.java
new file mode 100644
index 0000000..9660a41
--- /dev/null
+++ b/src/arden/configuration/ApplicationConfiguration.java
@@ -0,0 +1,100 @@
+package arden.configuration;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Properties;
+
+public class ApplicationConfiguration {
+ private static ApplicationConfiguration INSTANCE = null;
+
+ public static ApplicationConfiguration getInstance() {
+ if (INSTANCE == null) {
+ INSTANCE = new ApplicationConfiguration();
+ }
+ return INSTANCE;
+ }
+
+ private Properties config = null;
+ private final static String DEFAULT_COMMENT = "Arden2ByteCode config file";
+ private final static File CONFIGDIR = new File(System.getProperty("user.home") + File.separator + ".arden2bytecode");
+ private final static File CONFIGFILE = new File(System.getProperty("user.home") + File.separator + ".arden2bytecode" + File.separator + "config");
+
+ private ApplicationConfiguration() {
+ config = new Properties();
+
+ tryCreatingConfigFile();
+ if (!tryLoadingConfigFile()) {
+ tryLoadingConfigResource();
+ }
+ }
+
+ private void tryCreatingConfigFile() {
+ InputStream configResource = this.getClass().getClassLoader().getResourceAsStream(
+ "arden2bytecode.config");
+
+ // copy config resource to config file
+ if (CONFIGFILE.exists() == false && configResource != null) {
+ Properties configResProperties = new Properties();
+ try {
+ CONFIGDIR.mkdirs();
+ configResProperties.load(configResource);
+ configResProperties.store(new FileWriter(CONFIGFILE),
+ DEFAULT_COMMENT);
+ } catch (IOException e) {
+ }
+ }
+ }
+
+ private boolean tryLoadingConfigFile() {
+ // try to load config priorizing a config file before a resource
+ boolean configLoaded = false;
+ if (CONFIGFILE.exists()) {
+ try {
+ config.load(new FileReader(CONFIGFILE));
+ configLoaded = true;
+ } catch (FileNotFoundException e) {
+ } catch (IOException e) {
+ }
+ }
+ return configLoaded;
+ }
+
+ private void tryLoadingConfigResource() {
+ InputStream configResource = this.getClass().getClassLoader().getResourceAsStream(
+ "arden2bytecode.config");
+ if (configResource != null) {
+ try {
+ config.load(configResource);
+ } catch (IOException e) {
+ System.err.println("error: Could not load configuration from resource.");
+ }
+ }
+ }
+
+ public void finalize() {
+ try {
+ config.store(new FileWriter(CONFIGFILE), DEFAULT_COMMENT);
+ } catch (IOException e) {
+ }
+ }
+
+ public static String get(String key) {
+ return getInstance().getValue(key);
+ }
+
+ public static void set(String key, String value) {
+ getInstance().setValue(key, value);
+ }
+
+ public String getValue(String key) {
+ return config.getProperty(key);
+ }
+
+ public void setValue(String key, String value) {
+ config.setProperty(key, value);
+ }
+}
diff --git a/src/arden/constants/ConstantParser.java b/src/arden/constants/ConstantParser.java
new file mode 100644
index 0000000..750aaeb
--- /dev/null
+++ b/src/arden/constants/ConstantParser.java
@@ -0,0 +1,228 @@
+package arden.constants;
+
+import java.io.IOException;
+import java.io.PushbackReader;
+import java.io.StringReader;
+import java.util.Deque;
+import java.util.LinkedList;
+
+import arden.constants.analysis.DepthFirstAdapter;
+import arden.constants.lexer.Lexer;
+import arden.constants.lexer.LexerException;
+import arden.constants.node.AFalseArdenBoolean;
+import arden.constants.node.AListExpr;
+import arden.constants.node.AListatomExpr;
+import arden.constants.node.ANullAtom;
+import arden.constants.node.ANumberAtom;
+import arden.constants.node.AParAtom;
+import arden.constants.node.AStringAtom;
+import arden.constants.node.ATrueArdenBoolean;
+import arden.constants.node.Start;
+import arden.constants.node.TArdenString;
+import arden.constants.node.Token;
+import arden.constants.parser.Parser;
+import arden.constants.parser.ParserException;
+import arden.runtime.ArdenBoolean;
+import arden.runtime.ArdenList;
+import arden.runtime.ArdenNull;
+import arden.runtime.ArdenNumber;
+import arden.runtime.ArdenString;
+import arden.runtime.ArdenValue;
+import arden.runtime.ExpressionHelpers;
+
+public class ConstantParser {
+
+ public class ConstantParserException extends Exception {
+ private static final long serialVersionUID = 1L;
+ int line;
+ int pos;
+
+ public ConstantParserException(ParserException e) {
+ super(e);
+ if (e.getToken() != null) {
+ line = e.getToken().getLine();
+ pos = e.getToken().getPos();
+ } else {
+ line = pos = -1;
+ }
+ }
+
+ public ConstantParserException(LexerException e) {
+ super(e);
+ line = pos = -1;
+ }
+
+ public ConstantParserException(IOException e) {
+ super(e);
+ line = pos = -1;
+ }
+
+ public ConstantParserException(String message) {
+ super(message);
+ line = pos = -1;
+ }
+
+ public ConstantParserException(Token token, String message) {
+ super(message);
+ line = token.getLine();
+ pos = token.getPos();
+ }
+
+ public int getLine() {
+ return line;
+ }
+
+ public int getPos() {
+ return pos;
+ }
+ }
+
+ public ConstantParser() {
+ }
+
+ private class AstVisitor extends DepthFirstAdapter {
+ Deque stack;
+ ArdenValue result;
+ long primaryTime;
+
+ private boolean isWhitespace(char c) {
+ return c == ' ' || c == '\t' || c == '\n' || c == '\r';
+ }
+
+ public String parseString(TArdenString literal) throws ConstantParserException {
+ String input = literal.getText();
+ if (input.length() < 2 || input.charAt(0) != '"' || input.charAt(input.length() - 1) != '"')
+ throw new ConstantParserException(literal, "Invalid string literal");
+ StringBuilder output = new StringBuilder();
+ for (int i = 1; i < input.length() - 1; i++) {
+ char c = input.charAt(i);
+ if (c == '\r' || c == '\n') {
+ // (see spec for special rules in this case)
+ while (output.length() > 0 && isWhitespace(output.charAt(output.length() - 1)))
+ output.deleteCharAt(output.length() - 1);
+ int numLineFeed = 0;
+ while (isWhitespace(c)) {
+ if (c == '\n')
+ numLineFeed++;
+ c = input.charAt(++i);
+ }
+ if (numLineFeed > 1)
+ output.append('\n');
+ else
+ output.append(' ');
+ }
+ if (c == '"') {
+ i += 1;
+ if (input.charAt(i) != '"')
+ throw new ConstantParserException(literal, "Invalid string literal");
+ }
+ output.append(c);
+ }
+ return output.toString();
+ }
+
+ public AstVisitor() {
+ stack = new LinkedList();
+ primaryTime = System.currentTimeMillis();
+ result = null;
+ }
+
+ @Override
+ public void caseATrueArdenBoolean(ATrueArdenBoolean node) {
+ stack.push(ArdenBoolean.create(true, primaryTime));
+ }
+
+ @Override
+ public void caseAFalseArdenBoolean(AFalseArdenBoolean node) {
+ stack.push(ArdenBoolean.create(false, primaryTime));
+ }
+
+ @Override
+ public void caseAStringAtom(AStringAtom node) {
+ TArdenString string = node.getArdenString();
+ try {
+ stack.push(new ArdenString(parseString(string), primaryTime));
+ } catch (ConstantParserException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public void caseANumberAtom(ANumberAtom node) {
+ String numStr = node.getArdenNumber().getText();
+ double d = Double.NaN;
+ try {
+ d = Double.parseDouble(numStr);
+ } catch (NumberFormatException e) {
+ throw new RuntimeException("Not a valid number at pos: " + node.getArdenNumber().getPos());
+ }
+ if (Double.isInfinite(d) || Double.isNaN(d)) {
+ throw new RuntimeException("Not a valid number at pos: " + node.getArdenNumber().getPos());
+ }
+ stack.push(ArdenNumber.create(d, primaryTime));
+ }
+
+ @Override
+ public void caseANullAtom(ANullAtom node) {
+ stack.push(ArdenNull.create(primaryTime));
+ }
+
+ @Override
+ public void caseAListatomExpr(AListatomExpr node) {
+ node.getAtom().apply(this);
+ stack.push(ExpressionHelpers.unaryComma(stack.pop()));
+ }
+
+ @Override
+ public void caseAListExpr(AListExpr node) {
+ node.getExpr().apply(this);
+ node.getAtom().apply(this);
+ ArdenValue atomValue = stack.pop();
+ stack.push(ExpressionHelpers.binaryComma(stack.pop(), atomValue));
+ }
+
+ @Override
+ public void caseAParAtom(AParAtom node) {
+ stack.push(ArdenList.EMPTY);
+ }
+
+ @Override
+ public void outStart(Start node) {
+ if (stack.size() != 1) {
+ throw new RuntimeException("Input is malformed in terms of parentheses.");
+ }
+ result = stack.getFirst();
+ }
+
+ public ArdenValue getResult() {
+ return result;
+ }
+ }
+
+ public static ArdenValue parse(String input) throws ConstantParserException {
+ return new ConstantParser().doParse(input);
+ }
+
+ public ArdenValue doParse(String input) throws ConstantParserException {
+ if (input == null) {
+ return ArdenNull.create(System.currentTimeMillis());
+ }
+ StringReader reader = new StringReader(input);
+
+ Lexer lexer = new Lexer(new PushbackReader(reader, 256));
+ Parser parser = new Parser(lexer);
+ Start syntaxTree;
+ try {
+ syntaxTree = parser.parse();
+ } catch (ParserException e) {
+ throw new ConstantParserException(e);
+ } catch (LexerException e) {
+ throw new ConstantParserException(e);
+ } catch (IOException e) {
+ throw new ConstantParserException(e);
+ }
+ AstVisitor visitor = new AstVisitor();
+ syntaxTree.apply(visitor);
+ return visitor.getResult();
+ }
+}
diff --git a/src/arden/runtime/ArdenString.java b/src/arden/runtime/ArdenString.java
index 7c2b956..9ca58e5 100644
--- a/src/arden/runtime/ArdenString.java
+++ b/src/arden/runtime/ArdenString.java
@@ -39,6 +39,14 @@ public ArdenString(String value, long primaryTime) {
this.value = value;
}
+ public static String getStringFromValue(ArdenValue ardenValue) {
+ if (ardenValue instanceof ArdenString) {
+ return ((ArdenString)ardenValue).value;
+ } else {
+ return null;
+ }
+ }
+
@Override
public ArdenValue setTime(long newPrimaryTime) {
return new ArdenString(value, newPrimaryTime);
@@ -76,4 +84,5 @@ public int compareTo(ArdenValue rhs) {
return Integer.MIN_VALUE;
}
}
+
}
diff --git a/src/arden/runtime/ArdenTime.java b/src/arden/runtime/ArdenTime.java
index 00b5719..b80fa9c 100644
--- a/src/arden/runtime/ArdenTime.java
+++ b/src/arden/runtime/ArdenTime.java
@@ -29,6 +29,7 @@
import java.text.DateFormat;
import java.text.SimpleDateFormat;
+import java.util.Comparator;
import java.util.Date;
import java.util.GregorianCalendar;
@@ -99,7 +100,7 @@ private long addMonths(double months) {
return c.getTimeInMillis() + (long) ((months - wholeMonths) * 1000 * ArdenDuration.SECONDS_PER_MONTH);
}
- long add(ArdenDuration dur) {
+ public long add(ArdenDuration dur) {
if (dur.isMonths) {
return addMonths(dur.value);
} else {
@@ -108,7 +109,7 @@ long add(ArdenDuration dur) {
}
}
- long subtract(ArdenDuration dur) {
+ public long subtract(ArdenDuration dur) {
if (dur.isMonths) {
return addMonths(-dur.value);
} else {
@@ -116,4 +117,19 @@ long subtract(ArdenDuration dur) {
return this.value - milliseconds;
}
}
+
+ public static class NaturalComparator implements Comparator {
+ @Override
+ public int compare(ArdenTime arg0, ArdenTime arg1) {
+ if (arg0 == null) {
+ if (arg1 == null) {
+ return 0;
+ }
+ return 1;
+ } else if (arg1 == null) {
+ return -1;
+ }
+ return new Long(arg0.value).compareTo(new Long(arg1.value));
+ }
+ }
}
diff --git a/src/arden/runtime/BaseExecutionContext.java b/src/arden/runtime/BaseExecutionContext.java
new file mode 100644
index 0000000..0f1d6fe
--- /dev/null
+++ b/src/arden/runtime/BaseExecutionContext.java
@@ -0,0 +1,86 @@
+package arden.runtime;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.UnsupportedEncodingException;
+import java.lang.reflect.InvocationTargetException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import arden.MainClass;
+import arden.compiler.Compiler;
+import arden.compiler.CompilerException;
+import arden.compiler.CompiledMlm;
+
+public class BaseExecutionContext extends ExecutionContext {
+ List mlmSearchPath;
+ Map moduleList;
+
+ public BaseExecutionContext(URL[] mlmSearchPath) {
+ setURLs(mlmSearchPath);
+ moduleList = new HashMap();
+ }
+
+ public void addURL(URL url) {
+ mlmSearchPath.add(url);
+ }
+
+ public void setURLs(URL[] urls) {
+ mlmSearchPath = new LinkedList();
+ if (urls != null) {
+ mlmSearchPath.addAll(Arrays.asList(urls));
+ }
+ }
+
+ @Override
+ public void callWithDelay(ArdenRunnable mlm, ArdenValue[] arguments, ArdenValue delay) {
+ System.out.println("delay: " + delay.toString());
+ try {
+ mlm.run(this, arguments);
+ } catch (InvocationTargetException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public ArdenRunnable findModule(String name, String institution) {
+ if (!name.matches("[a-zA-Z0-9\\-_]+")) {
+ throw new RuntimeException("Malformed module name: " + name);
+ }
+ ArdenRunnable fromlist = moduleList.get(name.toLowerCase());
+ if (fromlist != null) {
+ return fromlist;
+ }
+ ClassLoader loader = new URLClassLoader(mlmSearchPath.toArray(new URL[]{}));
+ InputStream in = loader.getResourceAsStream(name + ".class");
+ if (in != null) {
+ try {
+ ArdenRunnable module = new CompiledMlm(in, name);
+ moduleList.put(name.toLowerCase(), module);
+ return module;
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ in = loader.getResourceAsStream(name + MainClass.MLM_FILE_EXTENSION);
+ Compiler compiler = new Compiler();
+ MedicalLogicModule mlm = null;
+ try {
+ mlm = compiler.compile(new InputStreamReader(in, "UTF-8")).get(0);
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException(e);
+ } catch (CompilerException e) {
+ throw new RuntimeException(e);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ moduleList.put(name.toLowerCase(), mlm);
+ return mlm;
+ }
+}
diff --git a/src/arden/runtime/ExecutionContext.java b/src/arden/runtime/ExecutionContext.java
index 74d24de..f5706d0 100644
--- a/src/arden/runtime/ExecutionContext.java
+++ b/src/arden/runtime/ExecutionContext.java
@@ -29,13 +29,16 @@
import java.util.Date;
+import arden.runtime.events.EvokeEvent;
+import arden.runtime.events.MappedEvokeEvent;
+
/**
* Describes the environment in which a Medical Logic Module is executed.
*
* @author Daniel Grunwald
*
*/
-public class ExecutionContext {
+public abstract class ExecutionContext {
/**
* Creates a database query using a mapping clause. The DatabaseQuery object
* can be used to limit the number of results produced.
@@ -58,6 +61,11 @@ public DatabaseQuery createQuery(String mapping) {
public ArdenValue getMessage(String mapping) {
return new ArdenString(mapping);
}
+
+ /** Gets an event defined with the EVENT{mapping} statement */
+ public EvokeEvent getEvent(String mapping) {
+ return new MappedEvokeEvent(mapping);
+ }
/**
* Called by write statements.
diff --git a/src/arden/runtime/ExpressionHelpers.java b/src/arden/runtime/ExpressionHelpers.java
index 8d5c544..107ebea 100644
--- a/src/arden/runtime/ExpressionHelpers.java
+++ b/src/arden/runtime/ExpressionHelpers.java
@@ -35,6 +35,12 @@
import java.util.HashMap;
import java.util.regex.Pattern;
+import arden.runtime.events.AfterEvokeEvent;
+import arden.runtime.events.CyclicEvokeEvent;
+import arden.runtime.events.EvokeEvent;
+import arden.runtime.events.NeverEvokeEvent;
+import arden.runtime.events.UntilEvokeEvent;
+
/**
* Static helper methods for ExpressionCompiler (mostly operators with special
* list handling).
@@ -42,6 +48,15 @@
* @author Daniel Grunwald
*/
public final class ExpressionHelpers {
+ /** helper function */
+ public static String getClassName(Object o) {
+ if (o == null) {
+ return "null";
+ }
+ return o.getClass().getSimpleName();
+ }
+
+
/** implements the ",x" operator */
public static ArdenList unaryComma(ArdenValue value) {
if (value instanceof ArdenList)
@@ -666,7 +681,22 @@ public static ArdenValue all(ArdenValue sequence) {
else
return ArdenNull.create(primaryTime);
}
-
+
+ /** implements the AFTER duration operator */
+ public static EvokeEvent after(ArdenValue duration, EvokeEvent event) {
+ if (duration instanceof ArdenDuration) {
+ long primaryTime = getCommonTime(new ArdenValue[]{duration, event});
+ return new AfterEvokeEvent((ArdenDuration) duration, event, primaryTime);
+ }
+ throw new RuntimeException("AFTER operator not implemented for "
+ + getClassName(duration)
+ + " AFTER " + getClassName(event));
+ }
+
+ public static EvokeEvent timeOf(EvokeEvent event, ExecutionContext context) {
+ return event;
+ }
+
public static ArdenValue createDuration(ArdenValue val, double multiplier, boolean isMonths) {
if (val instanceof ArdenList) {
ArdenValue[] inputs = ((ArdenList) val).values;
@@ -680,7 +710,36 @@ public static ArdenValue createDuration(ArdenValue val, double multiplier, boole
return ArdenNull.create(val.primaryTime);
}
}
+
+ public static EvokeEvent createEvokeCycle(ArdenValue interval, ArdenValue length, EvokeEvent start, ExecutionContext context) {
+ if (interval instanceof ArdenDuration && length instanceof ArdenDuration) {
+ ArdenTime starting = start.getNextRunTime(context);
+ if (starting != null) {
+ return new CyclicEvokeEvent((ArdenDuration) interval, (ArdenDuration) length, starting);
+ } else {
+ return new NeverEvokeEvent();
+ }
+ }
+ throw new RuntimeException("cannot create evoke cycle with these types: " +
+ getClassName(interval) + ", " +
+ getClassName(length) + ", " +
+ getClassName(start));
+ }
+ public static EvokeEvent until(EvokeEvent simpleEvokeCycle, ArdenValue untilExpr) {
+ if (untilExpr instanceof ArdenTime) {
+ return new UntilEvokeEvent(simpleEvokeCycle, (ArdenTime) untilExpr);
+ } else if (untilExpr instanceof ArdenNull) {
+ return simpleEvokeCycle;
+ }
+ throw new RuntimeException("cannot create until event for type " + getClassName(untilExpr) + " after the 'until'");
+ }
+
+ /** returns the EvokeEvent when 'call' is stated in the evoke slot */
+ public static EvokeEvent evokeSlotCall() {
+ return new NeverEvokeEvent();
+ }
+
public static ArdenValue extractTimeComponent(ArdenValue time, int component) {
if (time instanceof ArdenList) {
ArdenValue[] inputs = ((ArdenList) time).values;
diff --git a/src/arden/runtime/LibraryMetadata.java b/src/arden/runtime/LibraryMetadata.java
index ed418fa..9815e82 100644
--- a/src/arden/runtime/LibraryMetadata.java
+++ b/src/arden/runtime/LibraryMetadata.java
@@ -28,6 +28,7 @@
package arden.runtime;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
public class LibraryMetadata {
@@ -36,6 +37,19 @@ public class LibraryMetadata {
private final ArrayList keywords = new ArrayList();
private String citations;
private String links;
+
+ public LibraryMetadata() {
+
+ }
+
+ public LibraryMetadata(String purpose, String explanation, String[] keywords, String citations, String links) {
+ super();
+ this.purpose = purpose;
+ this.explanation = explanation;
+ this.citations = citations;
+ this.links = links;
+ this.keywords.addAll(Arrays.asList(keywords));
+ }
public void setPurpose(String purpose) {
this.purpose = purpose;
diff --git a/src/arden/runtime/MaintenanceMetadata.java b/src/arden/runtime/MaintenanceMetadata.java
index 57356d6..6645c5a 100644
--- a/src/arden/runtime/MaintenanceMetadata.java
+++ b/src/arden/runtime/MaintenanceMetadata.java
@@ -39,6 +39,24 @@ public class MaintenanceMetadata {
private String specialist;
private Date date;
private String validation;
+
+ public MaintenanceMetadata() {
+
+ }
+
+ public MaintenanceMetadata(String title, String mlmName, String ardenVersion, String version, String institution,
+ String author, String specialist, Date date, String validation) {
+ super();
+ this.title = title;
+ this.mlmName = mlmName;
+ this.ardenVersion = ardenVersion;
+ this.version = version;
+ this.institution = institution;
+ this.author = author;
+ this.specialist = specialist;
+ this.date = date;
+ this.validation = validation;
+ }
public void setTitle(String title) {
this.title = title;
diff --git a/src/arden/runtime/MedicalLogicModule.java b/src/arden/runtime/MedicalLogicModule.java
index 2dd9dbb..913d779 100644
--- a/src/arden/runtime/MedicalLogicModule.java
+++ b/src/arden/runtime/MedicalLogicModule.java
@@ -29,6 +29,9 @@
import java.lang.reflect.InvocationTargetException;
+import arden.runtime.events.EvokeEvent;
+
+
/**
* Represents a compiled medical logic module.
*
@@ -50,4 +53,18 @@ MedicalLogicModuleImplementation createInstance(ExecutionContext context, ArdenV
/** Gets the priority of this module. */
double getPriority();
+
+ /** Gets the urgency value of this module. */
+ double getUrgency();
+
+ /** Gets an evoke event telling when to run this MLM
+ * @throws InvocationTargetException */
+ EvokeEvent getEvoke(ExecutionContext context, ArdenValue[] arguments) throws InvocationTargetException;
+
+ /**
+ * Gets the value of a variable declared in a Medical Logic Module
+ * @param name Name of the value in the MLM
+ * @return the variable value or null if the MLM has not been run yet or the value does not exist, or ArdenNull if the variable is not yet initialized
+ */
+ ArdenValue getValue(String name);
}
diff --git a/src/arden/runtime/MedicalLogicModuleImplementation.java b/src/arden/runtime/MedicalLogicModuleImplementation.java
index 6194157..aeeab00 100644
--- a/src/arden/runtime/MedicalLogicModuleImplementation.java
+++ b/src/arden/runtime/MedicalLogicModuleImplementation.java
@@ -27,6 +27,9 @@
package arden.runtime;
+import arden.runtime.events.EvokeEvent;
+import arden.runtime.events.UndefinedEvokeEvent;
+
/**
* Base class for compiled logic etc. The compiler creates derived classes. An
* instance of the derived class will be created whenever the MLM is executed.
@@ -54,4 +57,39 @@ public abstract class MedicalLogicModuleImplementation {
public double getUrgency() {
return RuntimeHelpers.DEFAULT_URGENCY;
}
+
+ /** Gets the maintenance metadata
+ * (not declared abstract to stay downwards compatible with existing MLMs) */
+ public MaintenanceMetadata getMaintenanceMetadata() {
+ return null;
+ }
+
+ /**
+ * Gets the library metadata
+ */
+ public LibraryMetadata getLibraryMetadata() {
+ return null;
+ }
+
+ /**
+ * Gets the priority
+ */
+ public double getPriority() {
+ return RuntimeHelpers.DEFAULT_PRIORITY;
+ }
+
+ /**
+ * Gets the event when this MLM should be invoked
+ */
+ public EvokeEvent getEvokeEvent(ExecutionContext context) {
+ return new UndefinedEvokeEvent();
+ }
+
+ /**
+ * Gets a Variable that is declared in the Medical Logic Module.
+ * This method should be overridden by the MLMs ByteCode.
+ */
+ public ArdenValue getValue(String name) {
+ return ArdenNull.INSTANCE;
+ }
}
diff --git a/src/arden/runtime/RuntimeHelpers.java b/src/arden/runtime/RuntimeHelpers.java
index d72e60a..4fdebfa 100644
--- a/src/arden/runtime/RuntimeHelpers.java
+++ b/src/arden/runtime/RuntimeHelpers.java
@@ -34,6 +34,7 @@
import java.util.Date;
import java.util.GregorianCalendar;
+
/**
* Static helper methods.
*
@@ -55,8 +56,10 @@ public static ArdenValue[] call(ArdenRunnable mlm, ExecutionContext context, Ard
throw new RuntimeException(e);
}
}
-
+
public static final double DEFAULT_URGENCY = 50;
+
+ public static final double DEFAULT_PRIORITY = 50;
public static double urgencyGetPrimitiveValue(ArdenValue val) {
if (val instanceof ArdenNumber)
diff --git a/src/arden/runtime/StdIOExecutionContext.java b/src/arden/runtime/StdIOExecutionContext.java
new file mode 100644
index 0000000..b68faf2
--- /dev/null
+++ b/src/arden/runtime/StdIOExecutionContext.java
@@ -0,0 +1,96 @@
+package arden.runtime;
+
+import java.io.File;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Date;
+import java.util.Scanner;
+
+import arden.CommandLineOptions;
+import arden.constants.ConstantParser;
+import arden.constants.ConstantParser.ConstantParserException;
+
+public class StdIOExecutionContext extends BaseExecutionContext {
+ @SuppressWarnings("unused")
+ private CommandLineOptions options;
+
+ public StdIOExecutionContext(CommandLineOptions options) {
+ super(new URL[]{});
+ this.options = options;
+ try {
+ addURL(new File(".").toURI().toURL());
+ if (options.isClasspath()) {
+ String[] paths = options.getClasspath().split(File.pathSeparator);
+ for (String path : paths) {
+ File f = new File(path);
+ URL url = null;
+ url = f.toURI().toURL();
+ addURL(url);
+ }
+ }
+ } catch (MalformedURLException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public DatabaseQuery createQuery(String mapping) {
+ System.out.println("Query mapping: \"" + mapping + "\". Enter result as " +
+ "constant Arden Syntax expression (Strings in quotes)");
+ System.out.print(" >");
+ Scanner sc = new Scanner(System.in);
+ String line = null;
+ if (sc.hasNext()) {
+ line = sc.nextLine();
+ }
+ ArdenValue[] val = null;
+ try {
+ val = new ArdenValue[] {
+ ConstantParser.parse(line)
+ };
+ } catch (ConstantParserException e) {
+ System.out.println("Error parsing at char: " + e.getPos());
+ System.out.println("Message: " + e.getMessage());
+ }
+ return new MemoryQuery(val);
+ }
+
+ public ArdenValue getMessage(String mapping) {
+ System.out.println("Message, mapping: " + mapping);
+ return new ArdenString(mapping);
+ }
+
+ public void write(ArdenValue message, String destination) {
+ if ("stdout".equalsIgnoreCase(destination)) {
+ // just print string
+ if (message instanceof ArdenString) {
+ System.out.println(ArdenString.getStringFromValue(message));
+ } else {
+ System.out.println(message);
+ }
+ } else {
+ // prepend destination to printed string
+ System.out.print("Destination: \"");
+ System.out.print(destination);
+ System.out.print("\" Message: ");
+ if (message instanceof ArdenString) {
+ System.out.println(ArdenString.getStringFromValue(message));
+ } else {
+ System.out.println(message);
+ }
+ }
+ }
+
+ private ArdenTime eventtime = new ArdenTime(new Date());
+
+ public ArdenTime getEventTime() {
+ return eventtime;
+ }
+
+ public ArdenTime getTriggerTime() {
+ return eventtime;
+ }
+
+ public ArdenTime getCurrentTime() {
+ return new ArdenTime(new Date());
+ }
+}
diff --git a/src/arden/runtime/events/AfterEvokeEvent.java b/src/arden/runtime/events/AfterEvokeEvent.java
new file mode 100644
index 0000000..5f274f8
--- /dev/null
+++ b/src/arden/runtime/events/AfterEvokeEvent.java
@@ -0,0 +1,67 @@
+package arden.runtime.events;
+
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+import arden.runtime.ArdenDuration;
+import arden.runtime.ArdenTime;
+import arden.runtime.ArdenValue;
+import arden.runtime.ExecutionContext;
+
+public class AfterEvokeEvent extends EvokeEvent {
+
+ EvokeEvent target;
+ ArdenDuration duration;
+ SortedSet additionalSchedules;
+
+ public AfterEvokeEvent(ArdenDuration duration, EvokeEvent target, long primaryTime) {
+ super(primaryTime);
+ this.duration = duration;
+ this.target = target;
+ this.additionalSchedules = new TreeSet(new ArdenTime.NaturalComparator());
+ }
+
+ public AfterEvokeEvent(ArdenDuration duration, EvokeEvent target) {
+ this(duration, target, NOPRIMARYTIME);
+ }
+
+ @Override
+ public ArdenTime getNextRunTime(ExecutionContext context) {
+ ArdenTime currentTime = context.getCurrentTime();
+ ArdenTime nextRunTime = target.getNextRunTime(context);
+ if (nextRunTime != null) {
+ nextRunTime = new ArdenTime(nextRunTime.add(duration));
+ }
+
+ // delete past events from additionalSchedules:
+ while (!additionalSchedules.isEmpty() && additionalSchedules.comparator().compare(currentTime, additionalSchedules.first()) > 0) {
+ additionalSchedules.remove(additionalSchedules.first());
+ }
+
+ // decide whether to use additionalSchedule time or nextRunTime:
+ if (!additionalSchedules.isEmpty()) {
+ if (additionalSchedules.comparator().compare(additionalSchedules.first(), nextRunTime) > 0) {
+ return nextRunTime;
+ } else {
+ return additionalSchedules.first();
+ }
+ }
+ return nextRunTime;
+ }
+
+ @Override
+ public boolean runOnEvent(String event, ExecutionContext context) {
+ boolean run = target.runOnEvent(event, context);
+ if (run) {
+ // trigger in 'duration' after current time:
+ additionalSchedules.add(new ArdenTime(context.getCurrentTime().add(duration)));
+ }
+ return false;
+ }
+
+ @Override
+ public ArdenValue setTime(long newPrimaryTime) {
+ return new AfterEvokeEvent(duration, target, newPrimaryTime);
+ }
+
+}
diff --git a/src/arden/runtime/events/AnyEvokeEvent.java b/src/arden/runtime/events/AnyEvokeEvent.java
new file mode 100644
index 0000000..0dd26a9
--- /dev/null
+++ b/src/arden/runtime/events/AnyEvokeEvent.java
@@ -0,0 +1,55 @@
+package arden.runtime.events;
+
+import java.util.Arrays;
+import java.util.List;
+
+import arden.runtime.ArdenTime;
+import arden.runtime.ArdenValue;
+import arden.runtime.ExecutionContext;
+
+public class AnyEvokeEvent extends EvokeEvent {
+ List events;
+
+ public AnyEvokeEvent(EvokeEvent[] events, long primaryTime) {
+ this.events = Arrays.asList(events);
+ }
+
+ public AnyEvokeEvent(EvokeEvent[] events) {
+ this(events, NOPRIMARYTIME);
+ }
+
+ public AnyEvokeEvent(List events, long primaryTime) {
+ super(primaryTime);
+ this.events = events;
+ }
+
+ @Override
+ public ArdenTime getNextRunTime(ExecutionContext context) {
+ ArdenTime min = null;
+ for (EvokeEvent e : events) {
+ ArdenTime nextRunTime = e.getNextRunTime(context);
+ if (min == null || min.compareTo(nextRunTime) > 0) {
+ min = nextRunTime;
+ }
+ }
+ if (context.getCurrentTime().compareTo(min) > 0) {
+ return null; // event is in the past
+ }
+ return min;
+ }
+
+ @Override
+ public boolean runOnEvent(String event, ExecutionContext context) {
+ boolean any = false;
+ for (EvokeEvent e : events) {
+ any = any || e.runOnEvent(event, context);
+ }
+ return any;
+ }
+
+ @Override
+ public ArdenValue setTime(long newPrimaryTime) {
+ return new AnyEvokeEvent(events, newPrimaryTime);
+ }
+
+}
diff --git a/src/arden/runtime/events/CyclicEvokeEvent.java b/src/arden/runtime/events/CyclicEvokeEvent.java
new file mode 100644
index 0000000..60d7d50
--- /dev/null
+++ b/src/arden/runtime/events/CyclicEvokeEvent.java
@@ -0,0 +1,49 @@
+package arden.runtime.events;
+
+import arden.runtime.ArdenDuration;
+import arden.runtime.ArdenTime;
+import arden.runtime.ArdenValue;
+import arden.runtime.ExecutionContext;
+
+public class CyclicEvokeEvent extends EvokeEvent {
+
+ private ArdenDuration interval;
+ private ArdenDuration length;
+ private ArdenTime starting;
+ private ArdenTime next;
+
+ public CyclicEvokeEvent(ArdenDuration interval, ArdenDuration length, ArdenTime starting, long primaryTime) {
+ this.interval = interval;
+ this.length = length;
+ this.starting = starting;
+ this.next = this.starting;
+ }
+
+ public CyclicEvokeEvent(ArdenDuration interval, ArdenDuration length, ArdenTime starting) {
+ this(interval, length, starting, NOPRIMARYTIME);
+ }
+
+ @Override
+ public ArdenTime getNextRunTime(ExecutionContext context) {
+ ArdenTime current = context.getCurrentTime();
+ ArdenTime limit = new ArdenTime(starting.add(length));
+ while (current.compareTo(next) > 0) {
+ next = new ArdenTime(next.add(interval));
+ if (next.compareTo(limit) > 0) {
+ return null;
+ }
+ }
+ return next;
+ }
+
+ @Override
+ public boolean runOnEvent(String event, ExecutionContext context) {
+ return false;
+ }
+
+ @Override
+ public ArdenValue setTime(long newPrimaryTime) {
+ return new CyclicEvokeEvent(interval, length, starting, newPrimaryTime);
+ }
+
+}
diff --git a/src/arden/runtime/events/EmptyEvokeSlot.java b/src/arden/runtime/events/EmptyEvokeSlot.java
new file mode 100644
index 0000000..78f8e58
--- /dev/null
+++ b/src/arden/runtime/events/EmptyEvokeSlot.java
@@ -0,0 +1,32 @@
+package arden.runtime.events;
+
+import arden.runtime.ArdenTime;
+import arden.runtime.ArdenValue;
+import arden.runtime.ExecutionContext;
+
+public class EmptyEvokeSlot extends EvokeEvent {
+
+ public EmptyEvokeSlot(long primaryTime) {
+ super(primaryTime);
+ }
+
+ public EmptyEvokeSlot() {
+ this(NOPRIMARYTIME);
+ }
+
+ @Override
+ public ArdenTime getNextRunTime(ExecutionContext context) {
+ return null;
+ }
+
+ @Override
+ public boolean runOnEvent(String event, ExecutionContext context) {
+ return false;
+ }
+
+ @Override
+ public ArdenValue setTime(long newPrimaryTime) {
+ return new EmptyEvokeSlot(newPrimaryTime);
+ }
+
+}
diff --git a/src/arden/runtime/events/EvokeEvent.java b/src/arden/runtime/events/EvokeEvent.java
new file mode 100644
index 0000000..0d6f5dc
--- /dev/null
+++ b/src/arden/runtime/events/EvokeEvent.java
@@ -0,0 +1,22 @@
+package arden.runtime.events;
+
+import arden.runtime.ArdenTime;
+import arden.runtime.ArdenValue;
+import arden.runtime.ExecutionContext;
+
+
+public abstract class EvokeEvent extends ArdenValue {
+
+ public EvokeEvent() {
+ }
+
+ public EvokeEvent(long primaryTime) {
+ //super(primaryTime);
+ }
+
+ /** next run time for a scheduled event */
+ public abstract ArdenTime getNextRunTime(ExecutionContext context);
+
+ /** an event such as 'penicillin_storage' occurred */
+ public abstract boolean runOnEvent(String event, ExecutionContext context);
+}
diff --git a/src/arden/runtime/events/FixedDateEvokeEvent.java b/src/arden/runtime/events/FixedDateEvokeEvent.java
new file mode 100644
index 0000000..54288e4
--- /dev/null
+++ b/src/arden/runtime/events/FixedDateEvokeEvent.java
@@ -0,0 +1,35 @@
+package arden.runtime.events;
+
+import arden.runtime.ArdenTime;
+import arden.runtime.ArdenValue;
+import arden.runtime.ExecutionContext;
+
+public class FixedDateEvokeEvent extends EvokeEvent {
+
+ private ArdenTime date;
+
+ public FixedDateEvokeEvent(ArdenTime date, long primaryTime) {
+ super(primaryTime);
+ this.date = date;
+ }
+
+ public FixedDateEvokeEvent(ArdenTime date) {
+ this(date, NOPRIMARYTIME);
+ }
+
+ @Override
+ public ArdenTime getNextRunTime(ExecutionContext context) {
+ return date;
+ }
+
+ @Override
+ public boolean runOnEvent(String event, ExecutionContext context) {
+ return false;
+ }
+
+ @Override
+ public ArdenValue setTime(long newPrimaryTime) {
+ return new FixedDateEvokeEvent(date, newPrimaryTime);
+ }
+
+}
diff --git a/src/arden/runtime/events/FutureFixedDateEvokeEvent.java b/src/arden/runtime/events/FutureFixedDateEvokeEvent.java
new file mode 100644
index 0000000..aa68f0e
--- /dev/null
+++ b/src/arden/runtime/events/FutureFixedDateEvokeEvent.java
@@ -0,0 +1,32 @@
+package arden.runtime.events;
+
+import arden.runtime.ArdenTime;
+import arden.runtime.ArdenValue;
+import arden.runtime.ExecutionContext;
+
+public class FutureFixedDateEvokeEvent extends FixedDateEvokeEvent {
+
+ private ArdenTime date;
+
+ public FutureFixedDateEvokeEvent(ArdenTime date, long primaryTime) {
+ super(date, primaryTime);
+ }
+
+ public FutureFixedDateEvokeEvent(ArdenTime date) {
+ this(date, NOPRIMARYTIME);
+ }
+
+ @Override
+ public ArdenTime getNextRunTime(ExecutionContext context) {
+ if (context.getCurrentTime().compareTo(date) > 0) {
+ return null;
+ }
+ return date;
+ }
+
+ @Override
+ public ArdenValue setTime(long newPrimaryTime) {
+ return new FutureFixedDateEvokeEvent(date, newPrimaryTime);
+ }
+
+}
diff --git a/src/arden/runtime/events/MappedEvokeEvent.java b/src/arden/runtime/events/MappedEvokeEvent.java
new file mode 100644
index 0000000..8e3b24a
--- /dev/null
+++ b/src/arden/runtime/events/MappedEvokeEvent.java
@@ -0,0 +1,40 @@
+package arden.runtime.events;
+
+import arden.runtime.ArdenTime;
+import arden.runtime.ArdenValue;
+import arden.runtime.ExecutionContext;
+
+public class MappedEvokeEvent extends EvokeEvent {
+ private String mapping;
+
+ public MappedEvokeEvent(String mapping, long primaryTime) {
+ super(primaryTime);
+ if (mapping == null) {
+ throw new NullPointerException();
+ }
+ this.mapping = mapping;
+ }
+
+ public MappedEvokeEvent(String mapping) {
+ this(mapping, NOPRIMARYTIME);
+ }
+
+ @Override
+ public ArdenTime getNextRunTime(ExecutionContext context) {
+ return null;
+ }
+
+ @Override
+ public boolean runOnEvent(String event, ExecutionContext context) {
+ if (mapping.equalsIgnoreCase(event)) {
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public ArdenValue setTime(long newPrimaryTime) {
+ return new MappedEvokeEvent(mapping, newPrimaryTime);
+ }
+
+}
diff --git a/src/arden/runtime/events/NeverEvokeEvent.java b/src/arden/runtime/events/NeverEvokeEvent.java
new file mode 100644
index 0000000..de332f5
--- /dev/null
+++ b/src/arden/runtime/events/NeverEvokeEvent.java
@@ -0,0 +1,31 @@
+package arden.runtime.events;
+
+import arden.runtime.ArdenTime;
+import arden.runtime.ArdenValue;
+import arden.runtime.ExecutionContext;
+
+public class NeverEvokeEvent extends EvokeEvent {
+
+ public NeverEvokeEvent(long primaryTime) {
+ super(primaryTime);
+ }
+
+ public NeverEvokeEvent() {
+ this(NOPRIMARYTIME);
+ }
+
+ @Override
+ public ArdenTime getNextRunTime(ExecutionContext context) {
+ return null;
+ }
+
+ @Override
+ public boolean runOnEvent(String event, ExecutionContext context) {
+ return false;
+ }
+
+ @Override
+ public ArdenValue setTime(long newPrimaryTime) {
+ return new NeverEvokeEvent(newPrimaryTime);
+ }
+}
diff --git a/src/arden/runtime/events/UndefinedEvokeEvent.java b/src/arden/runtime/events/UndefinedEvokeEvent.java
new file mode 100644
index 0000000..6e7f2db
--- /dev/null
+++ b/src/arden/runtime/events/UndefinedEvokeEvent.java
@@ -0,0 +1,31 @@
+package arden.runtime.events;
+
+import arden.runtime.ArdenTime;
+import arden.runtime.ArdenValue;
+import arden.runtime.ExecutionContext;
+
+public class UndefinedEvokeEvent extends EvokeEvent {
+
+ public UndefinedEvokeEvent(long primaryTime) {
+ super(primaryTime);
+ }
+
+ public UndefinedEvokeEvent() {
+ this(NOPRIMARYTIME);
+ }
+
+ @Override
+ public boolean runOnEvent(String event, ExecutionContext context) {
+ return false;
+ }
+
+ @Override
+ public ArdenTime getNextRunTime(ExecutionContext context) {
+ return null;
+ }
+
+ @Override
+ public ArdenValue setTime(long newPrimaryTime) {
+ return new UndefinedEvokeEvent(newPrimaryTime);
+ }
+}
diff --git a/src/arden/runtime/events/UntilEvokeEvent.java b/src/arden/runtime/events/UntilEvokeEvent.java
new file mode 100644
index 0000000..9d31ff2
--- /dev/null
+++ b/src/arden/runtime/events/UntilEvokeEvent.java
@@ -0,0 +1,39 @@
+package arden.runtime.events;
+
+import arden.runtime.ArdenTime;
+import arden.runtime.ArdenValue;
+import arden.runtime.ExecutionContext;
+
+public class UntilEvokeEvent extends EvokeEvent {
+ private EvokeEvent cycle;
+ private ArdenTime until;
+
+ public UntilEvokeEvent(EvokeEvent cycle, ArdenTime until, long primaryTime) {
+ super(primaryTime);
+ this.cycle = cycle;
+ this.until = until;
+ }
+
+ public UntilEvokeEvent(EvokeEvent cycle, ArdenTime until) {
+ this(cycle, until, NOPRIMARYTIME);
+ }
+
+ @Override
+ public ArdenTime getNextRunTime(ExecutionContext context) {
+ ArdenTime next = cycle.getNextRunTime(context);
+ if (until.compareTo(next) > 0) {
+ return next;
+ }
+ return null;
+ }
+
+ @Override
+ public boolean runOnEvent(String event, ExecutionContext context) {
+ return cycle.runOnEvent(event, context);
+ }
+
+ @Override
+ public ArdenValue setTime(long newPrimaryTime) {
+ return new UntilEvokeEvent(cycle, until, newPrimaryTime);
+ }
+}
diff --git a/src/arden/runtime/jdbc/DriverHelper.java b/src/arden/runtime/jdbc/DriverHelper.java
new file mode 100644
index 0000000..1170275
--- /dev/null
+++ b/src/arden/runtime/jdbc/DriverHelper.java
@@ -0,0 +1,95 @@
+// arden2bytecode
+// Copyright (c) 2010, Daniel Grunwald
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are
+// permitted provided that the following conditions are met:
+//
+// - Redistributions of source code must retain the above copyright notice, this list
+// of conditions and the following disclaimer.
+//
+// - Redistributions in binary form must reproduce the above copyright notice, this list
+// of conditions and the following disclaimer in the documentation and/or other materials
+// provided with the distribution.
+//
+// - Neither the name of the owner nor the names of its contributors may be used to
+// endorse or promote products derived from this software without specific prior written
+// permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS &AS IS& AND ANY EXPRESS
+// OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package arden.runtime.jdbc;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.sql.Connection;
+import java.sql.Driver;
+import java.sql.DriverPropertyInfo;
+import java.sql.SQLException;
+import java.sql.SQLFeatureNotSupportedException;
+import java.util.Properties;
+import java.util.logging.Logger;
+
+public class DriverHelper implements Driver {
+ private final Driver driver;
+
+ public DriverHelper(Driver driver) {
+ if (driver == null) {
+ throw new IllegalArgumentException("Driver must not be null.");
+ }
+ this.driver = driver;
+ }
+
+ public Connection connect(String url, Properties info) throws SQLException {
+ return driver.connect(url, info);
+ }
+
+ public boolean acceptsURL(String url) throws SQLException {
+ return driver.acceptsURL(url);
+ }
+
+ public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException {
+ return driver.getPropertyInfo(url, info);
+ }
+
+ public int getMajorVersion() {
+ return driver.getMajorVersion();
+ }
+
+ public int getMinorVersion() {
+ return driver.getMinorVersion();
+ }
+
+ public boolean jdbcCompliant() {
+ return driver.jdbcCompliant();
+ }
+
+ /*
+ * this method is available since Java 1.7.
+ * Therefore it is not available on all platforms.
+ */
+ public Logger getParentLogger() throws SQLFeatureNotSupportedException {
+ Method getParentLogger = null;
+ try {
+ getParentLogger = driver.getClass().getMethod("getParentLogger", new Class>[]{});
+ } catch (SecurityException e) {
+ return null;
+ } catch (NoSuchMethodException e) {
+ return null;
+ }
+ try {
+ return (Logger) getParentLogger.invoke(driver, new Object[]{});
+ } catch (IllegalArgumentException e) {
+ } catch (IllegalAccessException e) {
+ } catch (InvocationTargetException e) {
+ }
+ return null;
+ }
+}
diff --git a/src/arden/runtime/jdbc/JDBCExecutionContext.java b/src/arden/runtime/jdbc/JDBCExecutionContext.java
new file mode 100644
index 0000000..09ca7af
--- /dev/null
+++ b/src/arden/runtime/jdbc/JDBCExecutionContext.java
@@ -0,0 +1,117 @@
+// arden2bytecode
+// Copyright (c) 2010, Daniel Grunwald
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are
+// permitted provided that the following conditions are met:
+//
+// - Redistributions of source code must retain the above copyright notice, this list
+// of conditions and the following disclaimer.
+//
+// - Redistributions in binary form must reproduce the above copyright notice, this list
+// of conditions and the following disclaimer in the documentation and/or other materials
+// provided with the distribution.
+//
+// - Neither the name of the owner nor the names of its contributors may be used to
+// endorse or promote products derived from this software without specific prior written
+// permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS &AS IS& AND ANY EXPRESS
+// OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package arden.runtime.jdbc;
+
+import java.sql.Connection;
+import java.sql.Driver;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+import java.util.Date;
+
+import arden.CommandLineOptions;
+import arden.runtime.ArdenString;
+import arden.runtime.ArdenTime;
+import arden.runtime.ArdenValue;
+import arden.runtime.DatabaseQuery;
+import arden.runtime.StdIOExecutionContext;
+
+public class JDBCExecutionContext extends StdIOExecutionContext {
+ private Connection connection = null;
+
+ public void loadDatabaseDriver(String className) {
+ try {
+ Driver driver = (Driver)Class.forName(className,
+ true,
+ Thread.currentThread().getContextClassLoader())
+ .newInstance();
+ DriverManager.registerDriver(new DriverHelper(driver));
+ } catch (InstantiationException e) {
+ e.printStackTrace();
+ System.exit(1);
+ } catch (IllegalAccessException e) {
+ e.printStackTrace();
+ System.exit(1);
+ } catch (ClassNotFoundException e) {
+ e.printStackTrace();
+ System.exit(1);
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public JDBCExecutionContext(CommandLineOptions options) {
+ super(options);
+
+ if (options.isDbdriver()) {
+ loadDatabaseDriver(options.getDbdriver());
+ }
+
+ // handle environment option
+ if (options.isEnvironment() && options.getEnvironment() != null) {
+ String environment = options.getEnvironment();
+ try {
+ connection = DriverManager.getConnection(environment);
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ } else {
+ throw new RuntimeException("No JDBC URL given. Can't connect.");
+ }
+ }
+
+ public void write(ArdenValue message, String destination) {
+ if ("database".equalsIgnoreCase(destination) || "query".equalsIgnoreCase(destination)) {
+ String msgString = ArdenString.getStringFromValue(message);
+
+ // execute query:
+ new JDBCQuery(msgString, connection).execute();
+ } else if ("email".equalsIgnoreCase(destination)) {
+ // TODO: implement email sending
+ } else {
+ super.write(message, destination);
+ }
+ }
+
+ public DatabaseQuery createQuery(String mapping) {
+ return new JDBCQuery(mapping, connection);
+ }
+
+ private ArdenTime eventtime = new ArdenTime(new Date());
+
+ public ArdenTime getEventTime() {
+ return eventtime;
+ }
+
+ public ArdenTime getTriggerTime() {
+ return eventtime;
+ }
+
+ public ArdenTime getCurrentTime() {
+ return new ArdenTime(new Date());
+ }
+}
diff --git a/src/arden/runtime/jdbc/JDBCQuery.java b/src/arden/runtime/jdbc/JDBCQuery.java
new file mode 100644
index 0000000..45a4e0d
--- /dev/null
+++ b/src/arden/runtime/jdbc/JDBCQuery.java
@@ -0,0 +1,137 @@
+// arden2bytecode
+// Copyright (c) 2010, Daniel Grunwald
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are
+// permitted provided that the following conditions are met:
+//
+// - Redistributions of source code must retain the above copyright notice, this list
+// of conditions and the following disclaimer.
+//
+// - Redistributions in binary form must reproduce the above copyright notice, this list
+// of conditions and the following disclaimer in the documentation and/or other materials
+// provided with the distribution.
+//
+// - Neither the name of the owner nor the names of its contributors may be used to
+// endorse or promote products derived from this software without specific prior written
+// permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS &AS IS& AND ANY EXPRESS
+// OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package arden.runtime.jdbc;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+
+import arden.runtime.ArdenList;
+import arden.runtime.ArdenNumber;
+import arden.runtime.ArdenString;
+import arden.runtime.ArdenValue;
+import arden.runtime.DatabaseQuery;
+
+public class JDBCQuery extends DatabaseQuery {
+ private Connection connection;
+ private String mapping;
+
+ public JDBCQuery(String mapping, Connection connection) {
+ this.mapping = mapping;
+ this.connection = connection;
+ }
+
+ public static ArdenValue objectToArdenValue(Object o) {
+ if (o instanceof String) {
+ return new ArdenString((String)o);
+ } else if (o instanceof Double) {
+ return new ArdenNumber(((Double)o).doubleValue());
+ } else if (o instanceof Integer) {
+ return new ArdenNumber(((Integer)o).doubleValue());
+ } else {
+ return new ArdenString(o.toString());
+ }
+ }
+
+ public static ArdenValue[] resultSetToArdenValues(ResultSet results) throws SQLException {
+ if (results == null) {
+ return ArdenList.EMPTY.values;
+ }
+
+ int columnCount = results.getMetaData().getColumnCount();
+
+ List> resultTable =
+ new ArrayList>(columnCount);
+ for (int column = 0; column < columnCount; column++) {
+ resultTable.add(new LinkedList());
+ }
+
+ int rowCount = 0;
+ while (results.next()) {
+ rowCount++;
+ for (int column = 0; column < columnCount; column++) {
+ Object o = results.getObject(column + 1);
+ resultTable.get(column).add(objectToArdenValue(o));
+ }
+ }
+
+ if (rowCount == 0) {
+ throw new RuntimeException("no results");
+ } else if (rowCount == 1) {
+ // one row
+ List ardenResult = new LinkedList();
+ for (int column = 0; column < columnCount; column++) {
+ ardenResult.add(resultTable.get(column).get(0));
+ }
+ return ardenResult.toArray(new ArdenValue[0]);
+ } else if (rowCount > 1) {
+ List ardenResult = new LinkedList();
+ for (int column = 0; column < columnCount; column++) {
+ // convert every column to ArdenList
+ ardenResult.add(
+ new ArdenList(
+ resultTable.get(column).toArray(
+ new ArdenValue[0])));
+ }
+ return ardenResult.toArray(new ArdenList[0]);
+ } else {
+ throw new RuntimeException("not implemented");
+ }
+ }
+
+ @Override
+ public ArdenValue[] execute() {
+ try {
+ Statement stmt = connection.createStatement();
+
+ boolean resultSetAvailable = stmt.execute(mapping);
+
+ ResultSet results = null;
+ if (resultSetAvailable) {
+ results = stmt.getResultSet();
+ }
+
+ return resultSetToArdenValues(results);
+ } catch (SQLException e) {
+ System.out.println("SQL Exception");
+ while (e != null) {
+ System.out.println(" State: " + e.getSQLState());
+ System.out.println(" Message: " + e.getMessage());
+ System.out.println(" Error: " + e.getErrorCode());
+ e = e.getNextException();
+ }
+ return ArdenList.EMPTY.values;
+ }
+ }
+
+
+}
diff --git a/src/arden/tests/ActionTests.java b/src/arden/tests/ActionTests.java
index 1e1f715..07ef36d 100644
--- a/src/arden/tests/ActionTests.java
+++ b/src/arden/tests/ActionTests.java
@@ -34,6 +34,7 @@
import java.io.StringReader;
import java.lang.reflect.InvocationTargetException;
+import arden.compiler.CompiledMlm;
import arden.compiler.Compiler;
import arden.compiler.CompilerException;
import arden.runtime.ArdenRunnable;
@@ -46,7 +47,7 @@
import org.junit.Test;
public class ActionTests {
- private static String inputStreamToString(InputStream in) throws IOException {
+ public static String inputStreamToString(InputStream in) throws IOException {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(in));
StringBuilder stringBuilder = new StringBuilder();
@@ -60,7 +61,7 @@ private static String inputStreamToString(InputStream in) throws IOException {
return stringBuilder.toString();
}
- public static MedicalLogicModule parseTemplate(String dataCode, String logicCode, String actionCode)
+ public static CompiledMlm parseTemplate(String dataCode, String logicCode, String actionCode)
throws CompilerException {
try {
InputStream s = ActionTests.class.getResourceAsStream("ActionTemplate.mlm");
diff --git a/src/arden/tests/CliTests.java b/src/arden/tests/CliTests.java
new file mode 100644
index 0000000..7461f98
--- /dev/null
+++ b/src/arden/tests/CliTests.java
@@ -0,0 +1,16 @@
+package arden.tests;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import arden.MainClass;
+
+/** tests for the command line interface (CLI) */
+public class CliTests {
+ @Test
+ public void basenameTest() throws Exception {
+ Assert.assertEquals("basename", MainClass.getFilenameBase("sdvnj/\\$%&../\\//./4e5\\v.s..df.v/basename.bfgb"));
+ Assert.assertEquals("", MainClass.getFilenameBase("sdvnj/\\$%&../\\//./4e5\\v.s..df.v/..fg.bfgb\\"));
+ Assert.assertEquals(".", MainClass.getFilenameBase(".."));
+ }
+}
diff --git a/src/arden/tests/ConstantParserTests.java b/src/arden/tests/ConstantParserTests.java
new file mode 100644
index 0000000..4a72473
--- /dev/null
+++ b/src/arden/tests/ConstantParserTests.java
@@ -0,0 +1,38 @@
+package arden.tests;
+
+import junit.framework.Assert;
+
+import org.junit.Test;
+
+import arden.constants.ConstantParser;
+import arden.runtime.ArdenList;
+import arden.runtime.ArdenNumber;
+import arden.runtime.ArdenString;
+import arden.runtime.ArdenValue;
+
+public class ConstantParserTests {
+ @Test
+ public void testConstantParser() throws Exception {
+ Assert.assertEquals(ArdenList.EMPTY, ConstantParser.parse("()"));
+ Assert.assertEquals(ArdenNumber.create(5.0, ArdenValue.NOPRIMARYTIME), ConstantParser.parse("5.0"));
+ Assert.assertFalse(ConstantParser.parse("5.0").equals(ArdenNumber.create(4.0, ArdenValue.NOPRIMARYTIME)));
+ Assert.assertEquals(new ArdenList(new ArdenValue[]{
+ ArdenNumber.create(1.0, ArdenValue.NOPRIMARYTIME)}),
+ ConstantParser.parse("(,1)"));
+ Assert.assertEquals(new ArdenList(new ArdenValue[]{
+ ArdenNumber.create(1.0, ArdenValue.NOPRIMARYTIME),
+ ArdenNumber.create(2.0, ArdenValue.NOPRIMARYTIME),
+ ArdenNumber.create(3.0, ArdenValue.NOPRIMARYTIME)
+ }),
+ ConstantParser.parse("(1,2,3)"));
+ Assert.assertEquals(new ArdenList(new ArdenValue[]{
+ ArdenNumber.create(1.0, ArdenValue.NOPRIMARYTIME),
+ ArdenNumber.create(2.1, ArdenValue.NOPRIMARYTIME),
+ ArdenNumber.create(2.2, ArdenValue.NOPRIMARYTIME),
+ ArdenNumber.create(2.3, ArdenValue.NOPRIMARYTIME),
+ ArdenNumber.create(3.0, ArdenValue.NOPRIMARYTIME)
+ }),
+ ConstantParser.parse("(1,(2.1,2.2,2.3),3)"));
+ Assert.assertEquals(new ArdenString("vfs\"dkj"), ConstantParser.parse("\"vfs\"\"dkj\""));
+ }
+}
diff --git a/src/arden/tests/EvokeTemplate.mlm b/src/arden/tests/EvokeTemplate.mlm
new file mode 100644
index 0000000..b9f2d0c
--- /dev/null
+++ b/src/arden/tests/EvokeTemplate.mlm
@@ -0,0 +1,30 @@
+maintenance:
+ title: Test;;
+ mlmname: test_mlm;;
+ arden: Version 2;;
+ version: 1.00;;
+ institution: TU Braunschweig;;
+ author: Daniel Grunwald;;
+ specialist: ;;
+ date: 2009-12-23;;
+ validation: testing;;
+library:
+ purpose:
+ Template for unit tests;;
+ explanation:
+ This MLM is used for several unit tests.;;
+ keywords:
+ Test Purpose;;
+ citations:
+ ;;
+knowledge:
+ type: data-driven;;
+ data: $DATA ;;
+evoke: $EVOKE;;
+logic:
+ $LOGIC
+ ;;
+action:
+ $ACTION
+ ;;
+end:
diff --git a/src/arden/tests/EvokeTests.java b/src/arden/tests/EvokeTests.java
new file mode 100644
index 0000000..e6c7d59
--- /dev/null
+++ b/src/arden/tests/EvokeTests.java
@@ -0,0 +1,253 @@
+// arden2bytecode
+// Copyright (c) 2010, Daniel Grunwald
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are
+// permitted provided that the following conditions are met:
+//
+// - Redistributions of source code must retain the above copyright notice, this list
+// of conditions and the following disclaimer.
+//
+// - Redistributions in binary form must reproduce the above copyright notice, this list
+// of conditions and the following disclaimer in the documentation and/or other materials
+// provided with the distribution.
+//
+// - Neither the name of the owner nor the names of its contributors may be used to
+// endorse or promote products derived from this software without specific prior written
+// permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS &AS IS& AND ANY EXPRESS
+// OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package arden.tests;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.StringReader;
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import arden.compiler.CompiledMlm;
+import arden.compiler.Compiler;
+import arden.compiler.CompilerException;
+import arden.runtime.ArdenTime;
+import arden.runtime.MedicalLogicModule;
+import arden.runtime.events.AfterEvokeEvent;
+import arden.runtime.events.CyclicEvokeEvent;
+import arden.runtime.events.EvokeEvent;
+import arden.runtime.events.FixedDateEvokeEvent;
+
+public class EvokeTests {
+ private static Calendar calendar = null;
+
+ public static ArdenTime createDate(int year, int month, int day) {
+ if (calendar == null) {
+ calendar = new GregorianCalendar();
+ }
+ calendar.clear();
+ calendar.set(year, month, day);
+ return new ArdenTime(calendar.getTimeInMillis());
+ }
+
+ public static ArdenTime createDateTime(int year, int month, int day, int hour, int minutes, int seconds) {
+ if (calendar == null) {
+ calendar = new GregorianCalendar();
+ }
+ calendar.clear();
+ calendar.set(year, month, day, hour, minutes, seconds);
+ return new ArdenTime(calendar.getTimeInMillis());
+ }
+
+ public static CompiledMlm parseTemplate(String dataCode, String evokeCode, String logicCode, String actionCode)
+ throws CompilerException {
+ try {
+ InputStream s = EvokeTests.class.getResourceAsStream("EvokeTemplate.mlm");
+ String fullCode = ActionTests.inputStreamToString(s)
+ .replace("$ACTION", actionCode)
+ .replace("$DATA", dataCode)
+ .replace("$EVOKE", evokeCode)
+ .replace("$LOGIC", logicCode);
+ Compiler c = new Compiler();
+ return c.compileMlm(new StringReader(fullCode));
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public static CompiledMlm parseEvoke(String evokeCode) throws CompilerException {
+ return parseEvoke("", evokeCode);
+ }
+
+ public static CompiledMlm parseEvoke(String data, String evokeCode) throws CompilerException {
+ return parseEvoke(data, evokeCode, "");
+ }
+
+ public static CompiledMlm parseEvoke(String data, String evokeCode, String actionCode) throws CompilerException {
+ return parseTemplate(data, evokeCode, "conclude true;", actionCode);
+ }
+
+ public static TestContext createTestContext() {
+ return new TestContext(createDate(1990, 0, 1)) {
+ @Override
+ public EvokeEvent getEvent(String mapping) {
+ if (mapping.equals("penicillin storage")) {
+ return new FixedDateEvokeEvent(createDate(1992, 0, 1));
+ } else if (mapping.equals("cephalosporin storage")) {
+ return new FixedDateEvokeEvent(createDate(1993, 0, 1));
+ } else if (mapping.equals("aminoglycoside storage")) {
+ return new FixedDateEvokeEvent(createDate(1994, 0, 1));
+ }
+ return super.getEvent(mapping);
+ }
+ };
+ }
+
+ @Test
+ public void AfterFixedDateOperator() throws Exception {
+ TestContext context = createTestContext();
+
+ MedicalLogicModule mlm = parseEvoke("3 days after 1992-01-01T00:00:00");
+
+ EvokeEvent e = mlm.getEvoke(context, null);
+ Assert.assertEquals(createDate(1992, 0, 4), e.getNextRunTime(context));
+ }
+
+ @Test
+ public void EventVariable() throws Exception {
+ TestContext context = createTestContext();
+
+ MedicalLogicModule mlm = parseEvoke("penicillin_storage := EVENT{penicillin storage}", "penicillin_storage");
+ EvokeEvent e = mlm.getEvoke(context, null);
+
+ Assert.assertEquals(createDate(1992, 0, 1), e.getNextRunTime(context));
+ }
+
+ @Test
+ public void AfterTimeOfEventOperator() throws Exception {
+ TestContext context = createTestContext();
+
+ CompiledMlm mlm = parseEvoke("event1 := EVENT{penicillin storage}", "3 days after time of event1");
+ EvokeEvent e = mlm.getEvoke(context, null);
+
+ Assert.assertEquals(createDate(1992, 0, 4), e.getNextRunTime(context));
+ }
+
+ @Test
+ public void FixedDate() throws Exception {
+ TestContext context = createTestContext();
+
+ MedicalLogicModule mlm = parseEvoke("1992-03-04");
+ EvokeEvent e = mlm.getEvoke(context, null);
+
+ Assert.assertEquals(createDate(1992, 2, 4), e.getNextRunTime(context));
+ }
+
+ @Test
+ public void FixedDateTime() throws Exception {
+ TestContext context = createTestContext();
+
+ MedicalLogicModule mlm = parseEvoke("1992-01-03T14:23:17.0");
+ EvokeEvent e = mlm.getEvoke(context, null);
+
+ Assert.assertEquals(createDateTime(1992, 0, 3, 14, 23, 17), e.getNextRunTime(context));
+ }
+
+ @Test
+ public void OrOperator() throws Exception {
+ TestContext context = createTestContext();
+
+ MedicalLogicModule mlm = parseEvoke(
+ "penicillin_storage := EVENT{penicillin storage};" +
+ "cephalosporin_storage := EVENT{cephalosporin storage};" +
+ "aminoglycoside_storage := EVENT{aminoglycoside storage};", "penicillin_storage OR cephalosporin_storage OR aminoglycoside_storage");
+ EvokeEvent e = mlm.getEvoke(context, null);
+
+ Assert.assertEquals(createDate(1992, 0, 1), e.getNextRunTime(context));
+ }
+
+ @Test
+ public void OrOperator2() throws Exception {
+ TestContext context = createTestContext();
+
+ MedicalLogicModule mlm = parseEvoke(
+ "cephalosporin_storage := EVENT{cephalosporin storage};" +
+ "aminoglycoside_storage := EVENT{aminoglycoside storage};", "cephalosporin_storage OR aminoglycoside_storage");
+ EvokeEvent e = mlm.getEvoke(context, null);
+
+ Assert.assertEquals(createDate(1993, 0, 1), e.getNextRunTime(context));
+ }
+
+ @Test
+ public void AnyOperator() throws Exception {
+ TestContext context = createTestContext();
+
+ MedicalLogicModule mlm = parseEvoke(
+ "penicillin_storage := EVENT{penicillin storage};" +
+ "cephalosporin_storage := EVENT{cephalosporin storage};" +
+ "aminoglycoside_storage := EVENT{aminoglycoside storage};", "ANY OF (penicillin_storage, cephalosporin_storage, aminoglycoside_storage)");
+ EvokeEvent e = mlm.getEvoke(context, null);
+
+ Assert.assertEquals(createDate(1992, 0, 1), e.getNextRunTime(context));
+ }
+
+ @Test
+ public void AnyOperator2() throws Exception {
+ TestContext context = createTestContext();
+
+ MedicalLogicModule mlm = parseEvoke(
+ "cephalosporin_storage := EVENT{cephalosporin storage};" +
+ "aminoglycoside_storage := EVENT{aminoglycoside storage};", "ANY OF (cephalosporin_storage, aminoglycoside_storage)");
+ EvokeEvent e = mlm.getEvoke(context, null);
+
+ Assert.assertEquals(createDate(1993, 0, 1), e.getNextRunTime(context));
+ }
+
+ @Test
+ public void AfterTimeOfEventOperator2() throws Exception {
+ TestContext context = createTestContext();
+
+ CompiledMlm mlm = parseEvoke("event1 := EVENT{test}", "3 days after time of event1");
+ EvokeEvent e = mlm.getEvoke(context, null);
+
+ Assert.assertTrue(e instanceof AfterEvokeEvent);
+ Assert.assertEquals(null, e.getNextRunTime(context));
+ Assert.assertEquals(createDate(1990, 0, 1), context.getCurrentTime());
+ e.runOnEvent("test", context);
+ Assert.assertEquals(createDate(1990, 0, 4), e.getNextRunTime(context));
+ }
+
+ @Test
+ public void CyclicEvent() throws Exception {
+ TestContext context = createTestContext();
+
+ CompiledMlm mlm = parseEvoke("every 5 days for 10 years starting 5 days after 1992-03-04");
+ EvokeEvent e = mlm.getEvoke(context, null);
+
+ Assert.assertTrue(e instanceof CyclicEvokeEvent);
+ Assert.assertEquals(createDate(1992, 2, 9), e.getNextRunTime(context));
+ context.setCurrentTime(createDate(1992, 2, 10));
+ Assert.assertEquals(createDate(1992, 2, 14), e.getNextRunTime(context));
+ }
+
+ @Test
+ public void CyclicEventBeginningInThePast() throws Exception {
+ TestContext context = createTestContext();
+
+ CompiledMlm mlm = parseEvoke("every 5 days for 10 years starting 5 days after 1989-03-04");
+ EvokeEvent e = mlm.getEvoke(context, null);
+
+ Assert.assertTrue(e instanceof CyclicEvokeEvent);
+ Assert.assertEquals(createDate(1990, 0, 3), e.getNextRunTime(context));
+ context.setCurrentTime(createDate(1990, 0, 4));
+ Assert.assertEquals(createDate(1990, 0, 8), e.getNextRunTime(context));
+ }
+}
diff --git a/src/arden/tests/ExampleEvokeTests.java b/src/arden/tests/ExampleEvokeTests.java
new file mode 100644
index 0000000..d9cee6c
--- /dev/null
+++ b/src/arden/tests/ExampleEvokeTests.java
@@ -0,0 +1,211 @@
+// arden2bytecode
+// Copyright (c) 2010, Daniel Grunwald
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are
+// permitted provided that the following conditions are met:
+//
+// - Redistributions of source code must retain the above copyright notice, this list
+// of conditions and the following disclaimer.
+//
+// - Redistributions in binary form must reproduce the above copyright notice, this list
+// of conditions and the following disclaimer in the documentation and/or other materials
+// provided with the distribution.
+//
+// - Neither the name of the owner nor the names of its contributors may be used to
+// endorse or promote products derived from this software without specific prior written
+// permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS &AS IS& AND ANY EXPRESS
+// OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package arden.tests;
+
+import java.io.InputStreamReader;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import arden.compiler.CompiledMlm;
+import arden.compiler.Compiler;
+import arden.runtime.ArdenDuration;
+import arden.runtime.ArdenList;
+import arden.runtime.ArdenNull;
+import arden.runtime.ArdenString;
+import arden.runtime.ArdenTime;
+import arden.runtime.ArdenValue;
+import arden.runtime.DatabaseQuery;
+import arden.runtime.MedicalLogicModule;
+import arden.runtime.MemoryQuery;
+import arden.runtime.events.CyclicEvokeEvent;
+import arden.runtime.events.EmptyEvokeSlot;
+import arden.runtime.events.EvokeEvent;
+import arden.runtime.events.FixedDateEvokeEvent;
+import arden.runtime.events.MappedEvokeEvent;
+
+public class ExampleEvokeTests {
+ private MedicalLogicModule compile(String filename) throws Exception {
+ Compiler c = new Compiler();
+ c.enableDebugging(filename + ".mlm");
+ CompiledMlm mlm = c
+ .compileMlm(new InputStreamReader(ExampleEvokeTests.class.getResourceAsStream(filename + ".mlm")));
+ return mlm;
+ }
+
+ @Test
+ public void X21() throws Exception {
+ MedicalLogicModule mlm = compile("x2.1");
+
+ TestContext context = new TestContext();
+ EvokeEvent e = mlm.getEvoke(context, null);
+
+ Assert.assertTrue(e instanceof MappedEvokeEvent);
+ Assert.assertTrue(e.runOnEvent("storage of urine electrolytes", context));
+ }
+
+ @Test
+ public void X22() throws Exception {
+ MedicalLogicModule mlm = compile("x2.2");
+
+ TestContext context = new TestContext();
+ EvokeEvent e = mlm.getEvoke(context, null);
+
+ Assert.assertTrue(e instanceof MappedEvokeEvent);
+ Assert.assertTrue(e.runOnEvent("'06210519','06210669'", context));
+ }
+
+ @Test
+ public void X23noAllergies() throws Exception {
+ MedicalLogicModule mlm = compile("x2.3");
+ TestContext context = new TestContext();
+ EvokeEvent e = mlm.getEvoke(context, null);
+
+ Assert.assertTrue(e instanceof MappedEvokeEvent);
+ Assert.assertTrue(e.runOnEvent("medication_order where class = penicillin", context));
+ }
+
+ @Test
+ public void X23allergies() throws Exception {
+ MedicalLogicModule mlm = compile("x2.3");
+ TestContext context = new TestContext() {
+ @Override
+ public DatabaseQuery createQuery(String mapping) {
+ Assert.assertEquals("allergy where agent_class = penicillin", mapping);
+ ArdenList list = new ArdenList(new ArdenValue[] { new ArdenString("all1"), new ArdenString("all2") });
+ return new MemoryQuery(new ArdenValue[] { list });
+ }
+ };
+ EvokeEvent e = mlm.getEvoke(context, null);
+
+ Assert.assertTrue(e instanceof MappedEvokeEvent);
+ Assert.assertTrue(e.runOnEvent("medication_order where class = penicillin", context));
+ }
+
+ @Test
+ public void X23allergiesButLastIsNull() throws Exception {
+ MedicalLogicModule mlm = compile("x2.3");
+ TestContext context = new TestContext() {
+ @Override
+ public DatabaseQuery createQuery(String mapping) {
+ Assert.assertEquals("allergy where agent_class = penicillin", mapping);
+ ArdenList list = new ArdenList(new ArdenValue[] { new ArdenString("all1"), ArdenNull.INSTANCE });
+ return new MemoryQuery(new ArdenValue[] { list });
+ }
+ };
+ EvokeEvent e = mlm.getEvoke(context, null);
+
+ Assert.assertTrue(e instanceof MappedEvokeEvent);
+ Assert.assertTrue(e.runOnEvent("medication_order where class = penicillin", context));
+ }
+
+ @Test
+ public void X24() throws Exception {
+ MedicalLogicModule mlm = compile("x2.4");
+
+ TestContext context = new TestContext();
+ EvokeEvent e = mlm.getEvoke(context, null);
+
+ Assert.assertTrue(e instanceof MappedEvokeEvent);
+ Assert.assertTrue(e.runOnEvent("medication_order where class = gentamicin", context));
+ }
+
+ @Test
+ public void X25() throws Exception {
+ MedicalLogicModule mlm = compile("x2.5");
+ ArdenTime defaultTime = EvokeTests.createDateTime(1980, 0, 1, 0, 0, 0); // this is the default myExecutionContext.getCurrentTime()
+ ArdenTime defaultEventDate = EvokeTests.createDateTime(2000, 0, 1, 0, 0, 0); // this is the default myExecutionContext.getEvent()
+ EvokeEvent defaultEvokeEvent = new FixedDateEvokeEvent(defaultEventDate);
+
+ TestContext context = new TestContext(defaultEvokeEvent, defaultTime);
+ EvokeEvent e = mlm.getEvoke(context, null);
+
+ Assert.assertTrue(e instanceof CyclicEvokeEvent);
+
+ ArdenDuration fiveDays = (ArdenDuration)ArdenDuration.create(
+ 60.0 * 60 * 24 * 5,
+ false,
+ context.getCurrentTime().value);
+ ArdenTime fiveDaysLater = new ArdenTime(
+ defaultEventDate.add(fiveDays)); // add 5 days as in x2.5.mlm
+ // default runtime should be 5 days after the event as declared in the MLM:
+ Assert.assertEquals(
+ fiveDaysLater,
+ e.getNextRunTime(context));
+
+ ArdenTime tenDaysLater = new ArdenTime(fiveDaysLater.add(fiveDays));
+ ArdenDuration oneSecond = (ArdenDuration)ArdenDuration.create(1, false, context.getCurrentTime().value);
+
+ context.setCurrentTime(new ArdenTime(fiveDaysLater.add(oneSecond)));
+ // after the first runtime has been passed, the mlm should be re-run another 5 days later:
+ Assert.assertEquals(
+ tenDaysLater,
+ e.getNextRunTime(context));
+ }
+
+ @Test
+ public void X26() throws Exception {
+ MedicalLogicModule mlm = compile("x2.6");
+
+ TestContext context = new TestContext();
+ EvokeEvent e = mlm.getEvoke(context, null);
+
+ Assert.assertTrue(e instanceof MappedEvokeEvent);
+ Assert.assertTrue(e.runOnEvent("STORAGE OF ABSOLUTE_NEUTROPHILE_COUNT", context));
+ }
+
+ @Test
+ public void X27() throws Exception {
+ MedicalLogicModule mlm = compile("x2.7");
+
+ TestContext context = new TestContext();
+ EvokeEvent e = mlm.getEvoke(context, null);
+
+ Assert.assertTrue(e instanceof EmptyEvokeSlot);
+ }
+
+ @Test
+ public void X28() throws Exception {
+ MedicalLogicModule mlm = compile("x2.8");
+
+ TestContext context = new TestContext();
+ ArdenList medOrders = new ArdenList(new ArdenValue[] { new ArdenString("order1"), new ArdenString("order2"),
+ new ArdenString("order3") });
+ ArdenList medAllergens = new ArdenList(new ArdenValue[] { new ArdenString("a1"), new ArdenString("a2"),
+ new ArdenString("a3") });
+ ArdenList patientAllergies = new ArdenList(new ArdenValue[] { new ArdenString("a2"), new ArdenString("a2"),
+ new ArdenString("a1") });
+ ArdenList patientReactions = new ArdenList(new ArdenValue[] { new ArdenString("r1"), new ArdenString("r2"),
+ new ArdenString("r3") });
+
+ EvokeEvent e = mlm.getEvoke(context, new ArdenValue[] { medOrders, medAllergens, patientAllergies,
+ patientReactions });
+
+ Assert.assertTrue(e instanceof EmptyEvokeSlot);
+ }
+}
diff --git a/src/arden/tests/ExampleTests.java b/src/arden/tests/ExampleTests.java
index 5df4356..2d6f10f 100644
--- a/src/arden/tests/ExampleTests.java
+++ b/src/arden/tests/ExampleTests.java
@@ -27,7 +27,6 @@
package arden.tests;
-import java.io.FileOutputStream;
import java.io.InputStreamReader;
import org.junit.Assert;
@@ -49,9 +48,9 @@ private MedicalLogicModule compile(String filename) throws Exception {
c.enableDebugging(filename + ".mlm");
CompiledMlm mlm = c
.compileMlm(new InputStreamReader(ExampleTests.class.getResourceAsStream(filename + ".mlm")));
- FileOutputStream fos = new FileOutputStream("bin/" + mlm.getName() + ".class");
+ /*FileOutputStream fos = new FileOutputStream(filename + ".class");
mlm.saveClassFile(fos);
- fos.close();
+ fos.close();*/
return mlm;
}
diff --git a/src/arden/tests/GetValueTests.java b/src/arden/tests/GetValueTests.java
new file mode 100644
index 0000000..1949d18
--- /dev/null
+++ b/src/arden/tests/GetValueTests.java
@@ -0,0 +1,51 @@
+package arden.tests;
+
+import java.io.InputStreamReader;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import arden.compiler.CompiledMlm;
+import arden.compiler.Compiler;
+import arden.runtime.ArdenNumber;
+import arden.runtime.ArdenValue;
+import arden.runtime.MedicalLogicModule;
+
+public class GetValueTests {
+
+ private MedicalLogicModule compile(String filename) throws Exception {
+ Compiler c = new Compiler();
+ c.enableDebugging(filename + ".mlm");
+ CompiledMlm mlm = c
+ .compileMlm(new InputStreamReader(ExampleTests.class.getResourceAsStream(filename + ".mlm")));
+ return mlm;
+ }
+
+ @Test
+ public void X27() throws Exception {
+ MedicalLogicModule mlm = compile("x2.7");
+
+ // mlm has not been not run yet:
+ Assert.assertNull(mlm.getValue("low_dose_beta_use"));
+
+ TestContext context = new TestContext();
+ mlm.run(context, null);
+
+ Assert.assertTrue(mlm.getValue("low_dose_beta_use").isFalse());
+ Assert.assertNull(mlm.getValue("does_not_exist"));
+ }
+
+ @Test
+ public void X28() throws Exception {
+ MedicalLogicModule mlm = compile("x2.8");
+
+ // mlm has not been not run yet:
+ Assert.assertNull(mlm.getValue("num"));
+
+ TestContext context = new TestContext();
+ mlm.run(context, null);
+
+ Assert.assertEquals(ArdenNumber.create(2.0, ArdenValue.NOPRIMARYTIME), mlm.getValue("num"));
+ Assert.assertNull(mlm.getValue("does_not_exist"));
+ }
+}
diff --git a/src/arden/tests/JDBCQueryTests.java b/src/arden/tests/JDBCQueryTests.java
new file mode 100644
index 0000000..5c916f9
--- /dev/null
+++ b/src/arden/tests/JDBCQueryTests.java
@@ -0,0 +1,151 @@
+package arden.tests;
+
+import java.io.File;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.sql.Connection;
+import java.sql.Driver;
+import java.sql.DriverManager;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+import org.junit.Test;
+import org.junit.Assert;
+import org.junit.internal.ArrayComparisonFailure;
+
+import uk.co.flamingpenguin.jewel.cli.CliFactory;
+
+import arden.CommandLineOptions;
+import arden.runtime.ArdenList;
+import arden.runtime.ArdenNumber;
+import arden.runtime.ArdenString;
+import arden.runtime.ArdenValue;
+import arden.runtime.ExecutionContext;
+import arden.runtime.MedicalLogicModule;
+import arden.runtime.jdbc.DriverHelper;
+import arden.runtime.jdbc.JDBCExecutionContext;
+import arden.runtime.jdbc.JDBCQuery;
+
+public class JDBCQueryTests {
+ private static boolean SQLiteLoaded = false;
+ private static final String SQLITE_PATH = "./sqlite-jdbc-3.7.2.jar";
+
+ public Driver loadSQLite() throws
+ MalformedURLException,
+ InstantiationException,
+ IllegalAccessException,
+ SQLException {
+ if (SQLiteLoaded) {
+ return DriverManager.getDriver("jdbc:sqlite:");
+ }
+ URL urlA =
+ new File(
+ SQLITE_PATH
+ ).toURI().toURL();
+ URL[] urls = { urlA };
+ URLClassLoader ulc = new URLClassLoader(urls);
+ Driver driver;
+ try {
+ driver = (Driver)Class.forName("org.sqlite.JDBC", true, ulc).newInstance();
+ } catch (ClassNotFoundException e) {
+ System.err.println("SQLite JDBC driver not found. Skipping associated test in " + this.getClass().getName());
+ return null;
+ }
+ DriverManager.registerDriver(new DriverHelper(driver));
+ SQLiteLoaded = true;
+ return driver;
+ }
+
+ public Statement initDb() {
+ Connection connection = null;
+ Statement statement = null;
+ try {
+ connection = DriverManager.getConnection("jdbc:sqlite:");
+ statement = connection.createStatement();
+
+ statement.executeUpdate("drop table if exists person");
+ statement.executeUpdate("create table person (id integer, name string)");
+ statement.executeUpdate("insert into person values(1, 'A')");
+ statement.executeUpdate("insert into person values(2, 'B')");
+ } catch (SQLException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ return statement;
+ }
+
+ @Test
+ public void ObjectToArdenValue() throws Exception {
+ Assert.assertEquals(new ArdenNumber(1.0),
+ JDBCQuery.objectToArdenValue(new Integer(1)));
+ Assert.assertEquals(new ArdenNumber(1.0),
+ JDBCQuery.objectToArdenValue(new Double(1.0)));
+ Assert.assertEquals(new ArdenString("hey"),
+ JDBCQuery.objectToArdenValue(new String("hey")));
+ }
+
+ private static void assertArrayNotEquals(Object[] expecteds, Object[] actuals) throws AssertionError {
+ boolean exceptionThrown = false;
+ try {
+ Assert.assertArrayEquals(expecteds, actuals);
+ } catch (ArrayComparisonFailure f) {
+ exceptionThrown = true;
+ }
+ if (!exceptionThrown) {
+ throw new AssertionError("Array is same.");
+ }
+ }
+
+ @Test
+ public void ResultSetToArdenValues() throws Exception {
+ if (loadSQLite() == null) {
+ return;
+ }
+ Statement stmt = initDb();
+ ResultSet results = stmt.executeQuery("select * from person");
+ ArdenValue[] ardenValues = JDBCQuery.resultSetToArdenValues(results);
+
+ ArdenValue[] expectedA = {new ArdenNumber(1), new ArdenNumber(2)};
+ ArdenValue[] expectedB = {new ArdenString("A"), new ArdenString("B")};
+ ArdenList[] expectedArrA = {new ArdenList(expectedA), new ArdenList(expectedB)};
+ Assert.assertArrayEquals(expectedArrA, ardenValues);
+
+ ArdenValue[] expectedC = {new ArdenString("A"), new ArdenString("X")};
+ ArdenList[] expectedArrB = {new ArdenList(expectedA), new ArdenList(expectedC)};
+ assertArrayNotEquals(expectedArrB, ardenValues);
+
+ ArdenValue[] expectedD = {new ArdenString("1"), new ArdenNumber(2)};
+ ArdenList[] expectedArrC = {new ArdenList(expectedD), new ArdenList(expectedB)};
+ assertArrayNotEquals(expectedArrC, ardenValues);
+ }
+
+ @Test
+ public void JDBCExecutionContextRead() throws Exception {
+ if (loadSQLite() == null) {
+ return;
+ }
+ String[] args = new String[]{"-e", "jdbc:sqlite:"};
+ CommandLineOptions options =
+ CliFactory.parseArguments(CommandLineOptions.class, args);
+
+ ExecutionContext testContext = new JDBCExecutionContext(options);
+ MedicalLogicModule mlm = ActionTests.parseTemplate(
+ "varA := read {drop table if exists person};\n" +
+ "varB := read {create table person (id integer, name string)};\n" +
+ "varC := read {insert into person values (1, 'A')};\n" +
+ "varD := read {insert into person values (2, 'B')};\n" +
+ "(varE, varF) := read {select * from person};\n",
+ "conclude true;",
+ "return (varE, varF);");
+ ArdenValue[] result = mlm.run(testContext, null);
+ Assert.assertEquals(1, result.length);
+
+ ArdenValue[] expected = {new ArdenNumber(1), new ArdenNumber(2),
+ new ArdenString("A"), new ArdenString("B")};
+ ArdenValue[] resultList = ((ArdenList)(result[0])).values;
+
+ Assert.assertArrayEquals(expected, resultList);
+ }
+}
diff --git a/src/arden/tests/LoadMlmFromBytecodeTests.java b/src/arden/tests/LoadMlmFromBytecodeTests.java
new file mode 100644
index 0000000..4b056fd
--- /dev/null
+++ b/src/arden/tests/LoadMlmFromBytecodeTests.java
@@ -0,0 +1,215 @@
+package arden.tests;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStreamReader;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import arden.compiler.Compiler;
+import arden.compiler.CompiledMlm;
+import arden.runtime.ArdenList;
+import arden.runtime.ArdenNull;
+import arden.runtime.ArdenString;
+import arden.runtime.ArdenValue;
+import arden.runtime.DatabaseQuery;
+import arden.runtime.LibraryMetadata;
+import arden.runtime.MaintenanceMetadata;
+import arden.runtime.MedicalLogicModule;
+import arden.runtime.MemoryQuery;
+import arden.runtime.RuntimeHelpers;
+
+public class LoadMlmFromBytecodeTests {
+ private MedicalLogicModule compile(String filename) throws Exception {
+ Compiler c = new Compiler();
+ c.enableDebugging(filename + ".mlm");
+ CompiledMlm mlm = c
+ .compileMlm(new InputStreamReader(ExampleTests.class.getResourceAsStream(filename + ".mlm")));
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ mlm.saveClassFile(bos);
+ bos.close();
+ return new CompiledMlm(new ByteArrayInputStream(bos.toByteArray()), mlm.getName());
+ }
+
+
+ @Test
+ public void X21() throws Exception {
+ MedicalLogicModule mlm = compile("x2.1");
+
+ TestContext context = new TestContext();
+ mlm.run(context, null);
+
+ Assert.assertEquals("", context.getOutputText());
+ }
+
+ @Test
+ public void X22() throws Exception {
+ MedicalLogicModule mlm = compile("x2.2");
+
+ TestContext context = new TestContext();
+ mlm.run(context, null);
+
+ Assert.assertEquals("", context.getOutputText());
+ }
+
+ @Test
+ public void X23noAllergies() throws Exception {
+ MedicalLogicModule mlm = compile("x2.3");
+ TestContext context = new TestContext();
+ mlm.run(context, null);
+ Assert.assertEquals("", context.getOutputText());
+ }
+
+ @Test
+ public void X23allergies() throws Exception {
+ MedicalLogicModule mlm = compile("x2.3");
+ TestContext context = new TestContext() {
+ @Override
+ public DatabaseQuery createQuery(String mapping) {
+ Assert.assertEquals("allergy where agent_class = penicillin", mapping);
+ ArdenList list = new ArdenList(new ArdenValue[] { new ArdenString("all1"), new ArdenString("all2") });
+ return new MemoryQuery(new ArdenValue[] { list });
+ }
+ };
+ mlm.run(context, null);
+ Assert.assertEquals("Caution, the patient has the following allergy to penicillin documented: all2\n", context
+ .getOutputText());
+ }
+
+ @Test
+ public void X23allergiesButLastIsNull() throws Exception {
+ MedicalLogicModule mlm = compile("x2.3");
+ TestContext context = new TestContext() {
+ @Override
+ public DatabaseQuery createQuery(String mapping) {
+ Assert.assertEquals("allergy where agent_class = penicillin", mapping);
+ ArdenList list = new ArdenList(new ArdenValue[] { new ArdenString("all1"), ArdenNull.INSTANCE });
+ return new MemoryQuery(new ArdenValue[] { list });
+ }
+ };
+ mlm.run(context, null);
+ Assert.assertEquals("", context.getOutputText());
+ }
+
+ @Test
+ public void X23urgency() throws Exception {
+ MedicalLogicModule mlm = compile("x2.3");
+ Assert.assertEquals(51.0, mlm.createInstance(new TestContext(), null).getUrgency(), 0);
+ }
+
+ @Test
+ public void X24() throws Exception {
+ MedicalLogicModule mlm = compile("x2.4");
+
+ TestContext context = new TestContext();
+ mlm.run(context, null);
+
+ Assert.assertEquals("", context.getOutputText());
+ }
+
+ @Test
+ public void X25() throws Exception {
+ MedicalLogicModule mlm = compile("x2.5");
+
+ TestContext context = new TestContext();
+ mlm.run(context, null);
+
+ Assert.assertEquals(
+ "Suggest obtaining a serum creatinine to follow up on renal function in the setting of gentamicin.\n",
+ context.getOutputText());
+ }
+
+ @Test
+ public void X26() throws Exception {
+ MedicalLogicModule mlm = compile("x2.6");
+
+ TestContext context = new TestContext();
+ mlm.run(context, null);
+
+ Assert.assertEquals("", context.getOutputText());
+ }
+
+ @Test
+ public void X27() throws Exception {
+ MedicalLogicModule mlm = compile("x2.7");
+
+ TestContext context = new TestContext();
+ mlm.run(context, null);
+
+ Assert.assertEquals("", context.getOutputText());
+ }
+
+ @Test
+ public void X28() throws Exception {
+ MedicalLogicModule mlm = compile("x2.8");
+
+ TestContext context = new TestContext();
+ ArdenList medOrders = new ArdenList(new ArdenValue[] { new ArdenString("order1"), new ArdenString("order2"),
+ new ArdenString("order3") });
+ ArdenList medAllergens = new ArdenList(new ArdenValue[] { new ArdenString("a1"), new ArdenString("a2"),
+ new ArdenString("a3") });
+ ArdenList patientAllergies = new ArdenList(new ArdenValue[] { new ArdenString("a2"), new ArdenString("a2"),
+ new ArdenString("a1") });
+ ArdenList patientReactions = new ArdenList(new ArdenValue[] { new ArdenString("r1"), new ArdenString("r2"),
+ new ArdenString("r3") });
+ ArdenValue[] result = mlm.run(context, new ArdenValue[] { medOrders, medAllergens, patientAllergies,
+ patientReactions });
+ Assert.assertEquals(3, result.length);
+
+ Assert.assertEquals("(\"order1\",\"order2\")", result[0].toString());
+ Assert.assertEquals("(\"a1\",\"a2\")", result[1].toString());
+ Assert.assertEquals("(\"r3\",\"r1\",\"r2\")", result[2].toString());
+
+ Assert.assertEquals("", context.getOutputText());
+ }
+
+ @Test
+ public void X21Metadata() throws Exception {
+ MedicalLogicModule compiledMlm = compile("x2.1");
+
+ MaintenanceMetadata m = compiledMlm.getMaintenance();
+ Assert.assertEquals("Fractional excretion of sodium", m.getTitle());
+ Assert.assertEquals("fractional_na", m.getMlmName());
+ Assert.assertEquals("2", m.getArdenVersion());
+ Assert.assertEquals("1.00", m.getVersion());
+ Assert.assertEquals("Columbia-Presbyterian Medical Center", m.getInstitution());
+ Assert.assertEquals("George Hripcsak, M.D.(hripcsak@cucis.cis.columbia.edu)", m.getAuthor());
+ Assert.assertNull(m.getSpecialist());
+ Assert.assertEquals("testing", m.getValidation());
+
+ LibraryMetadata l = compiledMlm.getLibrary();
+ Assert.assertEquals(3, l.getKeywords().size());
+ Assert.assertEquals("fractional excretion", l.getKeywords().get(0));
+ Assert.assertEquals("serum sodium", l.getKeywords().get(1));
+ Assert.assertEquals("azotemia", l.getKeywords().get(2));
+
+ Assert.assertEquals(RuntimeHelpers.DEFAULT_PRIORITY, compiledMlm.getPriority(), 0);
+
+ Assert.assertEquals(RuntimeHelpers.DEFAULT_URGENCY, compiledMlm.getUrgency(), 0);
+ }
+
+ @Test
+ public void X23Metadata() throws Exception {
+ MedicalLogicModule compiledMlm = compile("x2.3");
+
+ MaintenanceMetadata m = compiledMlm.getMaintenance();
+ Assert.assertEquals("Check for penicillin allergy", m.getTitle());
+ Assert.assertEquals("pen_allergy", m.getMlmName());
+ Assert.assertEquals("1", m.getArdenVersion());
+ Assert.assertEquals("1.00", m.getVersion());
+ Assert.assertEquals("Columbia-Presbyterian Medical Center", m.getInstitution());
+ Assert.assertEquals("George Hripcsak, M.D.", m.getAuthor());
+ Assert.assertNull(m.getSpecialist());
+ Assert.assertEquals("testing", m.getValidation());
+
+ LibraryMetadata l = compiledMlm.getLibrary();
+ Assert.assertEquals(2, l.getKeywords().size());
+ Assert.assertEquals("penicillin", l.getKeywords().get(0));
+ Assert.assertEquals("allergy", l.getKeywords().get(1));
+
+ Assert.assertEquals(42, compiledMlm.getPriority(), 0);
+
+ Assert.assertEquals(51, compiledMlm.getUrgency(), 0);
+ }
+}
diff --git a/src/arden/tests/LogicTests.java b/src/arden/tests/LogicTests.java
index 9bfc138..14dc2fe 100644
--- a/src/arden/tests/LogicTests.java
+++ b/src/arden/tests/LogicTests.java
@@ -32,6 +32,7 @@
import org.junit.Assert;
import org.junit.Test;
+import arden.compiler.CompiledMlm;
import arden.runtime.ArdenList;
import arden.runtime.ArdenNumber;
import arden.runtime.ArdenObject;
@@ -186,7 +187,7 @@ public ArdenValue[] run(ExecutionContext context, ArdenValue[] arguments)
@Test
public void RecursiveMlm() throws Exception {
- MedicalLogicModule mlm = ActionTests.parseTemplate(
+ CompiledMlm mlm = ActionTests.parseTemplate(
"this := MLM mlm_self; arg := ARGUMENT;",
"If arg > 1 THEN"
+ " result := CALL this WITH (arg-1);"
@@ -232,6 +233,15 @@ public void AttributeAssignment() throws Exception {
Assert.assertEquals("Rectangle := OBJECT [ aLeft, aTop, aWidth, aHeight ]", obj.type.toString());
Assert.assertEquals("NEW Rectangle WITH 0, 0, 10, 20", obj.toString());
}
+
+ @Test
+ public void AttributeAssignmentWithLet() throws Exception {
+ ArdenObject obj = (ArdenObject) eval("Rectangle := Object [ aLeft, aTop, aWidth, aHeight ];",
+ "rect := NEW Rectangle; LET rect.aLeft BE 0; LET rect.aTop BE 0; LET rect.aWidth BE 10; LET rect.aHeight BE 20; "
+ + " conclude true;", "return rect;", new TestContext());
+ Assert.assertEquals("Rectangle := OBJECT [ aLeft, aTop, aWidth, aHeight ]", obj.type.toString());
+ Assert.assertEquals("NEW Rectangle WITH 0, 0, 10, 20", obj.toString());
+ }
@Test
public void ReferenceIdentity() throws Exception {
diff --git a/src/arden/tests/MetadataTests.java b/src/arden/tests/MetadataTests.java
index 25b6ad9..d7657e7 100644
--- a/src/arden/tests/MetadataTests.java
+++ b/src/arden/tests/MetadataTests.java
@@ -32,9 +32,12 @@
import org.junit.Assert;
import org.junit.Test;
-import arden.compiler.CompiledMlm;
import arden.compiler.Compiler;
+import arden.compiler.CompiledMlm;
+import arden.runtime.ExecutionContext;
+import arden.runtime.LibraryMetadata;
import arden.runtime.MaintenanceMetadata;
+import arden.runtime.MedicalLogicModuleImplementation;
public class MetadataTests {
@Test
@@ -81,4 +84,57 @@ public void X23() throws Exception {
Assert.assertEquals(42, mlm.getPriority(), 0);
}
+
+ @Test
+ public void X21FromByteCode() throws Exception {
+ Compiler c = new Compiler();
+ CompiledMlm compiledMlm = c.compileMlm(new InputStreamReader(MetadataTests.class.getResourceAsStream("x2.1.mlm")));
+
+ ExecutionContext cx = new TestContext();
+
+ MedicalLogicModuleImplementation impl = compiledMlm.createInstance(cx, null);
+
+ MaintenanceMetadata m = impl.getMaintenanceMetadata();
+ Assert.assertEquals("Fractional excretion of sodium", m.getTitle());
+ Assert.assertEquals("fractional_na", m.getMlmName());
+ Assert.assertEquals("2", m.getArdenVersion());
+ Assert.assertEquals("1.00", m.getVersion());
+ Assert.assertEquals("Columbia-Presbyterian Medical Center", m.getInstitution());
+ Assert.assertEquals("George Hripcsak, M.D.(hripcsak@cucis.cis.columbia.edu)", m.getAuthor());
+ Assert.assertNull(m.getSpecialist());
+ Assert.assertEquals("testing", m.getValidation());
+
+ LibraryMetadata l = impl.getLibraryMetadata();
+ Assert.assertEquals(3, l.getKeywords().size());
+ Assert.assertEquals("fractional excretion", l.getKeywords().get(0));
+ Assert.assertEquals("serum sodium", l.getKeywords().get(1));
+ Assert.assertEquals("azotemia", l.getKeywords().get(2));
+ }
+
+ @Test
+ public void X23FromByteCode() throws Exception {
+ Compiler c = new Compiler();
+ CompiledMlm compiledMlm = c.compileMlm(new InputStreamReader(MetadataTests.class.getResourceAsStream("x2.3.mlm")));
+
+ ExecutionContext cx = new TestContext();
+
+ MedicalLogicModuleImplementation impl = compiledMlm.createInstance(cx, null);
+
+ MaintenanceMetadata m = impl.getMaintenanceMetadata();
+ Assert.assertEquals("Check for penicillin allergy", m.getTitle());
+ Assert.assertEquals("pen_allergy", m.getMlmName());
+ Assert.assertEquals("1", m.getArdenVersion());
+ Assert.assertEquals("1.00", m.getVersion());
+ Assert.assertEquals("Columbia-Presbyterian Medical Center", m.getInstitution());
+ Assert.assertEquals("George Hripcsak, M.D.", m.getAuthor());
+ Assert.assertNull(m.getSpecialist());
+ Assert.assertEquals("testing", m.getValidation());
+
+ LibraryMetadata l = impl.getLibraryMetadata();
+ Assert.assertEquals(2, l.getKeywords().size());
+ Assert.assertEquals("penicillin", l.getKeywords().get(0));
+ Assert.assertEquals("allergy", l.getKeywords().get(1));
+
+ Assert.assertEquals(42, impl.getPriority(), 0);
+ }
}
diff --git a/src/arden/tests/RuntimeTests.java b/src/arden/tests/RuntimeTests.java
new file mode 100644
index 0000000..2a06bfd
--- /dev/null
+++ b/src/arden/tests/RuntimeTests.java
@@ -0,0 +1,32 @@
+package arden.tests;
+
+import java.util.Comparator;
+
+import org.junit.Test;
+import org.junit.Assert;
+
+import arden.runtime.ArdenNumber;
+import arden.runtime.ArdenString;
+import arden.runtime.ArdenTime;
+
+public class RuntimeTests {
+ @Test
+ public void GetStringFromValue() throws Exception {
+ ArdenString string = new ArdenString("str");
+ Assert.assertEquals("str", ArdenString.getStringFromValue(string));
+ ArdenNumber number = new ArdenNumber(1.0);
+ Assert.assertEquals(null, ArdenString.getStringFromValue(number));
+ }
+
+ @Test
+ public void ArdenTimeComparatorTest() throws Exception {
+ ArdenTime t1 = new ArdenTime(2406808345L);
+ ArdenTime t2 = new ArdenTime(7575475677346L);
+ Assert.assertTrue(t1.compareTo(null) < 0);
+ Comparator c = new ArdenTime.NaturalComparator();
+ Assert.assertTrue(c.compare(t1, t2) < 0);
+ Assert.assertTrue(c.compare(t2, t1) > 0);
+ Assert.assertTrue(c.compare(t2, null) < 0);
+ Assert.assertTrue(c.compare(null, t2) > 0);
+ }
+}
diff --git a/src/arden/tests/TestContext.java b/src/arden/tests/TestContext.java
index 0d0ab90..194d155 100644
--- a/src/arden/tests/TestContext.java
+++ b/src/arden/tests/TestContext.java
@@ -28,13 +28,34 @@
package arden.tests;
import arden.runtime.ArdenString;
+import arden.runtime.ArdenTime;
import arden.runtime.ArdenValue;
import arden.runtime.DatabaseQuery;
import arden.runtime.ExecutionContext;
+import arden.runtime.events.EvokeEvent;
public class TestContext extends ExecutionContext {
StringBuilder b = new StringBuilder();
-
+ EvokeEvent defaultEvent = null;
+ ArdenTime defaultTime = null;
+
+ public TestContext() {
+
+ }
+
+ public TestContext(EvokeEvent defaultEvent) {
+ this.defaultEvent = defaultEvent;
+ }
+
+ public TestContext(EvokeEvent defaultEvent, ArdenTime defaultTime) {
+ this(defaultEvent);
+ this.defaultTime = defaultTime;
+ }
+
+ public TestContext(ArdenTime defaultTime) {
+ this.defaultTime = defaultTime;
+ }
+
@Override
public DatabaseQuery createQuery(String mapping) {
return DatabaseQuery.NULL;
@@ -49,4 +70,24 @@ public void write(ArdenValue message, String destination) {
public String getOutputText() {
return b.toString();
}
+
+ @Override
+ public EvokeEvent getEvent(String mapping) {
+ if (defaultEvent != null) {
+ return defaultEvent;
+ }
+ return super.getEvent(mapping);
+ }
+
+ @Override
+ public ArdenTime getCurrentTime() {
+ if (defaultTime != null) {
+ return defaultTime;
+ }
+ return super.getCurrentTime();
+ }
+
+ public void setCurrentTime(ArdenTime currentTime) {
+ defaultTime = currentTime;
+ }
}
diff --git a/src/ardenConstants.scc b/src/ardenConstants.scc
new file mode 100644
index 0000000..75fbc07
--- /dev/null
+++ b/src/ardenConstants.scc
@@ -0,0 +1,73 @@
+
+Package arden.constants;
+
+Helpers
+ ascii = [0..0x007f];
+
+ space = ' ';
+ tab = 0x0009;
+ lf = 0x000a;
+ cr = 0x000d;
+ wschar = space | tab | lf | cr;
+
+ input = [ascii - [cr + lf]];
+
+ digit = ['0'..'9'];
+ exp = ('e' | 'E') ('+' | '-')? digit+;
+
+ string_char = [input - '"'];
+
+ n = 'n' | 'N';
+ u = 'u' | 'U';
+ l = 'l' | 'L';
+ t = 't' | 'T';
+ r = 'r' | 'R';
+ e = 'e' | 'E';
+ f = 'f' | 'F';
+ a = 'a' | 'A';
+ s = 's' | 'S';
+
+Tokens
+
+ comma = ',';
+ l_par = '(';
+ r_par = ')';
+ null = n u l l;
+ true = t r u e;
+ false = f a l s e;
+
+ arden_number =
+ (digit+ ('.' digit*)? exp?)
+ | ('.' digit+ exp?);
+
+ arden_string =
+ '"' (
+ string_char* ('"' '"' string_char*)*
+ ) '"';
+
+ ws = wschar+;
+
+
+Ignored Tokens
+ ws;
+
+Productions
+
+ arden_constant = expr;
+
+ arden_boolean =
+ {true} true
+ | {false} false;
+
+ expr =
+ {atom} atom
+ | {listatom} comma atom
+ | {list} expr comma atom;
+
+ atom =
+ {number} arden_number
+ | {string} arden_string
+ | {boolean} arden_boolean
+ | {null} null
+ | {expr} l_par expr r_par
+ | {par} l_par r_par;
\ No newline at end of file