From 829cc83570ad929ec5f7736419ca221c8d671a21 Mon Sep 17 00:00:00 2001 From: hflicka Date: Thu, 4 Aug 2011 14:51:05 +0200 Subject: [PATCH 001/120] added alternate build option --- build.xml | 116 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 build.xml diff --git a/build.xml b/build.xml new file mode 100644 index 0000000..6b70625 --- /dev/null +++ b/build.xml @@ -0,0 +1,116 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @echo off + java -jar %~dp0${jar.filename} %* + pause + + + + + + + + + + + + + + + + + From 6252685ba03fe3286bcdd493942ac3f1feecb005 Mon Sep 17 00:00:00 2001 From: hflicka Date: Thu, 4 Aug 2011 14:51:24 +0200 Subject: [PATCH 002/120] added alternate build option --- .externalToolBuilders/SableCC.launch | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 .externalToolBuilders/SableCC.launch diff --git a/.externalToolBuilders/SableCC.launch b/.externalToolBuilders/SableCC.launch new file mode 100644 index 0000000..d14be05 --- /dev/null +++ b/.externalToolBuilders/SableCC.launch @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + From 209d4c834ef44ae2358df22c3dc0176686619f17 Mon Sep 17 00:00:00 2001 From: hflicka Date: Thu, 4 Aug 2011 14:55:16 +0200 Subject: [PATCH 003/120] added alternate build option --- .gitignore | 3 ++- .project | 10 ++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index c1a0fd5..b877388 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ /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 +/dist/ 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 From 5b54e1ca151eacdd59becebdd1f2546b8738d77c Mon Sep 17 00:00:00 2001 From: hflicka Date: Thu, 4 Aug 2011 16:14:30 +0200 Subject: [PATCH 004/120] made changes to build procedure --- .externalToolBuilders/SableCC.launch | 1 + build.xml | 27 ++++++++++++++++++++++----- src/arden/MainClass.java | 11 +++++++++-- 3 files changed, 32 insertions(+), 7 deletions(-) diff --git a/.externalToolBuilders/SableCC.launch b/.externalToolBuilders/SableCC.launch index d14be05..2ea516a 100644 --- a/.externalToolBuilders/SableCC.launch +++ b/.externalToolBuilders/SableCC.launch @@ -9,6 +9,7 @@ + diff --git a/build.xml b/build.xml index 6b70625..d340870 100644 --- a/build.xml +++ b/build.xml @@ -5,7 +5,7 @@ Author: hflicka --> - + @@ -40,20 +40,37 @@ + + + + + + + + - - + --> + + + + + + + + @@ -68,7 +85,7 @@ debug="${debug}" classpathref="build.classpath" optimize="${optimize}" - source="1.5"> + source="1.6"> @@ -92,7 +109,7 @@ @echo off java -jar %~dp0${jar.filename} %* - pause + rem pause diff --git a/src/arden/MainClass.java b/src/arden/MainClass.java index 7cfafdd..f2c090b 100644 --- a/src/arden/MainClass.java +++ b/src/arden/MainClass.java @@ -54,7 +54,7 @@ public static void main(String[] args) { compiler.enableDebugging(args[0]); mlm = compiler.compileMlm(new FileReader(args[0])); } catch (FileNotFoundException e) { - e.printStackTrace(); + System.err.println("error: File " + args[0] + " was not found."); return; } catch (CompilerException e) { e.printStackTrace(); @@ -62,6 +62,10 @@ public static void main(String[] args) { } catch (IOException e) { e.printStackTrace(); return; + } catch (ArrayIndexOutOfBoundsException e) { + System.err.println("error: No MLM source file given."); + System.err.println("usage: java -jar arden2bytecode.jar "); + return; } ExecutionContext context = new ExecutionContext() { @Override @@ -71,8 +75,11 @@ public void write(ArdenValue message, String destination) { }; try { ArdenValue[] result = mlm.run(context, null); - if (result != null && result.length == 1) + if (result != null && result.length == 1) { System.out.println("Return Value: " + result[0].toString()); + } else { + System.out.println("There was no return value or result length was not equal to 1."); + } } catch (InvocationTargetException e) { e.printStackTrace(); } From 4c44aa57db66708ba31b75f0586880cb8e54f490 Mon Sep 17 00:00:00 2001 From: hflicka Date: Thu, 4 Aug 2011 17:29:34 +0200 Subject: [PATCH 005/120] updated README to reflect current build process --- README | 34 +++++++++++++++++++++++++++------- src/arden/MainClass.java | 5 ++++- 2 files changed, 31 insertions(+), 8 deletions(-) diff --git a/README b/README index cb57ee9..07c99a3 100644 --- a/README +++ b/README @@ -1,8 +1,12 @@ +*** arden2bytecode - Compiler for Arden Syntax with Java Bytecode output. + Copyright 2009-2010, Daniel Grunwald Portions (arden.scc) Copyright 2004, University of British Columbia See LICENSE.txt for licensing information. +** Building Notes + To compile the compiler, you first need to generate the parser using the SableCC parser generator. To do this, run @@ -15,15 +19,31 @@ 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 compiler 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 compiler 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 -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. +** Notes to the present implementeation I believe this compiler fully implements Arden Syntax 2.5 with the following exceptions: diff --git a/src/arden/MainClass.java b/src/arden/MainClass.java index f2c090b..2b9c71f 100644 --- a/src/arden/MainClass.java +++ b/src/arden/MainClass.java @@ -64,7 +64,10 @@ public static void main(String[] args) { return; } catch (ArrayIndexOutOfBoundsException e) { System.err.println("error: No MLM source file given."); - System.err.println("usage: java -jar arden2bytecode.jar "); + System.err.println("usage: java "); + System.err.println(""); + System.err.println("e.g.: java -jar arden2bytecode.jar "); + System.err.println("or: java arden.MainClass "); return; } ExecutionContext context = new ExecutionContext() { From 8ddca9cf82cce8ebf1957a8fb4f16b7a65a7e77b Mon Sep 17 00:00:00 2001 From: hflicka Date: Fri, 5 Aug 2011 16:01:32 +0200 Subject: [PATCH 006/120] added compileOnly and jarOnly targets that have target 'init' as sole dependency --- build.xml | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/build.xml b/build.xml index d340870..140ae29 100644 --- a/build.xml +++ b/build.xml @@ -73,7 +73,7 @@ outputdirectory="${src.dir}"> - + @@ -89,8 +89,11 @@ - - + + + + + @@ -113,13 +116,19 @@ - + + + + + + + - + From 193ab957d5b30bde4f1269a0072db47ba03c6398 Mon Sep 17 00:00:00 2001 From: hflicka Date: Wed, 24 Aug 2011 15:38:45 +0200 Subject: [PATCH 007/120] added command line options --- lib/jewelcli-0.6.jar | Bin 0 -> 61072 bytes src/arden/CommandLineOptions.java | 49 ++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 lib/jewelcli-0.6.jar create mode 100644 src/arden/CommandLineOptions.java diff --git a/lib/jewelcli-0.6.jar b/lib/jewelcli-0.6.jar new file mode 100644 index 0000000000000000000000000000000000000000..17d6c6ed7f95e9053adcb0239df51f2976388ac8 GIT binary patch literal 61072 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

dCME2zWWaAANBJh?bE}-`h9t~%!UY$=CXJQ( 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 ZKfbk getInputFiles(); + boolean isInputFiles(); + + @Unparsed + List getFiles(); + boolean isFiles(); + + @Option(shortName = "o", + description = "Output file name to compile .MLM file to. You can also specify a directory e.g. in order to compile multiple MLMs.") + String getOutput(); + boolean isOutput(); + + @Option(shortName = "a", + description = "Arguments to MLM if running a MLM.") + String getArguments(); + boolean isArguments(); + + /* + @Option(shortName = "t", + defaultValue = "15", + description = "worker thread count (default = 15)") + int getThreadCount(); + + @Option(shortName = "l", + description = "log file name") + String getLogFile(); + boolean isLogFile();*/ +} From fe23cbb957f19895c631fee9a9cf81bae824e732 Mon Sep 17 00:00:00 2001 From: hflicka Date: Wed, 24 Aug 2011 15:40:02 +0200 Subject: [PATCH 008/120] added jewelcli lib to eclipse classpath --- .classpath | 1 + 1 file changed, 1 insertion(+) diff --git a/.classpath b/.classpath index b10b8d9..78dc779 100644 --- a/.classpath +++ b/.classpath @@ -3,5 +3,6 @@ + From 8624e31fe138101dc83ae114748a930872ea7611 Mon Sep 17 00:00:00 2001 From: hflicka Date: Wed, 24 Aug 2011 15:40:43 +0200 Subject: [PATCH 009/120] added jewelcli lib to build script --- build.xml | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/build.xml b/build.xml index 140ae29..3cf5ffa 100644 --- a/build.xml +++ b/build.xml @@ -3,7 +3,7 @@ Alternate build option for arden2bytecode. Used in Eclipse Project to launch SableCC. - Author: hflicka + Author: Hannes Flicka (hflicka@github) --> @@ -17,6 +17,7 @@ + @@ -24,7 +25,9 @@ - + + + @@ -108,6 +111,7 @@ + @echo off @@ -120,8 +124,8 @@ - - + + @@ -129,9 +133,9 @@ - + - + Date: Wed, 24 Aug 2011 15:41:02 +0200 Subject: [PATCH 010/120] updated LICENSE and README files --- LICENSE | 14 ++++++++++++++ README | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index 139deb6..5e040a3 100644 --- a/LICENSE +++ b/LICENSE @@ -1,3 +1,8 @@ +*** 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 @@ -10,6 +15,15 @@ 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 + + +** arden2bytecode License Text + GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 diff --git a/README b/README index 07c99a3..4c2b457 100644 --- a/README +++ b/README @@ -43,7 +43,7 @@ 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 implementeation +** Notes to the Present Implementeation I believe this compiler fully implements Arden Syntax 2.5 with the following exceptions: From 828163844e840b8b8295ef594d881ae0d7930e94 Mon Sep 17 00:00:00 2001 From: hflicka Date: Wed, 24 Aug 2011 16:13:18 +0200 Subject: [PATCH 011/120] tried to enable loading of mlms --- src/arden/MainClass.java | 114 +++++++++++++++- src/arden/compiler/RawCompiledMlm.java | 180 +++++++++++++++++++++++++ 2 files changed, 291 insertions(+), 3 deletions(-) create mode 100644 src/arden/compiler/RawCompiledMlm.java diff --git a/src/arden/MainClass.java b/src/arden/MainClass.java index 2b9c71f..eb2804a 100644 --- a/src/arden/MainClass.java +++ b/src/arden/MainClass.java @@ -27,27 +27,134 @@ package arden; +import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.lang.reflect.InvocationTargetException; +import java.util.LinkedList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import uk.co.flamingpenguin.jewel.cli.ArgumentValidationException; +import uk.co.flamingpenguin.jewel.cli.CliFactory; -import arden.compiler.CompiledMlm; import arden.compiler.Compiler; import arden.compiler.CompilerException; +import arden.compiler.RawCompiledMlm; import arden.runtime.ArdenValue; import arden.runtime.ExecutionContext; +import arden.runtime.MedicalLogicModule; public class MainClass { + private final static Pattern JAVA_CLASS_NAME = + Pattern.compile("[A-Za-z$_][A-Za-z0-9$_]*(?:\\.[A-Za-z$_][A-Za-z0-9$_]*)*"); + + private final static Pattern MLM_NAME_MATCHER = + Pattern.compile("(?:[A-Za-z$_][A-Za-z0-9$_]*\\.)*([A-Za-z$_][A-Za-z0-9$_]*)\\.class"); + public static void main(String[] args) { - System.out.println("arden2bytecode Interpreter example"); - System.out.println("Copyright 2010 Daniel Grunwald"); + System.out.println("arden2bytecode Compiler"); + System.out.println("Copyright 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(""); + System.out.println("Supply argument -h or -? to display help."); + System.out.println(""); + + List inputFiles = new LinkedList(); + + CommandLineOptions options = null; + try { + options = CliFactory.parseArguments(CommandLineOptions.class, args); + } catch (ArgumentValidationException e) { + System.err.println(e.getMessage()); + System.exit(1); + } + // check input files to this compiler + for (String filePath : options.getFiles()) { + File file = new File(filePath); + if (file.exists()) { + inputFiles.add(file); + } else { + Matcher m = JAVA_CLASS_NAME.matcher(filePath); + if (m.matches()) { + inputFiles.add(new File("." + + File.separatorChar + + filePath.replace('.', File.separatorChar) + + ".class")); + } + } + } + + if (options.getRun()) { + if (inputFiles.size() != 1) { + System.err.println("You should specify exactly one " + + "MLM or compiled MLM .class file when " + + "trying to run an MLM."); + System.exit(1); + } + File fileToRun = inputFiles.get(0); + MedicalLogicModule mlmToRun = null; + if (fileToRun.getName().endsWith(".class")) { + // TODO: load class with ClassLoader + Matcher m = MLM_NAME_MATCHER.matcher(fileToRun.getName()); + if (!m.matches()) { + String mlmname = m.group(); + try { + mlmToRun = new RawCompiledMlm(fileToRun, mlmname); + } catch (IOException e) { + System.err.println("Error loading " + + fileToRun.getName()); + e.printStackTrace(); + } + } + } else if (fileToRun.getName().endsWith(".mlm")) { + Compiler compiler = new Compiler(); + try { + compiler.enableDebugging(fileToRun.getPath()); + mlmToRun = compiler.compileMlm(new FileReader(fileToRun.getPath())); + } catch (CompilerException e) { + System.err.println("exception compiling " + fileToRun.getPath() + ":"); + e.printStackTrace(); + System.exit(1); + } catch (FileNotFoundException e) { + System.err.println("file not found: " + fileToRun.getPath()); + e.printStackTrace(); + System.exit(1); + } catch (IOException e) { + System.err.println("IO error reading: " + fileToRun.getPath()); + e.printStackTrace(); + System.exit(1); + } + } + ExecutionContext context = new ExecutionContext() { + @Override + public void write(ArdenValue message, String destination) { + System.out.println(message.toString()); + } + }; + + try { + ArdenValue[] result = mlmToRun.run(context, null); + if (result != null && result.length == 1) { + System.out.println("Return Value: " + result[0].toString()); + } else { + System.out.println("There was no return value or result length was not equal to 1."); + } + } catch (InvocationTargetException e) { + e.printStackTrace(); + } + } else { + // TODO: handle other options + } + + + /* Compiler compiler = new Compiler(); CompiledMlm mlm; try { @@ -86,5 +193,6 @@ public void write(ArdenValue message, String destination) { } catch (InvocationTargetException e) { e.printStackTrace(); } + */ } } diff --git a/src/arden/compiler/RawCompiledMlm.java b/src/arden/compiler/RawCompiledMlm.java new file mode 100644 index 0000000..3960dc0 --- /dev/null +++ b/src/arden/compiler/RawCompiledMlm.java @@ -0,0 +1,180 @@ +// 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 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.runtime.ArdenList; +import arden.runtime.ArdenValue; +import arden.runtime.ExecutionContext; +import arden.runtime.LibraryMetadata; +import arden.runtime.MaintenanceMetadata; +import arden.runtime.MedicalLogicModule; +import arden.runtime.MedicalLogicModuleImplementation; + +/** + * 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, Hannes Flicka + * + */ +public final class RawCompiledMlm implements MedicalLogicModule { + private final byte[] data; + private final String mlmname; + private Constructor ctor; + + RawCompiledMlm(byte[] data, String mlmname) { + if (mlmname == null) + throw new NullPointerException(); + this.data = data; + this.mlmname = mlmname; + } + + public RawCompiledMlm(File mlmfile, String mlmname) throws IOException { + this((byte[])null, mlmname); + loadClassFile(mlmfile); + } + + public void saveClassFile(OutputStream os) throws IOException { + os.write(data); + } + + public void loadClassFile(File file) throws IOException { + loadClassFile( + new BufferedInputStream( + new FileInputStream(file))); + } + + public void loadClassFile(InputStream in, int len) throws IOException { + in.read(data, 0, len); + } + + public void loadClassFile(InputStream in) throws IOException { + in.read(data); + } + + @SuppressWarnings("unchecked") + private synchronized Constructor getConstructor() { + if (ctor == null) { + Class clazz; + try { + ClassLoader classLoader = new InMemoryClassLoader(mlmname, data); + clazz = (Class) 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 ctor; + } + + /** Creates an instance of the implementation class. */ + @Override + public MedicalLogicModuleImplementation createInstance(ExecutionContext context, ArdenValue[] arguments) + throws InvocationTargetException { + if (context == null) + throw new NullPointerException(); + + if (arguments == null) + arguments = ArdenList.EMPTY.values; + + try { + return getConstructor().newInstance(context, this, arguments); + } catch (IllegalArgumentException e) { + throw new RuntimeException(e); + } catch (InstantiationException e) { + throw new RuntimeException(e); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + /** + * Executes the MLM. + * + * @return Returns the value(s) provided by the "return" statement, or + * (Java) null if no return statement was executed. + */ + @Override + public ArdenValue[] run(ExecutionContext context, ArdenValue[] arguments) throws InvocationTargetException { + MedicalLogicModuleImplementation impl = createInstance(context, arguments); + try { + if (impl.logic(context)) + return impl.action(context); + else + return null; + } catch (Exception ex) { + throw new InvocationTargetException(ex); + } + } + + @Override + public MaintenanceMetadata getMaintenance() { + return null; + } + + @Override + public LibraryMetadata getLibrary() { + return null; + } + + @Override + public String getName() { + return mlmname; + } + + @Override + public double getPriority() { + return -1.0; + } +} From ca88cd3fe9f330f3397001fcfe5b9820d023cd02 Mon Sep 17 00:00:00 2001 From: hflicka Date: Wed, 24 Aug 2011 17:27:44 +0200 Subject: [PATCH 012/120] tried to enable running class files --- build.xml | 2 +- src/arden/MainClass.java | 70 ++++++++++++++++++++------ src/arden/compiler/RawCompiledMlm.java | 12 ++--- 3 files changed, 62 insertions(+), 22 deletions(-) diff --git a/build.xml b/build.xml index 3cf5ffa..77f8248 100644 --- a/build.xml +++ b/build.xml @@ -114,7 +114,7 @@ - @echo off + @echo off java -jar %~dp0${jar.filename} %* rem pause diff --git a/src/arden/MainClass.java b/src/arden/MainClass.java index eb2804a..fa5c243 100644 --- a/src/arden/MainClass.java +++ b/src/arden/MainClass.java @@ -52,8 +52,9 @@ public class MainClass { private final static Pattern JAVA_CLASS_NAME = Pattern.compile("[A-Za-z$_][A-Za-z0-9$_]*(?:\\.[A-Za-z$_][A-Za-z0-9$_]*)*"); - private final static Pattern MLM_NAME_MATCHER = + private final static Pattern MLM_CLASS_FILE_NAME_MATCHER = Pattern.compile("(?:[A-Za-z$_][A-Za-z0-9$_]*\\.)*([A-Za-z$_][A-Za-z0-9$_]*)\\.class"); + //Pattern.compile("([A-Za-z$_][A-Za-z0-9$_]*)\\.class"); public static void main(String[] args) { System.out.println("arden2bytecode Compiler"); @@ -62,8 +63,6 @@ public static void main(String[] args) { 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(""); - System.out.println("Supply argument -h or -? to display help."); - System.out.println(""); List inputFiles = new LinkedList(); @@ -74,22 +73,41 @@ public static void main(String[] args) { System.err.println(e.getMessage()); System.exit(1); } - // check input files to this compiler - for (String filePath : options.getFiles()) { + + // 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 + if (!options.isInputFiles()) { + System.err.println("No input files given."); + System.exit(1); + } + List files = options.getInputFiles(); + for (String filePath : files) { File file = new File(filePath); if (file.exists()) { inputFiles.add(file); } else { Matcher m = JAVA_CLASS_NAME.matcher(filePath); if (m.matches()) { - inputFiles.add(new File("." + - File.separatorChar + + inputFiles.add(new File( filePath.replace('.', File.separatorChar) + ".class")); + } else { + System.err.println("File \"" + filePath + + "\" is neither an existing file " + + "nor a valid class name."); } } } + for (File f : inputFiles) { + System.out.println("input file: " + f.getPath()); + } + if (options.getRun()) { if (inputFiles.size() != 1) { System.err.println("You should specify exactly one " + @@ -98,25 +116,36 @@ public static void main(String[] args) { System.exit(1); } File fileToRun = inputFiles.get(0); - MedicalLogicModule mlmToRun = null; + MedicalLogicModule mlm = null; if (fileToRun.getName().endsWith(".class")) { // TODO: load class with ClassLoader - Matcher m = MLM_NAME_MATCHER.matcher(fileToRun.getName()); - if (!m.matches()) { - String mlmname = m.group(); + Matcher m = MLM_CLASS_FILE_NAME_MATCHER.matcher(fileToRun.getName()); + if (m.matches()) { + String mlmname = m.group(1); try { - mlmToRun = new RawCompiledMlm(fileToRun, mlmname); + mlm = new RawCompiledMlm(fileToRun, mlmname); } catch (IOException e) { System.err.println("Error loading " + - fileToRun.getName()); + fileToRun.getPath()); e.printStackTrace(); + System.exit(1); } + if (mlm == null) { + System.err.println("Could not load " + + fileToRun.getPath()); + System.exit(1); + } + } else { + System.err.println("File \"" + + fileToRun.getName() + + "\" has invalid name."); + System.exit(1); } } else if (fileToRun.getName().endsWith(".mlm")) { Compiler compiler = new Compiler(); try { compiler.enableDebugging(fileToRun.getPath()); - mlmToRun = compiler.compileMlm(new FileReader(fileToRun.getPath())); + mlm = compiler.compileMlm(new FileReader(fileToRun.getPath())); } catch (CompilerException e) { System.err.println("exception compiling " + fileToRun.getPath() + ":"); e.printStackTrace(); @@ -130,6 +159,11 @@ public static void main(String[] args) { e.printStackTrace(); System.exit(1); } + } else { + System.err.println("File \"" + fileToRun.getPath() + + "\" is neither .class nor .mlm file."); + System.err.println("Can't run such a file."); + System.exit(1); } ExecutionContext context = new ExecutionContext() { @@ -140,7 +174,7 @@ public void write(ArdenValue message, String destination) { }; try { - ArdenValue[] result = mlmToRun.run(context, null); + ArdenValue[] result = mlm.run(context, null); if (result != null && result.length == 1) { System.out.println("Return Value: " + result[0].toString()); } else { @@ -151,6 +185,12 @@ public void write(ArdenValue message, String destination) { } } else { // TODO: handle other options + System.err.println(""); + System.err.println("You should specify -r to run the files."); + System.err.println(""); + System.err.println("Specifying files without an option is not implemented."); + System.err.println(""); + System.exit(1); } diff --git a/src/arden/compiler/RawCompiledMlm.java b/src/arden/compiler/RawCompiledMlm.java index 3960dc0..5506ca3 100644 --- a/src/arden/compiler/RawCompiledMlm.java +++ b/src/arden/compiler/RawCompiledMlm.java @@ -60,7 +60,7 @@ * */ public final class RawCompiledMlm implements MedicalLogicModule { - private final byte[] data; + private byte[] data; private final String mlmname; private Constructor ctor; @@ -73,6 +73,8 @@ public final class RawCompiledMlm implements MedicalLogicModule { public RawCompiledMlm(File mlmfile, String mlmname) throws IOException { this((byte[])null, mlmname); + System.err.println("mlm: " + mlmfile.getPath()); + System.err.println("mlmname: " + mlmname); loadClassFile(mlmfile); } @@ -83,16 +85,14 @@ public void saveClassFile(OutputStream os) throws IOException { public void loadClassFile(File file) throws IOException { loadClassFile( new BufferedInputStream( - new FileInputStream(file))); + new FileInputStream(file)), + (int)(file.length())); } public void loadClassFile(InputStream in, int len) throws IOException { + data = new byte[len]; in.read(data, 0, len); } - - public void loadClassFile(InputStream in) throws IOException { - in.read(data); - } @SuppressWarnings("unchecked") private synchronized Constructor getConstructor() { From 35d3cac39f6ab93e64ed1e7b228b5e7b5af74970 Mon Sep 17 00:00:00 2001 From: hflicka Date: Wed, 7 Sep 2011 18:00:01 +0200 Subject: [PATCH 013/120] got command line interface to work. implemented options -r (run) and -c (compile) --- build.xml | 3 + src/arden/CommandLineOptions.java | 12 +- src/arden/MainClass.java | 352 +++++++++++++++---------- src/arden/compiler/RawCompiledMlm.java | 4 +- 4 files changed, 227 insertions(+), 144 deletions(-) diff --git a/build.xml b/build.xml index 77f8248..7407cf2 100644 --- a/build.xml +++ b/build.xml @@ -123,6 +123,9 @@ + + + diff --git a/src/arden/CommandLineOptions.java b/src/arden/CommandLineOptions.java index e6e5153..28d9115 100644 --- a/src/arden/CommandLineOptions.java +++ b/src/arden/CommandLineOptions.java @@ -12,15 +12,23 @@ public interface CommandLineOptions { 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(helpRequest = true, description = "display help", shortName = {"h", "?"}) boolean getHelp(); - @Option(shortName = "f", + /*@Option(shortName = "f", description = "input files (MLM files or MLM class files)") List getInputFiles(); - boolean isInputFiles(); + boolean isInputFiles();*/ @Unparsed List getFiles(); diff --git a/src/arden/MainClass.java b/src/arden/MainClass.java index fa5c243..4389ac4 100644 --- a/src/arden/MainClass.java +++ b/src/arden/MainClass.java @@ -27,8 +27,10 @@ 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; @@ -40,6 +42,7 @@ import uk.co.flamingpenguin.jewel.cli.ArgumentValidationException; import uk.co.flamingpenguin.jewel.cli.CliFactory; +import arden.compiler.CompiledMlm; import arden.compiler.Compiler; import arden.compiler.CompilerException; import arden.compiler.RawCompiledMlm; @@ -56,46 +59,33 @@ public class MainClass { Pattern.compile("(?:[A-Za-z$_][A-Za-z0-9$_]*\\.)*([A-Za-z$_][A-Za-z0-9$_]*)\\.class"); //Pattern.compile("([A-Za-z$_][A-Za-z0-9$_]*)\\.class"); - public static void main(String[] args) { - System.out.println("arden2bytecode Compiler"); - System.out.println("Copyright 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 final static Pattern CLASS_NAME_FROM_MLM_FILENAME = + Pattern.compile("([A-Za-z$_][A-Za-z0-9$_]*)\\.[mM][lL][mM]"); + + private static List handleInputFileNames(List filenames) { List inputFiles = new LinkedList(); - - CommandLineOptions options = null; - try { - options = CliFactory.parseArguments(CommandLineOptions.class, args); - } catch (ArgumentValidationException e) { - System.err.println(e.getMessage()); - System.exit(1); + if ((filenames == null) || filenames.isEmpty()) { + return null; } - - // 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 - if (!options.isInputFiles()) { - System.err.println("No input files given."); - System.exit(1); - } - List files = options.getInputFiles(); - for (String filePath : files) { + 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()) { - inputFiles.add(new File( - filePath.replace('.', File.separatorChar) + - ".class")); + String classFileName = + filePath.replace('.', File.separatorChar) + + ".class"; + File classFile = new File(classFileName); + if (classFile.exists()) { + inputFiles.add(classFile); + } else { + System.err.println("Class file " + classFileName + + " does not exist."); + } } else { System.err.println("File \"" + filePath + "\" is neither an existing file " @@ -103,128 +93,46 @@ public static void main(String[] args) { } } } - - for (File f : inputFiles) { - System.out.println("input file: " + f.getPath()); - } - - if (options.getRun()) { - if (inputFiles.size() != 1) { - System.err.println("You should specify exactly one " + - "MLM or compiled MLM .class file when " + - "trying to run an MLM."); - System.exit(1); - } - File fileToRun = inputFiles.get(0); - MedicalLogicModule mlm = null; - if (fileToRun.getName().endsWith(".class")) { - // TODO: load class with ClassLoader - Matcher m = MLM_CLASS_FILE_NAME_MATCHER.matcher(fileToRun.getName()); - if (m.matches()) { - String mlmname = m.group(1); - try { - mlm = new RawCompiledMlm(fileToRun, mlmname); - } catch (IOException e) { - System.err.println("Error loading " + - fileToRun.getPath()); - e.printStackTrace(); - System.exit(1); - } - if (mlm == null) { - System.err.println("Could not load " + - fileToRun.getPath()); - System.exit(1); - } - } else { - System.err.println("File \"" - + fileToRun.getName() - + "\" has invalid name."); - System.exit(1); - } - } else if (fileToRun.getName().endsWith(".mlm")) { - Compiler compiler = new Compiler(); - try { - compiler.enableDebugging(fileToRun.getPath()); - mlm = compiler.compileMlm(new FileReader(fileToRun.getPath())); - } catch (CompilerException e) { - System.err.println("exception compiling " + fileToRun.getPath() + ":"); - e.printStackTrace(); - System.exit(1); - } catch (FileNotFoundException e) { - System.err.println("file not found: " + fileToRun.getPath()); - e.printStackTrace(); - System.exit(1); - } catch (IOException e) { - System.err.println("IO error reading: " + fileToRun.getPath()); - e.printStackTrace(); - System.exit(1); - } - } else { - System.err.println("File \"" + fileToRun.getPath() - + "\" is neither .class nor .mlm file."); - System.err.println("Can't run such a file."); - System.exit(1); - } - - ExecutionContext context = new ExecutionContext() { - @Override - public void write(ArdenValue message, String destination) { - System.out.println(message.toString()); - } - }; - - try { - ArdenValue[] result = mlm.run(context, null); - if (result != null && result.length == 1) { - System.out.println("Return Value: " + result[0].toString()); - } else { - System.out.println("There was no return value or result length was not equal to 1."); - } - } catch (InvocationTargetException e) { - e.printStackTrace(); - } - } else { - // TODO: handle other options - System.err.println(""); - System.err.println("You should specify -r to run the files."); - System.err.println(""); - System.err.println("Specifying files without an option is not implemented."); - System.err.println(""); - System.exit(1); + return inputFiles; + } + + private static CompiledMlm compileMlm(File mlmfile, CommandLineOptions options) { + 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) { - System.err.println("error: File " + args[0] + " was not found."); - 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; - } catch (ArrayIndexOutOfBoundsException e) { - System.err.println("error: No MLM source file given."); - System.err.println("usage: java "); - System.err.println(""); - System.err.println("e.g.: java -jar arden2bytecode.jar "); - System.err.println("or: java arden.MainClass "); - return; + System.exit(1); } + return mlm; + } + + private static ArdenValue[] runMlm(MedicalLogicModule mlm, CommandLineOptions options) { ExecutionContext context = new ExecutionContext() { @Override public void write(ArdenValue message, String destination) { System.out.println(message.toString()); } }; + + ArdenValue[] result = null; try { - ArdenValue[] result = mlm.run(context, null); + result = mlm.run(context, null); if (result != null && result.length == 1) { System.out.println("Return Value: " + result[0].toString()); } else { @@ -233,6 +141,170 @@ public void write(ArdenValue message, String destination) { } catch (InvocationTargetException e) { e.printStackTrace(); } - */ + return result; + } + + private static int runInputFile(File fileToRun, CommandLineOptions options) { + String filename = fileToRun.getName(); + MedicalLogicModule mlm = null; + if (filename.endsWith(".class")) { + // TODO: load class with ClassLoader (does not work yet) + + // the following pattern matches the class name without packages as group 1 + // e.g. given the string "java.util.List.class", "List" would be matched as group 1 + Matcher m = MLM_CLASS_FILE_NAME_MATCHER.matcher(filename); + if (m.matches()) { + String mlmname = m.group(1); + try { + mlm = new RawCompiledMlm(fileToRun, mlmname); + } catch (IOException e) { + System.err.println("Error loading " + + fileToRun.getPath()); + e.printStackTrace(); + return 1; + } + } else { + System.err.println("File \"" + + fileToRun.getName() + + "\" has invalid name."); + return 1; + } + } else if (fileToRun.getName().endsWith(".mlm")) { + mlm = compileMlm(fileToRun, options); + } else { + System.err.println("File \"" + fileToRun.getPath() + + "\" is neither .class nor .mlm file."); + System.err.println("Can't run such a file."); + return 1; + } + + if (options.getVerbose()) { + System.out.println("Running MLM..."); + System.out.println(""); + } + + ArdenValue[] result = runMlm(mlm, options); + + return 0; + } + + private static int compileInputFiles(List inputFiles, CommandLineOptions options) { + boolean firstFile = true; + for (File fileToCompile : inputFiles) { + CompiledMlm mlm = compileMlm(fileToCompile, options); + File outputFile = null; + if (options.isOutput() && firstFile) { + outputFile = new File(options.getOutput()); + } else { + String filename = fileToCompile.getName(); + Matcher m = CLASS_NAME_FROM_MLM_FILENAME.matcher(filename); + if (m.matches()) { + String assumedName = m.group(1) + ".class"; + File assumed = new File(fileToCompile.getParentFile(), assumedName); + if (firstFile) { + System.err.println("warning: File " + fileToCompile.getName() + + " compiled, but no output file given. Assuming " + + assumed.getPath() + + " as output file."); + } else { + System.err.println("warning: File " + fileToCompile.getName() + + " compiled, but can't write to same output file again. " + + "Assuming " + + assumed.getPath() + + " as output file."); + } + outputFile = assumed; + } else { + System.err.println("File " + fileToCompile.getName() + + " compiled, but does not seem to name an MLM file." + + " Can't figure out file to write to."); + } + } + + 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 int handleCommandLineArgs(String[] args) { + // parse command line using jewelCli + CommandLineOptions options = null; + try { + options = CliFactory.parseArguments(CommandLineOptions.class, args); + } catch (ArgumentValidationException e) { + System.err.println(e.getMessage()); + return 1; + } + + // 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 (options.getVerbose()) { + for (File f : inputFiles) { + System.out.println("input file: " + f.getPath()); + } + System.out.println(""); + } + + 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) { + return runInputFile(fileToRun, options); + } + } else if (options.getCompile()) { + return compileInputFiles(inputFiles, options); + } else { + // TODO: handle other options + System.err.println(""); + System.err.println("You should specify -r to run the files or -c to compile the files."); + System.err.println(""); + System.err.println("Specifying files without an option is not implemented."); + System.err.println(""); + System.exit(1); + } + + return 0; + } + + public static void main(String[] args) { + System.out.println("arden2bytecode Compiler"); + 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(""); + + int returnValue = handleCommandLineArgs(args); + + System.exit(returnValue); } } diff --git a/src/arden/compiler/RawCompiledMlm.java b/src/arden/compiler/RawCompiledMlm.java index 5506ca3..833c6f5 100644 --- a/src/arden/compiler/RawCompiledMlm.java +++ b/src/arden/compiler/RawCompiledMlm.java @@ -73,8 +73,8 @@ public final class RawCompiledMlm implements MedicalLogicModule { public RawCompiledMlm(File mlmfile, String mlmname) throws IOException { this((byte[])null, mlmname); - System.err.println("mlm: " + mlmfile.getPath()); - System.err.println("mlmname: " + mlmname); + //System.err.println("mlm: " + mlmfile.getPath()); + //System.err.println("mlmname: " + mlmname); loadClassFile(mlmfile); } From 8fb081f4d121e422465371b0eea7998dc97a5564 Mon Sep 17 00:00:00 2001 From: hflicka Date: Wed, 7 Sep 2011 18:03:11 +0200 Subject: [PATCH 014/120] renamed RawCompiledMlm to LoadableCompiledMlm --- src/arden/compiler/LoadableCompiledMlm.java | 180 ++++++++++++++++++++ 1 file changed, 180 insertions(+) create mode 100644 src/arden/compiler/LoadableCompiledMlm.java diff --git a/src/arden/compiler/LoadableCompiledMlm.java b/src/arden/compiler/LoadableCompiledMlm.java new file mode 100644 index 0000000..b62f4c2 --- /dev/null +++ b/src/arden/compiler/LoadableCompiledMlm.java @@ -0,0 +1,180 @@ +// 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 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.runtime.ArdenList; +import arden.runtime.ArdenValue; +import arden.runtime.ExecutionContext; +import arden.runtime.LibraryMetadata; +import arden.runtime.MaintenanceMetadata; +import arden.runtime.MedicalLogicModule; +import arden.runtime.MedicalLogicModuleImplementation; + +/** + * 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, Hannes Flicka + * + */ +public final class LoadableCompiledMlm implements MedicalLogicModule { + private byte[] data; + private final String mlmname; + private Constructor ctor; + + LoadableCompiledMlm(byte[] data, String mlmname) { + if (mlmname == null) + throw new NullPointerException(); + this.data = data; + this.mlmname = mlmname; + } + + public LoadableCompiledMlm(File mlmfile, String mlmname) throws IOException { + this((byte[])null, mlmname); + //System.err.println("mlm: " + mlmfile.getPath()); + //System.err.println("mlmname: " + mlmname); + loadClassFile(mlmfile); + } + + public void saveClassFile(OutputStream os) throws IOException { + os.write(data); + } + + public void loadClassFile(File file) throws IOException { + loadClassFile( + new BufferedInputStream( + new FileInputStream(file)), + (int)(file.length())); + } + + public void loadClassFile(InputStream in, int len) throws IOException { + data = new byte[len]; + in.read(data, 0, len); + } + + @SuppressWarnings("unchecked") + private synchronized Constructor getConstructor() { + if (ctor == null) { + Class clazz; + try { + ClassLoader classLoader = new InMemoryClassLoader(mlmname, data); + clazz = (Class) 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 ctor; + } + + /** Creates an instance of the implementation class. */ + @Override + public MedicalLogicModuleImplementation createInstance(ExecutionContext context, ArdenValue[] arguments) + throws InvocationTargetException { + if (context == null) + throw new NullPointerException(); + + if (arguments == null) + arguments = ArdenList.EMPTY.values; + + try { + return getConstructor().newInstance(context, this, arguments); + } catch (IllegalArgumentException e) { + throw new RuntimeException(e); + } catch (InstantiationException e) { + throw new RuntimeException(e); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + /** + * Executes the MLM. + * + * @return Returns the value(s) provided by the "return" statement, or + * (Java) null if no return statement was executed. + */ + @Override + public ArdenValue[] run(ExecutionContext context, ArdenValue[] arguments) throws InvocationTargetException { + MedicalLogicModuleImplementation impl = createInstance(context, arguments); + try { + if (impl.logic(context)) + return impl.action(context); + else + return null; + } catch (Exception ex) { + throw new InvocationTargetException(ex); + } + } + + @Override + public MaintenanceMetadata getMaintenance() { + return null; + } + + @Override + public LibraryMetadata getLibrary() { + return null; + } + + @Override + public String getName() { + return mlmname; + } + + @Override + public double getPriority() { + return -1.0; + } +} From b5401064995cb6e5c560204a6eeacf286b2c86ca Mon Sep 17 00:00:00 2001 From: hflicka Date: Wed, 7 Sep 2011 18:03:26 +0200 Subject: [PATCH 015/120] renamed RawCompiledMlm to LoadableCompiledMlm --- src/arden/MainClass.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/arden/MainClass.java b/src/arden/MainClass.java index 4389ac4..2cafcfd 100644 --- a/src/arden/MainClass.java +++ b/src/arden/MainClass.java @@ -45,7 +45,7 @@ import arden.compiler.CompiledMlm; import arden.compiler.Compiler; import arden.compiler.CompilerException; -import arden.compiler.RawCompiledMlm; +import arden.compiler.LoadableCompiledMlm; import arden.runtime.ArdenValue; import arden.runtime.ExecutionContext; import arden.runtime.MedicalLogicModule; @@ -156,7 +156,7 @@ private static int runInputFile(File fileToRun, CommandLineOptions options) { if (m.matches()) { String mlmname = m.group(1); try { - mlm = new RawCompiledMlm(fileToRun, mlmname); + mlm = new LoadableCompiledMlm(fileToRun, mlmname); } catch (IOException e) { System.err.println("Error loading " + fileToRun.getPath()); From 36cc05ff3b9e7da5be39111cdb4a5bc6449584e0 Mon Sep 17 00:00:00 2001 From: hflicka Date: Wed, 7 Sep 2011 18:53:02 +0200 Subject: [PATCH 016/120] minor fixes --- src/arden/MainClass.java | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/src/arden/MainClass.java b/src/arden/MainClass.java index 2cafcfd..b97e675 100644 --- a/src/arden/MainClass.java +++ b/src/arden/MainClass.java @@ -245,7 +245,15 @@ private static int handleCommandLineArgs(String[] args) { try { options = CliFactory.parseArguments(CommandLineOptions.class, args); } catch (ArgumentValidationException e) { - System.err.println(e.getMessage()); + 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 files."); + System.err.println(""); + } + return 1; } @@ -253,7 +261,7 @@ private static int handleCommandLineArgs(String[] args) { 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(); @@ -278,16 +286,19 @@ private static int handleCommandLineArgs(String[] args) { return 1; } for (File fileToRun : inputFiles) { - return runInputFile(fileToRun, options); + int result = runInputFile(fileToRun, options); + if (result != 0) { + return result; + } } } else if (options.getCompile()) { return compileInputFiles(inputFiles, options); } else { // TODO: handle other options - System.err.println(""); - System.err.println("You should specify -r to run the files or -c to compile the files."); - System.err.println(""); - System.err.println("Specifying files without an option is not implemented."); + 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."); System.err.println(""); System.exit(1); } From 6b141e7b665ed751dd03e9258a9cb4254ccd0871 Mon Sep 17 00:00:00 2001 From: hflicka Date: Wed, 7 Sep 2011 18:53:48 +0200 Subject: [PATCH 017/120] fixed ant build. as JUnit is not included, tests will not be built. --- build.xml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/build.xml b/build.xml index 7407cf2..c67d428 100644 --- a/build.xml +++ b/build.xml @@ -88,8 +88,10 @@ debug="${debug}" classpathref="build.classpath" optimize="${optimize}" - source="1.6"> + source="1.6" + includeantruntime="false"> + From c11b08cfbe5c7d9bce6d7d065ca31030304fc2bb Mon Sep 17 00:00:00 2001 From: hflicka Date: Wed, 7 Sep 2011 18:54:08 +0200 Subject: [PATCH 018/120] minor fixes --- src/arden/compiler/LoadableCompiledMlm.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/arden/compiler/LoadableCompiledMlm.java b/src/arden/compiler/LoadableCompiledMlm.java index b62f4c2..ca2af50 100644 --- a/src/arden/compiler/LoadableCompiledMlm.java +++ b/src/arden/compiler/LoadableCompiledMlm.java @@ -73,6 +73,7 @@ public final class LoadableCompiledMlm implements MedicalLogicModule { public LoadableCompiledMlm(File mlmfile, String mlmname) throws IOException { this((byte[])null, mlmname); + // for debugging reasons: //System.err.println("mlm: " + mlmfile.getPath()); //System.err.println("mlmname: " + mlmname); loadClassFile(mlmfile); From 040e2c5881968f015eaca7e4a242ec4594503745 Mon Sep 17 00:00:00 2001 From: hflicka Date: Wed, 7 Sep 2011 18:54:31 +0200 Subject: [PATCH 019/120] renamed RawCompiledMlm to LoadableCompiledMlm --- src/arden/compiler/RawCompiledMlm.java | 180 ------------------------- 1 file changed, 180 deletions(-) delete mode 100644 src/arden/compiler/RawCompiledMlm.java diff --git a/src/arden/compiler/RawCompiledMlm.java b/src/arden/compiler/RawCompiledMlm.java deleted file mode 100644 index 833c6f5..0000000 --- a/src/arden/compiler/RawCompiledMlm.java +++ /dev/null @@ -1,180 +0,0 @@ -// 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 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.runtime.ArdenList; -import arden.runtime.ArdenValue; -import arden.runtime.ExecutionContext; -import arden.runtime.LibraryMetadata; -import arden.runtime.MaintenanceMetadata; -import arden.runtime.MedicalLogicModule; -import arden.runtime.MedicalLogicModuleImplementation; - -/** - * 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, Hannes Flicka - * - */ -public final class RawCompiledMlm implements MedicalLogicModule { - private byte[] data; - private final String mlmname; - private Constructor ctor; - - RawCompiledMlm(byte[] data, String mlmname) { - if (mlmname == null) - throw new NullPointerException(); - this.data = data; - this.mlmname = mlmname; - } - - public RawCompiledMlm(File mlmfile, String mlmname) throws IOException { - this((byte[])null, mlmname); - //System.err.println("mlm: " + mlmfile.getPath()); - //System.err.println("mlmname: " + mlmname); - loadClassFile(mlmfile); - } - - public void saveClassFile(OutputStream os) throws IOException { - os.write(data); - } - - public void loadClassFile(File file) throws IOException { - loadClassFile( - new BufferedInputStream( - new FileInputStream(file)), - (int)(file.length())); - } - - public void loadClassFile(InputStream in, int len) throws IOException { - data = new byte[len]; - in.read(data, 0, len); - } - - @SuppressWarnings("unchecked") - private synchronized Constructor getConstructor() { - if (ctor == null) { - Class clazz; - try { - ClassLoader classLoader = new InMemoryClassLoader(mlmname, data); - clazz = (Class) 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 ctor; - } - - /** Creates an instance of the implementation class. */ - @Override - public MedicalLogicModuleImplementation createInstance(ExecutionContext context, ArdenValue[] arguments) - throws InvocationTargetException { - if (context == null) - throw new NullPointerException(); - - if (arguments == null) - arguments = ArdenList.EMPTY.values; - - try { - return getConstructor().newInstance(context, this, arguments); - } catch (IllegalArgumentException e) { - throw new RuntimeException(e); - } catch (InstantiationException e) { - throw new RuntimeException(e); - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } - } - - /** - * Executes the MLM. - * - * @return Returns the value(s) provided by the "return" statement, or - * (Java) null if no return statement was executed. - */ - @Override - public ArdenValue[] run(ExecutionContext context, ArdenValue[] arguments) throws InvocationTargetException { - MedicalLogicModuleImplementation impl = createInstance(context, arguments); - try { - if (impl.logic(context)) - return impl.action(context); - else - return null; - } catch (Exception ex) { - throw new InvocationTargetException(ex); - } - } - - @Override - public MaintenanceMetadata getMaintenance() { - return null; - } - - @Override - public LibraryMetadata getLibrary() { - return null; - } - - @Override - public String getName() { - return mlmname; - } - - @Override - public double getPriority() { - return -1.0; - } -} From 41f84d020ba82db18f67a592f32062cb7b74346f Mon Sep 17 00:00:00 2001 From: hflicka Date: Wed, 7 Sep 2011 19:34:00 +0200 Subject: [PATCH 020/120] added a class loader for mlms stored as .class file --- .../AnonymousInMemoryClassLoader.java | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 src/arden/compiler/AnonymousInMemoryClassLoader.java diff --git a/src/arden/compiler/AnonymousInMemoryClassLoader.java b/src/arden/compiler/AnonymousInMemoryClassLoader.java new file mode 100644 index 0000000..d270176 --- /dev/null +++ b/src/arden/compiler/AnonymousInMemoryClassLoader.java @@ -0,0 +1,51 @@ +// 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; + +/** + * ClassLoader used for loading the compiled classes without having to save them + * to disk. + * + * @author Daniel Grunwald + */ +final class AnonymousInMemoryClassLoader extends ClassLoader { + byte[] data; + Class loadedClass; + + public AnonymousInMemoryClassLoader(byte[] data) { + this.data = data; + } + + protected synchronized Class findClass(String name) throws ClassNotFoundException { + if (loadedClass == null) { + loadedClass = defineClass(null, data, 0, data.length); + data = null; + } + return loadedClass; + } +} From d39ffa9ddefcbca4da29f6d9c6e9f39f9ffc6c42 Mon Sep 17 00:00:00 2001 From: hflicka Date: Wed, 7 Sep 2011 19:34:31 +0200 Subject: [PATCH 021/120] implemented loading of .class files with wrong name --- src/arden/MainClass.java | 27 ++++++--------------- src/arden/compiler/LoadableCompiledMlm.java | 19 +++++++-------- 2 files changed, 17 insertions(+), 29 deletions(-) diff --git a/src/arden/MainClass.java b/src/arden/MainClass.java index b97e675..6b73752 100644 --- a/src/arden/MainClass.java +++ b/src/arden/MainClass.java @@ -60,7 +60,7 @@ public class MainClass { //Pattern.compile("([A-Za-z$_][A-Za-z0-9$_]*)\\.class"); private final static Pattern CLASS_NAME_FROM_MLM_FILENAME = - Pattern.compile("([A-Za-z$_][A-Za-z0-9$_]*)\\.[mM][lL][mM]"); + Pattern.compile("([A-Za-z$_][A-Za-z0-9$_\\.]*)\\.[mM][lL][mM]"); private static List handleInputFileNames(List filenames) { List inputFiles = new LinkedList(); @@ -149,24 +149,13 @@ private static int runInputFile(File fileToRun, CommandLineOptions options) { MedicalLogicModule mlm = null; if (filename.endsWith(".class")) { // TODO: load class with ClassLoader (does not work yet) - - // the following pattern matches the class name without packages as group 1 - // e.g. given the string "java.util.List.class", "List" would be matched as group 1 - Matcher m = MLM_CLASS_FILE_NAME_MATCHER.matcher(filename); - if (m.matches()) { - String mlmname = m.group(1); - try { - mlm = new LoadableCompiledMlm(fileToRun, mlmname); - } catch (IOException e) { - System.err.println("Error loading " + - fileToRun.getPath()); - e.printStackTrace(); - return 1; - } - } else { - System.err.println("File \"" - + fileToRun.getName() - + "\" has invalid name."); + + try { + mlm = new LoadableCompiledMlm(fileToRun); + } catch (IOException e) { + System.err.println("Error loading " + + fileToRun.getPath()); + e.printStackTrace(); return 1; } } else if (fileToRun.getName().endsWith(".mlm")) { diff --git a/src/arden/compiler/LoadableCompiledMlm.java b/src/arden/compiler/LoadableCompiledMlm.java index ca2af50..e6c7374 100644 --- a/src/arden/compiler/LoadableCompiledMlm.java +++ b/src/arden/compiler/LoadableCompiledMlm.java @@ -61,18 +61,16 @@ */ public final class LoadableCompiledMlm implements MedicalLogicModule { private byte[] data; - private final String mlmname; + private String mlmname; private Constructor ctor; - LoadableCompiledMlm(byte[] data, String mlmname) { - if (mlmname == null) - throw new NullPointerException(); + LoadableCompiledMlm(byte[] data) { this.data = data; - this.mlmname = mlmname; + this.mlmname = null; } - public LoadableCompiledMlm(File mlmfile, String mlmname) throws IOException { - this((byte[])null, mlmname); + public LoadableCompiledMlm(File mlmfile) throws IOException { + this((byte[])null); // for debugging reasons: //System.err.println("mlm: " + mlmfile.getPath()); //System.err.println("mlmname: " + mlmname); @@ -100,8 +98,9 @@ private synchronized Constructor get if (ctor == null) { Class clazz; try { - ClassLoader classLoader = new InMemoryClassLoader(mlmname, data); - clazz = (Class) classLoader.loadClass(mlmname); + ClassLoader classLoader = new AnonymousInMemoryClassLoader(data); + clazz = (Class) classLoader.loadClass(""); + mlmname = clazz.getName(); } catch (ClassNotFoundException e) { throw new RuntimeException(e); } @@ -176,6 +175,6 @@ public String getName() { @Override public double getPriority() { - return -1.0; + return Double.NaN; } } From 26f06fbc6eb99e61da1a1d916d959f02e26ea15c Mon Sep 17 00:00:00 2001 From: hflicka Date: Thu, 8 Sep 2011 13:19:49 +0200 Subject: [PATCH 022/120] added unix shell script for jar build --- build.xml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/build.xml b/build.xml index c67d428..5675d45 100644 --- a/build.xml +++ b/build.xml @@ -119,7 +119,11 @@ @echo off java -jar %~dp0${jar.filename} %* rem pause - + + #!/bin/sh + java -jar $( cd -P "$( dirname "$0" )" && pwd )${jar.filename} $@ + + From 0810071b794cc3593885017d46519129f5bf9322 Mon Sep 17 00:00:00 2001 From: hflicka Date: Thu, 8 Sep 2011 13:24:51 +0200 Subject: [PATCH 023/120] fixes to unix startup script --- build.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.xml b/build.xml index 5675d45..0c0e5b4 100644 --- a/build.xml +++ b/build.xml @@ -121,7 +121,7 @@ rem pause #!/bin/sh - java -jar $( cd -P "$( dirname "$0" )" && pwd )${jar.filename} $@ + java -jar "$( cd -P "$( dirname "$0" )" && pwd )/${jar.filename}" $@ From 397a1025fd18b4fd3b5bdcad4e6222e94be1c3a1 Mon Sep 17 00:00:00 2001 From: hflicka Date: Thu, 8 Sep 2011 13:40:19 +0200 Subject: [PATCH 024/120] added descriptions to ant targets --- build.xml | 45 ++++++++++++++++++++++++++++++++------------- 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/build.xml b/build.xml index 0c0e5b4..9ea554e 100644 --- a/build.xml +++ b/build.xml @@ -5,10 +5,15 @@ Author: Hannes Flicka (hflicka@github) --> - - + + arden2bytecode ant build script. + + + - + @@ -40,7 +45,8 @@ - + @@ -57,7 +63,8 @@ - + - - - - - - + + + + + + + + + + + - + + + + From 0d07fc7bb2689bf5ffc05c5e648e2ec91e8df67c Mon Sep 17 00:00:00 2001 From: Hannes Flicka Date: Fri, 14 Sep 2012 15:49:41 +0200 Subject: [PATCH 103/120] pulled new version ov examples --- resource/examples | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resource/examples b/resource/examples index be736e0..65ec65e 160000 --- a/resource/examples +++ b/resource/examples @@ -1 +1 @@ -Subproject commit be736e0091015bed5566625f85a0d280b2d0d2ef +Subproject commit 65ec65e90c0c68b8323bc133d25e660d24c62663 From 23e20259bd03b7f4c9b54d2483dce741aaaa6bd7 Mon Sep 17 00:00:00 2001 From: hflicka Date: Sun, 16 Sep 2012 17:11:18 +0200 Subject: [PATCH 104/120] changed file not found notification --- src/arden/MainClass.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/arden/MainClass.java b/src/arden/MainClass.java index c8d330f..f062371 100644 --- a/src/arden/MainClass.java +++ b/src/arden/MainClass.java @@ -87,8 +87,8 @@ private static List handleInputFileNames(List filenames) { if (classFile.exists()) { inputFiles.add(classFile); } else { - System.err.println("Class file " + classFileName - + " does not exist."); + System.err.println("File " + filePath + " and class file " + classFileName + + " do not exist."); } } else { System.err.println("File \"" + filePath From 97a8e4e314d5aea0b9e02df7074f05323685fbc5 Mon Sep 17 00:00:00 2001 From: hflicka Date: Mon, 17 Sep 2012 16:27:20 +0200 Subject: [PATCH 105/120] added guessing of mlmname frm filename to CompiledMlm --- src/arden/compiler/CompiledMlm.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/arden/compiler/CompiledMlm.java b/src/arden/compiler/CompiledMlm.java index d116545..e963c8c 100644 --- a/src/arden/compiler/CompiledMlm.java +++ b/src/arden/compiler/CompiledMlm.java @@ -36,6 +36,7 @@ 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; @@ -80,9 +81,9 @@ public CompiledMlm(InputStream in, String mlmname) throws IOException { public CompiledMlm(File mlmfile, String mlmname) throws IOException { this((byte[]) null, mlmname); - // for debugging reasons: - //System.err.println("mlm: " + mlmfile.getPath()); - //System.err.println("mlmname: " + mlmname); + if (this.mlmname == null) { + this.mlmname = MainClass.getFilenameBase(mlmfile.getName()); + } loadClassFile(mlmfile); this.mlmname = getName(); } From 631cb9a4e877369c861aefaede0d178e3f717370 Mon Sep 17 00:00:00 2001 From: hflicka Date: Mon, 17 Sep 2012 16:34:06 +0200 Subject: [PATCH 106/120] switched to master --- resource/examples | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resource/examples b/resource/examples index 65ec65e..32dffcf 160000 --- a/resource/examples +++ b/resource/examples @@ -1 +1 @@ -Subproject commit 65ec65e90c0c68b8323bc133d25e660d24c62663 +Subproject commit 32dffcfb81b9c2ad66cc1f39aade59a3c406e2dc From da797a281a107fbd10867839601fd6f19d34d725 Mon Sep 17 00:00:00 2001 From: hflicka Date: Tue, 18 Sep 2012 00:24:55 +0200 Subject: [PATCH 107/120] fixed build script to create sablecc directories when not existing --- build.xml | 263 +++++++++++++++++++++++++++++------------------------- 1 file changed, 140 insertions(+), 123 deletions(-) diff --git a/build.xml b/build.xml index 5c63da8..b4131d2 100644 --- a/build.xml +++ b/build.xml @@ -6,16 +6,16 @@ Author: Hannes Flicka (hflicka@github) --> - arden2bytecode ant build script. - + arden2bytecode ant build script. + + description="default target, depends on 'jar' which means a binary jar file will be built."> + description="initializes used variables, mostly paths and directories"> - + @@ -24,7 +24,7 @@ - + @@ -45,94 +45,111 @@ - - - - - - - - - - - - + + + + + + + + + + + + + + - + + + + + + + + + + + + - - - - - - - - - - - + + + - - - + + + - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + description="compile all .java files in ./src except for tests"> - - - - - + + + + + + includeantruntime="false"> - + - - - - + + + + + description="generate .jar bundle from compiled files without actually compiling the sources"> @@ -147,74 +164,74 @@ - - + + @echo off java -jar "%~dp0${jar.filename}" %* rem pause - #!/bin/sh - java -jar "$( cd -P "$( dirname "$0" )" && pwd )/${jar.filename}" "$@" - - + #!/bin/sh + java -jar "$( cd -P "$( dirname "$0" )" && pwd )/${jar.filename}" "$@" + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + description="run the program from the bin directory"> - - - + + + + description="run the program and redirect output to 'output.txt'"> From 8b5fde9a2b0aba600bbf91af20d59cc28b179b34 Mon Sep 17 00:00:00 2001 From: Hannes Flicka Date: Wed, 19 Sep 2012 16:12:33 +0200 Subject: [PATCH 108/120] trying to implement access to mlm variables via a fixed function in generated .class files --- src/arden/runtime/MedicalLogicModuleImplementation.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/arden/runtime/MedicalLogicModuleImplementation.java b/src/arden/runtime/MedicalLogicModuleImplementation.java index 229b4a9..2b39300 100644 --- a/src/arden/runtime/MedicalLogicModuleImplementation.java +++ b/src/arden/runtime/MedicalLogicModuleImplementation.java @@ -27,6 +27,8 @@ package arden.runtime; +import java.lang.reflect.Field; + import arden.runtime.events.EvokeEvent; import arden.runtime.events.UndefinedEvokeEvent; @@ -59,7 +61,7 @@ public double getUrgency() { } /** Gets the maintenance metadata - * (not declared abstract to stay downwards compatible with exiting MLMs) */ + * (not declared abstract to stay downwards compatible with existing MLMs) */ public MaintenanceMetadata getMaintenanceMetadata() { return null; } @@ -78,6 +80,9 @@ public double getPriority() { return RuntimeHelpers.DEFAULT_PRIORITY; } + /** + * Gets the event when this MLM should be invoked + */ public EvokeEvent getEvokeEvent(ExecutionContext context) { return new UndefinedEvokeEvent(); } From b4d7b717f3745c9a79c3a00d5fe21bb09d4b0af7 Mon Sep 17 00:00:00 2001 From: Hannes Flicka Date: Wed, 19 Sep 2012 16:13:01 +0200 Subject: [PATCH 109/120] trying to implement access to mlm variables via a fixed function in generated .class files --- src/arden/codegenerator/ExceptionTable.java | 51 +++++++++++++++++++++ src/arden/tests/test.java | 49 ++++++++++++++++++++ 2 files changed, 100 insertions(+) create mode 100644 src/arden/codegenerator/ExceptionTable.java create mode 100644 src/arden/tests/test.java 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 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/tests/test.java b/src/arden/tests/test.java new file mode 100644 index 0000000..3169d83 --- /dev/null +++ b/src/arden/tests/test.java @@ -0,0 +1,49 @@ +package arden.tests; + +import java.lang.reflect.Field; + +import arden.runtime.ArdenString; +import arden.runtime.ArdenValue; +import arden.runtime.ExecutionContext; +import arden.runtime.MedicalLogicModuleImplementation; + +public class test { + public static class Mlm extends MedicalLogicModuleImplementation { + + private ArdenValue p1 = new ArdenString("abc"); + private ArdenString p2 = new ArdenString("def"); + + public Mlm(ExecutionContext context, ArdenValue[] args) { + + } + + @Override + public boolean logic(ExecutionContext context) { + // TODO Auto-generated method stub + return false; + } + + @Override + public ArdenValue[] action(ExecutionContext context) { + // TODO Auto-generated method stub + return null; + } + + public ArdenValue getValue(String id) { + Field field; + try { + field = this.getClass().getDeclaredField(id); + return (ArdenValue) field.get(this); + } catch (SecurityException e) { + } catch (NoSuchFieldException e) { + } catch (IllegalArgumentException e) { + } catch (IllegalAccessException e) { + } + return null; + } + } + + public static void main(String args[]) { + System.out.println(new Mlm(null, null).getValue("p1")); + } +} From 38113f3f401ac084957158a315541ab4cffaf301 Mon Sep 17 00:00:00 2001 From: Hannes Flicka Date: Mon, 1 Oct 2012 17:15:55 +0200 Subject: [PATCH 110/120] added methods to enable exception handling in generated methods --- src/arden/codegenerator/MethodWriter.java | 33 ++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) 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 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() { From 9d8ecc9b66750a0262e5435d124fc2def42ec0db Mon Sep 17 00:00:00 2001 From: Hannes Flicka Date: Mon, 1 Oct 2012 17:17:12 +0200 Subject: [PATCH 111/120] added method to read variables declared in a MLM --- src/arden/compiler/CodeGenerator.java | 59 +++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/src/arden/compiler/CodeGenerator.java b/src/arden/compiler/CodeGenerator.java index 53ef1e5..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; @@ -275,6 +276,64 @@ public CompilerContext createEvokeEvent() { 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) { From dc9bac916dc7abdf78347302b9f947f9787e9b71 Mon Sep 17 00:00:00 2001 From: Hannes Flicka Date: Mon, 1 Oct 2012 17:17:39 +0200 Subject: [PATCH 112/120] calling createGetValue() in doCompile() --- src/arden/compiler/Compiler.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/arden/compiler/Compiler.java b/src/arden/compiler/Compiler.java index a776291..564b10d 100644 --- a/src/arden/compiler/Compiler.java +++ b/src/arden/compiler/Compiler.java @@ -164,6 +164,8 @@ private CompiledMlm doCompileMlm(AMlm mlm) { throw new RuntimeException(e); } + codeGen.createGetValue(); + byte[] data; try { ByteArrayOutputStream bos = new ByteArrayOutputStream(); From f9d6f0e89cb4b120a50149ca3a6f8a83beee8f89 Mon Sep 17 00:00:00 2001 From: Hannes Flicka Date: Mon, 1 Oct 2012 17:18:16 +0200 Subject: [PATCH 113/120] added method to get variables declared in a MLM to MLM interface --- src/arden/runtime/MedicalLogicModule.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/arden/runtime/MedicalLogicModule.java b/src/arden/runtime/MedicalLogicModule.java index d83565f..913d779 100644 --- a/src/arden/runtime/MedicalLogicModule.java +++ b/src/arden/runtime/MedicalLogicModule.java @@ -60,4 +60,11 @@ MedicalLogicModuleImplementation createInstance(ExecutionContext context, ArdenV /** 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); } From 68c96a7af1c8dc217a8354054d1d8537f25f942d Mon Sep 17 00:00:00 2001 From: Hannes Flicka Date: Mon, 1 Oct 2012 17:19:00 +0200 Subject: [PATCH 114/120] added method to get MLM variables which is intended to be overridden by generated MLM code --- .../runtime/MedicalLogicModuleImplementation.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/arden/runtime/MedicalLogicModuleImplementation.java b/src/arden/runtime/MedicalLogicModuleImplementation.java index 2b39300..aeeab00 100644 --- a/src/arden/runtime/MedicalLogicModuleImplementation.java +++ b/src/arden/runtime/MedicalLogicModuleImplementation.java @@ -27,8 +27,6 @@ package arden.runtime; -import java.lang.reflect.Field; - import arden.runtime.events.EvokeEvent; import arden.runtime.events.UndefinedEvokeEvent; @@ -86,4 +84,12 @@ public double getPriority() { 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; + } } From e6afbd62eca707a3edc02faa57ca5831473ba969 Mon Sep 17 00:00:00 2001 From: Hannes Flicka Date: Mon, 1 Oct 2012 17:20:48 +0200 Subject: [PATCH 115/120] added method to get a MLM variable value from a MLM instance created before --- src/arden/compiler/CompiledMlm.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/arden/compiler/CompiledMlm.java b/src/arden/compiler/CompiledMlm.java index e963c8c..1723c10 100644 --- a/src/arden/compiler/CompiledMlm.java +++ b/src/arden/compiler/CompiledMlm.java @@ -65,6 +65,7 @@ public final class CompiledMlm implements MedicalLogicModule { private byte[] data; Class clazz = null; private MedicalLogicModuleImplementation uninitializedInstance = null; + private MedicalLogicModuleImplementation initializedInstance = null; private EvokeEvent evokeEvent = null; private String mlmname; @@ -180,6 +181,7 @@ public MedicalLogicModuleImplementation createInstance(ExecutionContext context, @Override public ArdenValue[] run(ExecutionContext context, ArdenValue[] arguments) throws InvocationTargetException { MedicalLogicModuleImplementation instance = createInstance(context, arguments); + initializedInstance = instance; try { if (instance.logic(context)) return instance.action(context); @@ -239,10 +241,19 @@ public double getPriority() { @Override public EvokeEvent getEvoke(ExecutionContext context, ArdenValue[] arguments) throws InvocationTargetException { if (evokeEvent == null) { - MedicalLogicModuleImplementation instance = createInstance(context, arguments); + 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; + } } From 6dcb57d5ed1a17979a29949a0eb1f17a9dc02538 Mon Sep 17 00:00:00 2001 From: Hannes Flicka Date: Mon, 1 Oct 2012 17:21:18 +0200 Subject: [PATCH 116/120] added tests for MedicalLogicModule.getValue(String) --- src/arden/tests/GetValueTests.java | 52 ++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 src/arden/tests/GetValueTests.java diff --git a/src/arden/tests/GetValueTests.java b/src/arden/tests/GetValueTests.java new file mode 100644 index 0000000..06fbd7a --- /dev/null +++ b/src/arden/tests/GetValueTests.java @@ -0,0 +1,52 @@ +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.ArdenBoolean; +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")); + } +} From 8afc4514d59c8b4921a7728e8b8e87e75caa78f7 Mon Sep 17 00:00:00 2001 From: Hannes Flicka Date: Mon, 1 Oct 2012 17:21:44 +0200 Subject: [PATCH 117/120] deleted proposal code that is not needed anymore --- src/arden/tests/test.java | 49 --------------------------------------- 1 file changed, 49 deletions(-) delete mode 100644 src/arden/tests/test.java diff --git a/src/arden/tests/test.java b/src/arden/tests/test.java deleted file mode 100644 index 3169d83..0000000 --- a/src/arden/tests/test.java +++ /dev/null @@ -1,49 +0,0 @@ -package arden.tests; - -import java.lang.reflect.Field; - -import arden.runtime.ArdenString; -import arden.runtime.ArdenValue; -import arden.runtime.ExecutionContext; -import arden.runtime.MedicalLogicModuleImplementation; - -public class test { - public static class Mlm extends MedicalLogicModuleImplementation { - - private ArdenValue p1 = new ArdenString("abc"); - private ArdenString p2 = new ArdenString("def"); - - public Mlm(ExecutionContext context, ArdenValue[] args) { - - } - - @Override - public boolean logic(ExecutionContext context) { - // TODO Auto-generated method stub - return false; - } - - @Override - public ArdenValue[] action(ExecutionContext context) { - // TODO Auto-generated method stub - return null; - } - - public ArdenValue getValue(String id) { - Field field; - try { - field = this.getClass().getDeclaredField(id); - return (ArdenValue) field.get(this); - } catch (SecurityException e) { - } catch (NoSuchFieldException e) { - } catch (IllegalArgumentException e) { - } catch (IllegalAccessException e) { - } - return null; - } - } - - public static void main(String args[]) { - System.out.println(new Mlm(null, null).getValue("p1")); - } -} From 5db6b41e880ba8e14b098488528fb32d75b760ae Mon Sep 17 00:00:00 2001 From: Hannes Flicka Date: Mon, 1 Oct 2012 17:30:20 +0200 Subject: [PATCH 118/120] organized imports --- src/arden/tests/GetValueTests.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/arden/tests/GetValueTests.java b/src/arden/tests/GetValueTests.java index 06fbd7a..1949d18 100644 --- a/src/arden/tests/GetValueTests.java +++ b/src/arden/tests/GetValueTests.java @@ -7,7 +7,6 @@ import arden.compiler.CompiledMlm; import arden.compiler.Compiler; -import arden.runtime.ArdenBoolean; import arden.runtime.ArdenNumber; import arden.runtime.ArdenValue; import arden.runtime.MedicalLogicModule; From a783dc8fb662f20bb47451ab27528466c177474d Mon Sep 17 00:00:00 2001 From: Hannes Flicka Date: Mon, 1 Oct 2012 17:32:41 +0200 Subject: [PATCH 119/120] updated submodule --- resource/examples | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resource/examples b/resource/examples index 32dffcf..57da760 160000 --- a/resource/examples +++ b/resource/examples @@ -1 +1 @@ -Subproject commit 32dffcfb81b9c2ad66cc1f39aade59a3c406e2dc +Subproject commit 57da7600adcd46f0f8e1194e81e8303d7fbf2674 From c20ec355c9b6a95f06ef4ab02de3b7617bc20f71 Mon Sep 17 00:00:00 2001 From: Hannes Flicka Date: Tue, 2 Oct 2012 17:00:48 +0200 Subject: [PATCH 120/120] split up cleaning of classes and other generated files --- build.xml | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/build.xml b/build.xml index b4131d2..841f8bb 100644 --- a/build.xml +++ b/build.xml @@ -72,12 +72,18 @@ - + - + + + + + + @@ -130,6 +136,7 @@ +