Coverage Report - org.webslinger.bsf.groovy.GroovyCompiler
 
Classes in this File Line Coverage Branch Coverage Complexity
GroovyCompiler
89%
90/101
100%
14/14
0
GroovyCompiler$GroovyCompilerContext
100%
3/3
N/A
0
GroovyCompiler$NameEncoder
100%
5/5
100%
1/1
0
 
 1  
 package org.webslinger.bsf.groovy;
 2  
 
 3  
 import java.util.HashMap;
 4  
 import java.util.regex.Pattern;
 5  
 import java.util.regex.Matcher;
 6  
 
 7  
 import org.apache.bsf.BSFDeclaredBean;
 8  
 import org.apache.bsf.BSFException;
 9  
 
 10  
 import groovy.lang.GroovyClassLoader;
 11  
 
 12  
 import org.webslinger.bsf.ApplyKey;
 13  
 import org.webslinger.bsf.Compiler;
 14  
 import org.webslinger.bsf.EvalKey;
 15  
 import org.webslinger.bsf.ExecKey;
 16  
 import org.webslinger.bsf.Key;
 17  
 import org.webslinger.util.GeneratedResult;
 18  
 
 19  9
 public final class GroovyCompiler extends Compiler<Object, Class<? extends Object>> {
 20  1
     protected static final Pattern singleLineCommentPattern = Pattern.compile("^(//(?ms:[^\\r\\n]*$))((?ms).*)");
 21  1
     protected static final Pattern multiLineCommentPattern = Pattern.compile("^(?ms:(/\\*.*?\\*/))((?ms).*)");
 22  1
     protected static final Pattern whitespacePattern = Pattern.compile("^((?ms:\\s+))((?ms).*)");
 23  1
     protected static final Pattern importPattern = Pattern.compile("^import\\b((?ms).*)");
 24  1
     protected static final Pattern identifierPattern = Pattern.compile("^([a-zA-Z0-9_]+)\\b((?ms).*)");
 25  
 
 26  1
     protected static final HashMap<Class, Class> implementsMap = new HashMap<Class, Class>();
 27  
     static {
 28  1
         implementsMap.put(ApplyKey.class, GroovyApply.class);
 29  1
     }
 30  
 
 31  
     public class GroovyCompilerContext extends CompilerContext {
 32  
         protected StringBuilder imports;
 33  
 
 34  3
         protected GroovyCompilerContext(Key<Class<? extends Object>> key) throws BSFException {
 35  3
             super(key);
 36  3
         }
 37  
     }
 38  
 
 39  3
     public static class NameEncoder extends Compiler.NameEncoder {
 40  
         public void encodeChar(StringBuilder target, char c, boolean isStart) {
 41  70
             if (c != '_' && (isStart ? Character.isJavaIdentifierStart(c) : Character.isJavaIdentifierPart(c))) {
 42  63
                 target.append(c);
 43  
             } else {
 44  7
                 target.append('_').append((int) c).append('_');
 45  
             }
 46  70
         }
 47  
     }
 48  
 
 49  
     public GroovyCompiler(GroovyEngine engine) {
 50  3
         super(engine, new NameEncoder());
 51  3
     }
 52  
 
 53  
     protected String filter(CompilerContext context, String text) throws BSFException {
 54  3
         return filter((GroovyCompilerContext) context, text);
 55  
     }
 56  
 
 57  
     protected String filterComments(StringBuilder sb, String text) {
 58  
         while (true) {
 59  25
             Matcher matcher = singleLineCommentPattern.matcher(text);
 60  25
             if (matcher.matches()) {
 61  1
                 sb.append(matcher.group(1));
 62  1
                 text = matcher.group(2);
 63  1
                 continue;
 64  
             }
 65  24
             matcher = multiLineCommentPattern.matcher(text);
 66  24
             if (matcher.matches()) {
 67  1
                 sb.append(matcher.group(1));
 68  1
                 text = matcher.group(2);
 69  1
                 continue;
 70  
             }
 71  
             break;
 72  
         }
 73  23
         return text;
 74  
     }
 75  
 
 76  
     protected String filterSkippable(StringBuilder sb, String text) {
 77  
         while (true) {
 78  21
             text = filterComments(sb, text);
 79  21
             Matcher matcher = whitespacePattern.matcher(text);
 80  21
             if (!matcher.matches()) break;
 81  4
             sb.append(matcher.group(1));
 82  4
             text = matcher.group(2);
 83  4
         }
 84  17
         return text;
 85  
     }
 86  
 
 87  
     protected String filter(GroovyCompilerContext context, String text) throws BSFException {
 88  3
         StringBuilder sb = new StringBuilder();
 89  
         while (true) {
 90  5
             text = filterSkippable(sb, text);
 91  5
             Matcher matcher = importPattern.matcher(text);
 92  5
             if (!matcher.matches()) break;
 93  2
             StringBuilder importSb = new StringBuilder();
 94  2
             importSb.append("import");
 95  2
             text = filterComments(importSb, matcher.group(1));
 96  2
             matcher = whitespacePattern.matcher(text);
 97  2
             if (!matcher.matches()) throw new BSFException("Bad groovy file(missing whitespace after import)");
 98  2
             importSb.append(matcher.group(1));
 99  2
             text = filterSkippable(importSb, matcher.group(2));
 100  2
             matcher = identifierPattern.matcher(text);
 101  2
             if (!matcher.matches()) throw new BSFException("Bad groovy file(missing identifier part after import)");
 102  2
             importSb.append(matcher.group(1));
 103  2
             text = matcher.group(2);
 104  
             while (true) {
 105  6
                 text = filterSkippable(importSb, text);
 106  6
                 if (!text.startsWith(".")) break;
 107  4
                 importSb.append('.');
 108  4
                 matcher = identifierPattern.matcher(text.substring(1));
 109  4
                 if (!matcher.matches()) throw new BSFException("Bad groovy file(missing identifier part after . in import)");
 110  4
                 importSb.append(matcher.group(1));
 111  4
                 text = matcher.group(2);
 112  
             }
 113  
             while (true) {
 114  4
                 text = filterSkippable(importSb, text);
 115  4
                 if (!text.startsWith(";")) break;
 116  2
                 importSb.append(';');
 117  2
                 text = text.substring(1);
 118  
             }
 119  2
             sb.append(importSb);
 120  2
         }
 121  3
         context.imports = sb;
 122  3
         return text;
 123  
     }
 124  
 
 125  
     public void declareBean(BSFDeclaredBean bean) throws BSFException {
 126  
         //interp.set(bean.name, bean.bean);
 127  0
     }
 128  
 
 129  
     public void undeclareBean(BSFDeclaredBean bean) throws BSFException {
 130  
         //interp.set(bean.name, null);
 131  0
     }
 132  
 
 133  
     protected CompilerContext newContext(Key<Class<? extends Object>> key) throws BSFException {
 134  3
         return new GroovyCompilerContext(key);
 135  
     }
 136  
 
 137  
     protected Class<? extends Object> compile(CompilerContext context) throws Throwable {
 138  3
         return compile((GroovyCompilerContext) context);
 139  
     }
 140  
 
 141  
     protected Class<? extends Object> compile(GroovyCompilerContext context) throws Throwable {
 142  3
         String fileName = engine.getVFSDelegate().absolutePath(context.key.getId());
 143  3
         StringBuilder classNameBuffer = new StringBuilder();
 144  3
         nameEncoder.encodeName(classNameBuffer, fileName);
 145  
 
 146  3
         StringBuilder code = context.code;
 147  3
         code.append(context.imports);
 148  3
         code.append("public class ").append(classNameBuffer);
 149  3
         Class implementsClass = implementsMap.get(context.key.getClass());
 150  3
         if (implementsClass != null) code.append(" implements ").append(implementsClass.getName());
 151  3
         code.append(" {");
 152  3
         super.compile(context);
 153  3
         code.append('}');
 154  3
         if (engine.isDebugOn()) System.err.println(code);
 155  3
         GroovyClassLoader loader = new GroovyClassLoader(getEngine().getManager().getClassLoader());
 156  3
         Class<?> clz = loader.parseClass(code.toString(), fileName);
 157  3
         return clz.asSubclass(Object.class);
 158  
     }
 159  
 
 160  
     protected Object init(CompilerContext context, Class<? extends Object> compiled) throws Throwable {
 161  3
         return compiled.newInstance();
 162  
     }
 163  
 
 164  
     public Class<? extends Object> compileKey(ApplyKey<Class<? extends Object>> key, CompilerContext context) throws BSFException {
 165  3
         StringBuilder code = context.code;
 166  3
         code.append("public Object apply(org.apache.bsf.BSFManager bsf, Object[] args) throws Exception {");
 167  3
         String[] names = key.getNames();
 168  3
         Class[] types = key.getTypes();
 169  12
         for (int i = 0; i < types.length; i++) {
 170  9
             if (i != 0) code.append(' ');
 171  9
             Class type = types[i];
 172  
             String typeName, prefix, postfix;
 173  9
             code.append(type != null ? type.getName() : "Object").append(' ').append(names[i]);
 174  9
             code.append(" = args[").append(i).append("];");
 175  
         }
 176  3
         appendText(code, "", context.text);
 177  3
         code.append("}");
 178  3
         return null;
 179  
     }
 180  
 
 181  
     public Class<? extends Object> compileKey(EvalKey<Class<? extends Object>> key, CompilerContext context) throws BSFException {
 182  
         //context.code.append("():\n");
 183  0
         StringBuilder code = context.code;
 184  0
         code.append("public Object eval(BSFManager bsf) throws Exception {");
 185  0
         appendText(context.code, "", context.text);
 186  0
         return null;
 187  
     }
 188  
 
 189  
     public Class<? extends Object> compileKey(ExecKey<Class<? extends Object>> key, CompilerContext context) throws BSFException {
 190  
         //context.code.append("():\n");
 191  0
         StringBuilder code = context.code;
 192  0
         code.append("public void exec(BSFManager bsf) throws Exception {");
 193  0
         appendText(context.code, "", context.text);
 194  0
         code.append("}");
 195  0
         return null;
 196  
     }
 197  
 }