diff --git a/src/main/java/com/metaweb/gridworks/expr/EvalError.java b/src/main/java/com/metaweb/gridworks/expr/EvalError.java index 4eceb26d3..ee435cde5 100644 --- a/src/main/java/com/metaweb/gridworks/expr/EvalError.java +++ b/src/main/java/com/metaweb/gridworks/expr/EvalError.java @@ -8,6 +8,12 @@ import org.json.JSONWriter; import com.metaweb.gridworks.Jsonizable; +/** + * An error that occurs during the evaluation of an Evaluable. Errors are values, too + * because they can be stored in cells just like strings, numbers, etc. Errors are not + * thrown because an error might occupy just one element in an array and doesn't need + * to make the whole array erroneous. + */ public class EvalError implements Serializable, Jsonizable { private static final long serialVersionUID = -102681220092874080L; diff --git a/src/main/java/com/metaweb/gridworks/expr/Evaluable.java b/src/main/java/com/metaweb/gridworks/expr/Evaluable.java index 1984e66fd..776b31e02 100644 --- a/src/main/java/com/metaweb/gridworks/expr/Evaluable.java +++ b/src/main/java/com/metaweb/gridworks/expr/Evaluable.java @@ -2,6 +2,15 @@ package com.metaweb.gridworks.expr; import java.util.Properties; +/** + * Interface for evaluable expressions in any arbitrary language. + */ public interface Evaluable { + /** + * Evaluate this expression in the given environment (bindings). + * + * @param bindings + * @return + */ public Object evaluate(Properties bindings); } diff --git a/src/main/java/com/metaweb/gridworks/expr/ExpressionUtils.java b/src/main/java/com/metaweb/gridworks/expr/ExpressionUtils.java index 1c80fb8b6..c1b973fc3 100644 --- a/src/main/java/com/metaweb/gridworks/expr/ExpressionUtils.java +++ b/src/main/java/com/metaweb/gridworks/expr/ExpressionUtils.java @@ -64,13 +64,15 @@ public class ExpressionUtils { } static public boolean sameValue(Object v1, Object v2) { - if (v1 == null) { - return (v2 == null) || (v2 instanceof String && ((String) v2).length() == 0); - } else if (v2 == null) { - return (v1 == null) || (v1 instanceof String && ((String) v1).length() == 0); - } else { - return v1.equals(v2); - } + if (v1 == null) { + return (v2 == null) + || (v2 instanceof String && ((String) v2).length() == 0); + } else if (v2 == null) { + return (v1 == null) + || (v1 instanceof String && ((String) v1).length() == 0); + } else { + return v1.equals(v2); + } } static public boolean isStorable(Object v) { @@ -90,12 +92,12 @@ public class ExpressionUtils { } @SuppressWarnings("unchecked") - static public List toObjectList(Object v) { - return (List) v; + static public List toObjectList(Object v) { + return (List) v; } @SuppressWarnings("unchecked") - static public Collection toObjectCollection(Object v) { - return (Collection) v; + static public Collection toObjectCollection(Object v) { + return (Collection) v; } } diff --git a/src/main/java/com/metaweb/gridworks/expr/HasFields.java b/src/main/java/com/metaweb/gridworks/expr/HasFields.java index 2267413a7..4e4b43bc3 100644 --- a/src/main/java/com/metaweb/gridworks/expr/HasFields.java +++ b/src/main/java/com/metaweb/gridworks/expr/HasFields.java @@ -2,6 +2,10 @@ package com.metaweb.gridworks.expr; import java.util.Properties; +/** + * Interface for objects that have named fields, which can be retrieved using the + * dot notation or the bracket notation, e.g., cells.Country, cells["Type of Disaster"]. + */ public interface HasFields { public Object getField(String name, Properties bindings); } diff --git a/src/main/java/com/metaweb/gridworks/expr/JythonEvaluable.java b/src/main/java/com/metaweb/gridworks/expr/JythonEvaluable.java index bc91d8e19..a5fe58556 100644 --- a/src/main/java/com/metaweb/gridworks/expr/JythonEvaluable.java +++ b/src/main/java/com/metaweb/gridworks/expr/JythonEvaluable.java @@ -19,22 +19,22 @@ public class JythonEvaluable implements Evaluable { private static PythonInterpreter _engine = new PythonInterpreter(); public JythonEvaluable(String s) { - // indent and create a function out of the code - String[] lines = s.split("\r\n|\r|\n"); - - StringBuffer sb = new StringBuffer(); - sb.append("def " + s_functionName + "(value, cell, cells, row, rowIndex):"); - for (int i = 0; i < lines.length; i++) { - sb.append("\n " + lines[i]); - } - + // indent and create a function out of the code + String[] lines = s.split("\r\n|\r|\n"); + + StringBuffer sb = new StringBuffer(); + sb.append("def " + s_functionName + "(value, cell, cells, row, rowIndex):"); + for (int i = 0; i < lines.length; i++) { + sb.append("\n " + lines[i]); + } + _engine.exec(sb.toString()); } - public Object evaluate(Properties bindings) { - try { - // call the temporary PyFunction directly - Object result = ((PyFunction)_engine.get(s_functionName)).__call__( + public Object evaluate(Properties bindings) { + try { + // call the temporary PyFunction directly + Object result = ((PyFunction)_engine.get(s_functionName)).__call__( new PyObject[] { Py.java2py( bindings.get("value") ), new JythonHasFieldsWrapper((HasFields) bindings.get("cell"), bindings), @@ -42,15 +42,15 @@ public class JythonEvaluable implements Evaluable { new JythonHasFieldsWrapper((HasFields) bindings.get("row"), bindings), Py.java2py( bindings.get("rowIndex") ) } - ); + ); - return unwrap(result); - } catch (PyException e) { - return new EvalError(e.toString()); - } - } - - protected Object unwrap(Object result) { + return unwrap(result); + } catch (PyException e) { + return new EvalError(e.toString()); + } + } + + protected Object unwrap(Object result) { if (result != null) { if (result instanceof JythonObjectWrapper) { return ((JythonObjectWrapper) result)._obj; @@ -64,12 +64,12 @@ public class JythonEvaluable implements Evaluable { } return result; - } - - protected Object unwrap(PyObject po) { - if (po instanceof PyNone) { - return null; - } else if (po.isNumberType()) { + } + + protected Object unwrap(PyObject po) { + if (po instanceof PyNone) { + return null; + } else if (po.isNumberType()) { return po.asDouble(); } else if (po.isSequenceType()) { Iterator i = po.asIterable().iterator(); @@ -83,5 +83,5 @@ public class JythonEvaluable implements Evaluable { } else { return po; } - } + } } diff --git a/src/main/java/com/metaweb/gridworks/expr/JythonHasFieldsWrapper.java b/src/main/java/com/metaweb/gridworks/expr/JythonHasFieldsWrapper.java index b15ad39ce..22dfa0566 100644 --- a/src/main/java/com/metaweb/gridworks/expr/JythonHasFieldsWrapper.java +++ b/src/main/java/com/metaweb/gridworks/expr/JythonHasFieldsWrapper.java @@ -5,34 +5,34 @@ import java.util.Properties; import org.python.core.PyObject; import org.python.core.PyString; - public class JythonHasFieldsWrapper extends PyObject { private static final long serialVersionUID = -1275353513262385099L; - - public HasFields _obj; - private Properties _bindings; - - public JythonHasFieldsWrapper(HasFields obj, Properties bindings) { - _obj = obj; - _bindings = bindings; - } - - public PyObject __finditem__(PyObject key) { - String k = (String) key.__tojava__(String.class); - Object v = _obj.getField(k, _bindings); - if (v != null) { - if (v instanceof HasFields) { - return new JythonHasFieldsWrapper((HasFields) v, _bindings); - } else if (v instanceof String) { - return new PyString((String) v); - } else if (v instanceof PyObject) { - return (PyObject) v; - } else { - return new JythonObjectWrapper(v); - } - } else { - return null; - } - } - + + public HasFields _obj; + + private Properties _bindings; + + public JythonHasFieldsWrapper(HasFields obj, Properties bindings) { + _obj = obj; + _bindings = bindings; + } + + public PyObject __finditem__(PyObject key) { + String k = (String) key.__tojava__(String.class); + Object v = _obj.getField(k, _bindings); + if (v != null) { + if (v instanceof HasFields) { + return new JythonHasFieldsWrapper((HasFields) v, _bindings); + } else if (v instanceof String) { + return new PyString((String) v); + } else if (v instanceof PyObject) { + return (PyObject) v; + } else { + return new JythonObjectWrapper(v); + } + } else { + return null; + } + } + } diff --git a/src/main/java/com/metaweb/gridworks/expr/JythonObjectWrapper.java b/src/main/java/com/metaweb/gridworks/expr/JythonObjectWrapper.java index 3fc3ac438..a182b6ee1 100644 --- a/src/main/java/com/metaweb/gridworks/expr/JythonObjectWrapper.java +++ b/src/main/java/com/metaweb/gridworks/expr/JythonObjectWrapper.java @@ -4,14 +4,14 @@ import org.python.core.PyObject; public class JythonObjectWrapper extends PyObject { private static final long serialVersionUID = -6608115027151667441L; - - public Object _obj; - - public JythonObjectWrapper(Object obj) { - _obj = obj; - } - - public String toString() { - return _obj.getClass().getSimpleName(); - } + + public Object _obj; + + public JythonObjectWrapper(Object obj) { + _obj = obj; + } + + public String toString() { + return _obj.getClass().getSimpleName(); + } } diff --git a/src/main/java/com/metaweb/gridworks/expr/MetaParser.java b/src/main/java/com/metaweb/gridworks/expr/MetaParser.java index 399d1a13d..c6ddc4275 100644 --- a/src/main/java/com/metaweb/gridworks/expr/MetaParser.java +++ b/src/main/java/com/metaweb/gridworks/expr/MetaParser.java @@ -8,6 +8,15 @@ import clojure.lang.IFn; import com.metaweb.gridworks.gel.Parser; abstract public class MetaParser { + /** + * Parse an expression that might have a language prefix into an Evaluable. + * Expressions without valid prefixes or without any prefix are assumed to be + * GEL expressions. + * + * @param s + * @return + * @throws ParsingException + */ static public Evaluable parse(String s) throws ParsingException { String language = "gel"; diff --git a/src/main/java/com/metaweb/gridworks/expr/functions/Get.java b/src/main/java/com/metaweb/gridworks/expr/functions/Get.java index 3c68786c9..f8c3009fb 100644 --- a/src/main/java/com/metaweb/gridworks/expr/functions/Get.java +++ b/src/main/java/com/metaweb/gridworks/expr/functions/Get.java @@ -26,10 +26,10 @@ public class Get implements Function { } else { if (from instanceof Number && (to == null || to instanceof Number)) { if (v.getClass().isArray() || v instanceof List) { - int length = v.getClass().isArray() ? - ((Object[]) v).length : - ExpressionUtils.toObjectList(v).size(); - + int length = v.getClass().isArray() ? + ((Object[]) v).length : + ExpressionUtils.toObjectList(v).size(); + int start = ((Number) from).intValue(); if (start < 0) { start = length + start; @@ -38,9 +38,9 @@ public class Get implements Function { if (to == null) { return start >= length ? null : - (v.getClass().isArray() ? - ((Object[]) v)[start] : - ExpressionUtils.toObjectList(v).get(start)); + (v.getClass().isArray() ? + ((Object[]) v)[start] : + ExpressionUtils.toObjectList(v).get(start)); } else { int end = to != null && to instanceof Number ? ((Number) to).intValue() : length; @@ -51,15 +51,15 @@ public class Get implements Function { end = Math.min(length, Math.max(start, end)); if (end > start) { - if (v.getClass().isArray()) { + if (v.getClass().isArray()) { Object[] a2 = new Object[end - start]; System.arraycopy((Object[]) v, start, a2, 0, end - start); return a2; - } else { - return ExpressionUtils.toObjectList(v).subList(start, end); - } + } else { + return ExpressionUtils.toObjectList(v).subList(start, end); + } } } } else { diff --git a/src/main/java/com/metaweb/gridworks/expr/functions/Slice.java b/src/main/java/com/metaweb/gridworks/expr/functions/Slice.java index ba9a517a1..8f2f12703 100644 --- a/src/main/java/com/metaweb/gridworks/expr/functions/Slice.java +++ b/src/main/java/com/metaweb/gridworks/expr/functions/Slice.java @@ -19,10 +19,10 @@ public class Slice implements Function { if (v != null && from != null && from instanceof Number && (to == null || to instanceof Number)) { if (v.getClass().isArray() || v instanceof List) { - int length = v.getClass().isArray() ? - ((Object[]) v).length : - ExpressionUtils.toObjectList(v).size(); - + int length = v.getClass().isArray() ? + ((Object[]) v).length : + ExpressionUtils.toObjectList(v).size(); + int start = ((Number) from).intValue(); int end = to != null && to instanceof Number ? ((Number) to).intValue() : length; @@ -37,15 +37,15 @@ public class Slice implements Function { } end = Math.min(length, Math.max(start, end)); - if (v.getClass().isArray()) { + if (v.getClass().isArray()) { Object[] a2 = new Object[end - start]; System.arraycopy((Object[]) v, start, a2, 0, end - start); return a2; - } else { - return ExpressionUtils.toObjectList(v).subList(start, end); - } + } else { + return ExpressionUtils.toObjectList(v).subList(start, end); + } } else { String s = (v instanceof String ? (String) v : v.toString()); diff --git a/src/main/java/com/metaweb/gridworks/expr/functions/Type.java b/src/main/java/com/metaweb/gridworks/expr/functions/Type.java index c9ce3d283..fb4e37552 100644 --- a/src/main/java/com/metaweb/gridworks/expr/functions/Type.java +++ b/src/main/java/com/metaweb/gridworks/expr/functions/Type.java @@ -1,6 +1,7 @@ package com.metaweb.gridworks.expr.functions; import java.util.Calendar; +import java.util.Date; import java.util.List; import java.util.Properties; @@ -20,18 +21,21 @@ public class Type implements Function { if (v != null) { if (v instanceof String) { return "string"; - } else if (v instanceof Calendar) { + } else if (v instanceof Calendar || v instanceof Date) { return "date"; } else if (v instanceof Number) { return "number"; } else if (v.getClass().isArray() || v instanceof List) { return "array"; + } else if (v instanceof EvalError) { + return "error"; } else { return v.getClass().getName(); } } + return "undefined"; } - return new EvalError(ControlFunctionRegistry.getFunctionName(this) + " expects a parameter"); + return new EvalError(ControlFunctionRegistry.getFunctionName(this) + " expects one argument"); } public void write(JSONWriter writer, Properties options) diff --git a/src/main/java/com/metaweb/gridworks/expr/functions/arrays/Reverse.java b/src/main/java/com/metaweb/gridworks/expr/functions/arrays/Reverse.java index a16a2d216..f24d29bf0 100644 --- a/src/main/java/com/metaweb/gridworks/expr/functions/arrays/Reverse.java +++ b/src/main/java/com/metaweb/gridworks/expr/functions/arrays/Reverse.java @@ -18,21 +18,21 @@ public class Reverse implements Function { Object v = args[0]; if (v != null && (v.getClass().isArray() || v instanceof List)) { - int length = v.getClass().isArray() ? - ((Object[]) v).length : - ExpressionUtils.toObjectList(v).size(); - + int length = v.getClass().isArray() ? + ((Object[]) v).length : + ExpressionUtils.toObjectList(v).size(); + Object[] r = new Object[length]; if (v.getClass().isArray()) { - Object[] a = (Object[]) v; - for (int i = 0; i < length; i++) { - r[i] = a[r.length - i - 1]; - } + Object[] a = (Object[]) v; + for (int i = 0; i < length; i++) { + r[i] = a[r.length - i - 1]; + } } else { - List a = ExpressionUtils.toObjectList(v); - for (int i = 0; i < length; i++) { - r[i] = a.get(r.length - i - 1); - } + List a = ExpressionUtils.toObjectList(v); + for (int i = 0; i < length; i++) { + r[i] = a.get(r.length - i - 1); + } } return r; } diff --git a/src/main/java/com/metaweb/gridworks/expr/functions/arrays/Sort.java b/src/main/java/com/metaweb/gridworks/expr/functions/arrays/Sort.java index a85ab1132..0a3faece4 100644 --- a/src/main/java/com/metaweb/gridworks/expr/functions/arrays/Sort.java +++ b/src/main/java/com/metaweb/gridworks/expr/functions/arrays/Sort.java @@ -20,19 +20,19 @@ public class Sort implements Function { Object v = args[0]; if (v != null) { - if (v.getClass().isArray()) { - Object[] a = (Object[]) v; - Object[] r = a.clone(); - - Arrays.sort(r, 0, r.length); - - return r; - } else if (v instanceof List) { - List a = (List) v; - Collections.sort(a); - - return a; - } + if (v.getClass().isArray()) { + Object[] a = (Object[]) v; + Object[] r = a.clone(); + + Arrays.sort(r, 0, r.length); + + return r; + } else if (v instanceof List) { + List a = (List) v; + Collections.sort(a); + + return a; + } } } return new EvalError(ControlFunctionRegistry.getFunctionName(this) + " expects an array"); diff --git a/src/main/java/com/metaweb/gridworks/expr/functions/math/Sum.java b/src/main/java/com/metaweb/gridworks/expr/functions/math/Sum.java index c345b1161..057c8f339 100644 --- a/src/main/java/com/metaweb/gridworks/expr/functions/math/Sum.java +++ b/src/main/java/com/metaweb/gridworks/expr/functions/math/Sum.java @@ -18,28 +18,28 @@ public class Sum implements Function { Object v = args[0]; if (v != null && (v.getClass().isArray() || v instanceof List)) { - int length = v.getClass().isArray() ? - ((Object[]) v).length : - ExpressionUtils.toObjectList(v).size(); + int length = v.getClass().isArray() ? + ((Object[]) v).length : + ExpressionUtils.toObjectList(v).size(); double total = 0; if (v.getClass().isArray()) { - Object[] a = (Object[]) v; - for (int i = 0; i < length; i++) { - Object n = a[length - i - 1]; - if (n instanceof Number) { - total += ((Number) n).doubleValue(); - } - } + Object[] a = (Object[]) v; + for (int i = 0; i < length; i++) { + Object n = a[length - i - 1]; + if (n instanceof Number) { + total += ((Number) n).doubleValue(); + } + } } else { - List a = ExpressionUtils.toObjectList(v); - for (int i = 0; i < length; i++) { - Object n = a.get(length - i - 1); - if (n instanceof Number) { - total += ((Number) n).doubleValue(); - } - } + List a = ExpressionUtils.toObjectList(v); + for (int i = 0; i < length; i++) { + Object n = a.get(length - i - 1); + if (n instanceof Number) { + total += ((Number) n).doubleValue(); + } + } } return total; }