From c914aa6c16e10f17483894ae3b6683dac81ae9c4 Mon Sep 17 00:00:00 2001 From: David Huynh Date: Sat, 27 Feb 2010 05:48:33 +0000 Subject: [PATCH] Introduced EvalError objects as possible values returned by expressions. Extracted function and control name mappings to ControlFunctionRegistry. git-svn-id: http://google-refine.googlecode.com/svn/trunk@148 7d457c2a-affb-35e4-300a-418c747d4874 --- .../recon/ReconJudgeOneCellCommand.java | 4 +- .../GetExpressionLanguageInfoCommand.java | 6 +- .../util/GuessTypesOfColumnCommand.java | 2 +- .../util/PreviewExpressionCommand.java | 12 +- .../com/metaweb/gridworks/expr/Control.java | 2 + .../expr/ControlFunctionRegistry.java | 128 ++++++++++++++++++ .../com/metaweb/gridworks/expr/EvalError.java | 26 ++++ .../gridworks/expr/ExpressionUtils.java | 11 ++ .../gridworks/expr/FieldAccessorExpr.java | 9 +- .../gridworks/expr/FunctionCallExpr.java | 6 +- .../gridworks/expr/OperatorCallExpr.java | 6 +- .../com/metaweb/gridworks/expr/Parser.java | 126 ++++------------- .../metaweb/gridworks/expr/VariableExpr.java | 6 +- .../gridworks/expr/controls/ForEach.java | 77 ++++++----- .../gridworks/expr/controls/ForNonBlank.java | 53 ++++---- .../metaweb/gridworks/expr/controls/If.java | 26 ++-- .../metaweb/gridworks/expr/controls/With.java | 54 +++++--- .../gridworks/expr/functions/Ceil.java | 6 +- .../gridworks/expr/functions/EndsWith.java | 4 +- .../gridworks/expr/functions/Floor.java | 6 +- .../gridworks/expr/functions/IndexOf.java | 4 +- .../gridworks/expr/functions/IsBlank.java | 2 +- .../gridworks/expr/functions/IsNotBlank.java | 4 +- .../gridworks/expr/functions/Join.java | 4 +- .../gridworks/expr/functions/LastIndexOf.java | 4 +- .../gridworks/expr/functions/Length.java | 4 +- .../metaweb/gridworks/expr/functions/Ln.java | 6 +- .../metaweb/gridworks/expr/functions/Log.java | 6 +- .../metaweb/gridworks/expr/functions/Max.java | 8 +- .../metaweb/gridworks/expr/functions/Min.java | 8 +- .../metaweb/gridworks/expr/functions/Mod.java | 8 +- .../metaweb/gridworks/expr/functions/Not.java | 6 +- .../gridworks/expr/functions/Replace.java | 4 +- .../gridworks/expr/functions/Reverse.java | 4 +- .../gridworks/expr/functions/Round.java | 6 +- .../gridworks/expr/functions/Sort.java | 4 +- .../gridworks/expr/functions/Split.java | 4 +- .../gridworks/expr/functions/StartsWith.java | 4 +- .../gridworks/expr/functions/ToLowercase.java | 4 +- .../gridworks/expr/functions/ToTitlecase.java | 4 +- .../gridworks/expr/functions/ToUppercase.java | 4 +- .../importers/ImporterUtilities.java | 14 +- .../com/metaweb/gridworks/model/Project.java | 4 +- .../metaweb/gridworks/model/ReconStats.java | 2 +- .../MultiValuedCellJoinOperation.java | 2 +- .../ReconJudgeSimilarCellsOperation.java | 2 +- .../gridworks/operations/ReconOperation.java | 2 +- .../protograph/transpose/Transposer.java | 2 +- .../dialogs/expression-preview-dialog.js | 9 +- src/site/index.html | 8 +- 50 files changed, 456 insertions(+), 261 deletions(-) create mode 100644 src/main/java/com/metaweb/gridworks/expr/ControlFunctionRegistry.java create mode 100644 src/main/java/com/metaweb/gridworks/expr/EvalError.java diff --git a/src/main/java/com/metaweb/gridworks/commands/recon/ReconJudgeOneCellCommand.java b/src/main/java/com/metaweb/gridworks/commands/recon/ReconJudgeOneCellCommand.java index dd6291f6b..41085e814 100644 --- a/src/main/java/com/metaweb/gridworks/commands/recon/ReconJudgeOneCellCommand.java +++ b/src/main/java/com/metaweb/gridworks/commands/recon/ReconJudgeOneCellCommand.java @@ -100,8 +100,8 @@ public class ReconJudgeOneCellCommand extends Command { protected HistoryEntry createHistoryEntry() throws Exception { Cell cell = _project.rows.get(rowIndex).getCell(cellIndex); - if (cell == null || ExpressionUtils.isBlank(cell.value)) { - throw new Exception("Cell is blank"); + if (cell == null || !ExpressionUtils.isNonBlankData(cell.value)) { + throw new Exception("Cell is blank or error"); } Column column = _project.columnModel.getColumnByCellIndex(cellIndex); diff --git a/src/main/java/com/metaweb/gridworks/commands/util/GetExpressionLanguageInfoCommand.java b/src/main/java/com/metaweb/gridworks/commands/util/GetExpressionLanguageInfoCommand.java index 7f8d47968..456804323 100644 --- a/src/main/java/com/metaweb/gridworks/commands/util/GetExpressionLanguageInfoCommand.java +++ b/src/main/java/com/metaweb/gridworks/commands/util/GetExpressionLanguageInfoCommand.java @@ -12,8 +12,8 @@ import org.json.JSONWriter; import com.metaweb.gridworks.commands.Command; import com.metaweb.gridworks.expr.Control; +import com.metaweb.gridworks.expr.ControlFunctionRegistry; import com.metaweb.gridworks.expr.Function; -import com.metaweb.gridworks.expr.Parser; public class GetExpressionLanguageInfoCommand extends Command { @@ -30,7 +30,7 @@ public class GetExpressionLanguageInfoCommand extends Command { writer.key("functions"); writer.object(); { - for (Entry entry : Parser.functionTable.entrySet()) { + for (Entry entry : ControlFunctionRegistry.getFunctionMapping()) { writer.key(entry.getKey()); entry.getValue().write(writer, options); } @@ -40,7 +40,7 @@ public class GetExpressionLanguageInfoCommand extends Command { writer.key("controls"); writer.object(); { - for (Entry entry : Parser.controlTable.entrySet()) { + for (Entry entry : ControlFunctionRegistry.getControlMapping()) { writer.key(entry.getKey()); entry.getValue().write(writer, options); } diff --git a/src/main/java/com/metaweb/gridworks/commands/util/GuessTypesOfColumnCommand.java b/src/main/java/com/metaweb/gridworks/commands/util/GuessTypesOfColumnCommand.java index 8a0c2117d..d7ced540d 100644 --- a/src/main/java/com/metaweb/gridworks/commands/util/GuessTypesOfColumnCommand.java +++ b/src/main/java/com/metaweb/gridworks/commands/util/GuessTypesOfColumnCommand.java @@ -86,7 +86,7 @@ public class GuessTypesOfColumnCommand extends Command { for (Row row : project.rows) { Object value = row.getCellValue(cellIndex); - if (!ExpressionUtils.isBlank(value)) { + if (ExpressionUtils.isNonBlankData(value)) { String s = value.toString().trim(); if (!sampleSet.contains(s)) { samples.add(s); diff --git a/src/main/java/com/metaweb/gridworks/commands/util/PreviewExpressionCommand.java b/src/main/java/com/metaweb/gridworks/commands/util/PreviewExpressionCommand.java index 33687d8b2..eb71d4f0a 100644 --- a/src/main/java/com/metaweb/gridworks/commands/util/PreviewExpressionCommand.java +++ b/src/main/java/com/metaweb/gridworks/commands/util/PreviewExpressionCommand.java @@ -12,10 +12,12 @@ import org.json.JSONWriter; import com.metaweb.gridworks.commands.Command; +import com.metaweb.gridworks.expr.EvalError; import com.metaweb.gridworks.expr.Evaluable; import com.metaweb.gridworks.expr.ExpressionUtils; import com.metaweb.gridworks.expr.HasFields; import com.metaweb.gridworks.expr.Parser; +import com.metaweb.gridworks.expr.Parser.ParserException; import com.metaweb.gridworks.model.Cell; import com.metaweb.gridworks.model.Project; import com.metaweb.gridworks.model.Row; @@ -69,15 +71,23 @@ public class PreviewExpressionCommand extends Command { } if (result != null) { - if (result instanceof HasFields) { + if (result instanceof EvalError) { + result = "[Error: " + ((EvalError) result).message + "]"; + } else if (result instanceof HasFields) { result = "[object " + result.getClass().getSimpleName() + "]"; } } writer.value(result); } writer.endArray(); + } catch (ParserException e) { + writer.key("code"); writer.value("error"); + writer.key("type"); writer.value("parser"); + writer.key("message"); writer.value(e.getMessage()); } catch (Exception e) { writer.key("code"); writer.value("error"); + writer.key("type"); writer.value("other"); + writer.key("message"); writer.value(e.getMessage()); } writer.endObject(); diff --git a/src/main/java/com/metaweb/gridworks/expr/Control.java b/src/main/java/com/metaweb/gridworks/expr/Control.java index 4235746b7..185e1a403 100644 --- a/src/main/java/com/metaweb/gridworks/expr/Control.java +++ b/src/main/java/com/metaweb/gridworks/expr/Control.java @@ -6,4 +6,6 @@ import com.metaweb.gridworks.Jsonizable; public interface Control extends Jsonizable { public Object call(Properties bindings, Evaluable[] args); + + public String checkArguments(Evaluable[] args); } diff --git a/src/main/java/com/metaweb/gridworks/expr/ControlFunctionRegistry.java b/src/main/java/com/metaweb/gridworks/expr/ControlFunctionRegistry.java new file mode 100644 index 000000000..1fd5c5489 --- /dev/null +++ b/src/main/java/com/metaweb/gridworks/expr/ControlFunctionRegistry.java @@ -0,0 +1,128 @@ +package com.metaweb.gridworks.expr; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.Map.Entry; + +import com.metaweb.gridworks.expr.controls.ForEach; +import com.metaweb.gridworks.expr.controls.ForNonBlank; +import com.metaweb.gridworks.expr.controls.If; +import com.metaweb.gridworks.expr.controls.With; +import com.metaweb.gridworks.expr.functions.And; +import com.metaweb.gridworks.expr.functions.Ceil; +import com.metaweb.gridworks.expr.functions.EndsWith; +import com.metaweb.gridworks.expr.functions.Floor; +import com.metaweb.gridworks.expr.functions.Get; +import com.metaweb.gridworks.expr.functions.IndexOf; +import com.metaweb.gridworks.expr.functions.IsBlank; +import com.metaweb.gridworks.expr.functions.IsNotBlank; +import com.metaweb.gridworks.expr.functions.IsNotNull; +import com.metaweb.gridworks.expr.functions.IsNull; +import com.metaweb.gridworks.expr.functions.Join; +import com.metaweb.gridworks.expr.functions.LastIndexOf; +import com.metaweb.gridworks.expr.functions.Length; +import com.metaweb.gridworks.expr.functions.Ln; +import com.metaweb.gridworks.expr.functions.Log; +import com.metaweb.gridworks.expr.functions.Max; +import com.metaweb.gridworks.expr.functions.Min; +import com.metaweb.gridworks.expr.functions.Mod; +import com.metaweb.gridworks.expr.functions.Not; +import com.metaweb.gridworks.expr.functions.Or; +import com.metaweb.gridworks.expr.functions.Replace; +import com.metaweb.gridworks.expr.functions.Reverse; +import com.metaweb.gridworks.expr.functions.Round; +import com.metaweb.gridworks.expr.functions.Slice; +import com.metaweb.gridworks.expr.functions.Sort; +import com.metaweb.gridworks.expr.functions.Split; +import com.metaweb.gridworks.expr.functions.StartsWith; +import com.metaweb.gridworks.expr.functions.ToLowercase; +import com.metaweb.gridworks.expr.functions.ToNumber; +import com.metaweb.gridworks.expr.functions.ToString; +import com.metaweb.gridworks.expr.functions.ToTitlecase; +import com.metaweb.gridworks.expr.functions.ToUppercase; + +public class ControlFunctionRegistry { + + static private Map s_nameToFunction = new HashMap(); + static private Map s_functionToName = new HashMap(); + + static private Map s_nameToControl = new HashMap(); + static private Map s_controlToName = new HashMap(); + + static public Function getFunction(String name) { + return s_nameToFunction.get(name); + } + static public String getFunctionName(Function f) { + return s_functionToName.get(f); + } + static public Set> getFunctionMapping() { + return s_nameToFunction.entrySet(); + } + + static public Control getControl(String name) { + return s_nameToControl.get(name); + } + static public String getControlName(Function f) { + return s_controlToName.get(f); + } + static public Set> getControlMapping() { + return s_nameToControl.entrySet(); + } + + static protected void registerFunction(String name, Function f) { + s_nameToFunction.put(name, f); + s_functionToName.put(f, name); + } + + static protected void registerControl(String name, Control c) { + s_nameToControl.put(name, c); + s_controlToName.put(c, name); + } + + static { + registerFunction("toString", new ToString()); + registerFunction("toNumber", new ToNumber()); + + registerFunction("toUppercase", new ToUppercase()); + registerFunction("toLowercase", new ToLowercase()); + registerFunction("toTitlecase", new ToTitlecase()); + + registerFunction("get", new Get()); + registerFunction("slice", new Slice()); + registerFunction("substring", new Slice()); + registerFunction("replace", new Replace()); + registerFunction("split", new Split()); + registerFunction("length", new Length()); + + registerFunction("indexOf", new IndexOf()); + registerFunction("lastIndexOf", new LastIndexOf()); + registerFunction("startsWith", new StartsWith()); + registerFunction("endsWith", new EndsWith()); + registerFunction("join", new Join()); + registerFunction("reverse", new Reverse()); + registerFunction("sort", new Sort()); + + registerFunction("round", new Round()); + registerFunction("floor", new Floor()); + registerFunction("ceil", new Ceil()); + registerFunction("mod", new Mod()); + registerFunction("max", new Max()); + registerFunction("min", new Min()); + registerFunction("log", new Log()); + registerFunction("ln", new Ln()); + + registerFunction("and", new And()); + registerFunction("or", new Or()); + registerFunction("not", new Not()); + registerFunction("isNull", new IsNull()); + registerFunction("isNotNull", new IsNotNull()); + registerFunction("isBlank", new IsBlank()); + registerFunction("isNotBlank", new IsNotBlank()); + + registerControl("if", new If()); + registerControl("with", new With()); + registerControl("forEach", new ForEach()); + registerControl("forNonBlank", new ForNonBlank()); + } +} diff --git a/src/main/java/com/metaweb/gridworks/expr/EvalError.java b/src/main/java/com/metaweb/gridworks/expr/EvalError.java new file mode 100644 index 000000000..ffb4e559d --- /dev/null +++ b/src/main/java/com/metaweb/gridworks/expr/EvalError.java @@ -0,0 +1,26 @@ +package com.metaweb.gridworks.expr; + +import java.util.Properties; + +import org.json.JSONException; +import org.json.JSONWriter; + +import com.metaweb.gridworks.Jsonizable; + +public class EvalError implements Jsonizable { + final public String message; + + public EvalError(String message) { + this.message = message; + } + + public void write(JSONWriter writer, Properties options) + throws JSONException { + + writer.object(); + writer.key("type"); writer.value("error"); + writer.key("message"); writer.value(message); + writer.endObject(); + } + +} diff --git a/src/main/java/com/metaweb/gridworks/expr/ExpressionUtils.java b/src/main/java/com/metaweb/gridworks/expr/ExpressionUtils.java index 9d66fec7f..9bcfef8b7 100644 --- a/src/main/java/com/metaweb/gridworks/expr/ExpressionUtils.java +++ b/src/main/java/com/metaweb/gridworks/expr/ExpressionUtils.java @@ -32,9 +32,20 @@ public class ExpressionUtils { } } + static public boolean isError(Object o) { + return o != null && o instanceof EvalError; + } + /* static public boolean isBlank(Object o) { return o == null || (o instanceof String && ((String) o).length() == 0); } + */ + static public boolean isNonBlankData(Object o) { + return + o != null && + !(o instanceof EvalError) && + (!(o instanceof String) || ((String) o).length() > 0); + } static public boolean isTrue(Object o) { return o != null && diff --git a/src/main/java/com/metaweb/gridworks/expr/FieldAccessorExpr.java b/src/main/java/com/metaweb/gridworks/expr/FieldAccessorExpr.java index 32bca3f6e..389d022f5 100644 --- a/src/main/java/com/metaweb/gridworks/expr/FieldAccessorExpr.java +++ b/src/main/java/com/metaweb/gridworks/expr/FieldAccessorExpr.java @@ -13,10 +13,15 @@ public class FieldAccessorExpr implements Evaluable { public Object evaluate(Properties bindings) { Object o = _inner.evaluate(bindings); - if (o != null && o instanceof HasFields) { + if (ExpressionUtils.isError(o)) { + return o; + } else if (o == null) { + return new EvalError("Cannot retrieve field from null"); + } else if (o instanceof HasFields) { return ((HasFields) o).getField(_fieldName, bindings); + } else { + return new EvalError("Object does not have any field, including " + _fieldName); } - return null; } @Override diff --git a/src/main/java/com/metaweb/gridworks/expr/FunctionCallExpr.java b/src/main/java/com/metaweb/gridworks/expr/FunctionCallExpr.java index e56b696a0..f68cf0043 100644 --- a/src/main/java/com/metaweb/gridworks/expr/FunctionCallExpr.java +++ b/src/main/java/com/metaweb/gridworks/expr/FunctionCallExpr.java @@ -14,7 +14,11 @@ public class FunctionCallExpr implements Evaluable { public Object evaluate(Properties bindings) { Object[] args = new Object[_args.length]; for (int i = 0; i < _args.length; i++) { - args[i] = _args[i].evaluate(bindings); + Object v = _args[i].evaluate(bindings); + if (ExpressionUtils.isError(v)) { + return v; + } + args[i] = v; } return _function.call(bindings, args); } diff --git a/src/main/java/com/metaweb/gridworks/expr/OperatorCallExpr.java b/src/main/java/com/metaweb/gridworks/expr/OperatorCallExpr.java index fde798dd8..bebf81fdc 100644 --- a/src/main/java/com/metaweb/gridworks/expr/OperatorCallExpr.java +++ b/src/main/java/com/metaweb/gridworks/expr/OperatorCallExpr.java @@ -14,7 +14,11 @@ public class OperatorCallExpr implements Evaluable { public Object evaluate(Properties bindings) { Object[] args = new Object[_args.length]; for (int i = 0; i < _args.length; i++) { - args[i] = _args[i].evaluate(bindings); + Object v = _args[i].evaluate(bindings); + if (ExpressionUtils.isError(v)) { + return v; + } + args[i] = v; } if (args.length == 2) { diff --git a/src/main/java/com/metaweb/gridworks/expr/Parser.java b/src/main/java/com/metaweb/gridworks/expr/Parser.java index 1131761c4..6bcfab198 100644 --- a/src/main/java/com/metaweb/gridworks/expr/Parser.java +++ b/src/main/java/com/metaweb/gridworks/expr/Parser.java @@ -1,109 +1,30 @@ package com.metaweb.gridworks.expr; -import java.util.HashMap; import java.util.LinkedList; import java.util.List; -import java.util.Map; import com.metaweb.gridworks.expr.Scanner.NumberToken; import com.metaweb.gridworks.expr.Scanner.Token; import com.metaweb.gridworks.expr.Scanner.TokenType; -import com.metaweb.gridworks.expr.controls.ForEach; -import com.metaweb.gridworks.expr.controls.ForNonBlank; -import com.metaweb.gridworks.expr.controls.If; -import com.metaweb.gridworks.expr.controls.With; -import com.metaweb.gridworks.expr.functions.And; -import com.metaweb.gridworks.expr.functions.Ceil; -import com.metaweb.gridworks.expr.functions.EndsWith; -import com.metaweb.gridworks.expr.functions.Floor; -import com.metaweb.gridworks.expr.functions.Get; -import com.metaweb.gridworks.expr.functions.IndexOf; -import com.metaweb.gridworks.expr.functions.IsBlank; -import com.metaweb.gridworks.expr.functions.IsNotBlank; -import com.metaweb.gridworks.expr.functions.IsNotNull; -import com.metaweb.gridworks.expr.functions.IsNull; -import com.metaweb.gridworks.expr.functions.Join; -import com.metaweb.gridworks.expr.functions.LastIndexOf; -import com.metaweb.gridworks.expr.functions.Length; -import com.metaweb.gridworks.expr.functions.Ln; -import com.metaweb.gridworks.expr.functions.Log; -import com.metaweb.gridworks.expr.functions.Max; -import com.metaweb.gridworks.expr.functions.Min; -import com.metaweb.gridworks.expr.functions.Mod; -import com.metaweb.gridworks.expr.functions.Not; -import com.metaweb.gridworks.expr.functions.Or; -import com.metaweb.gridworks.expr.functions.Replace; -import com.metaweb.gridworks.expr.functions.Reverse; -import com.metaweb.gridworks.expr.functions.Round; -import com.metaweb.gridworks.expr.functions.Slice; -import com.metaweb.gridworks.expr.functions.Sort; -import com.metaweb.gridworks.expr.functions.Split; -import com.metaweb.gridworks.expr.functions.StartsWith; -import com.metaweb.gridworks.expr.functions.ToLowercase; -import com.metaweb.gridworks.expr.functions.ToNumber; -import com.metaweb.gridworks.expr.functions.ToString; -import com.metaweb.gridworks.expr.functions.ToTitlecase; -import com.metaweb.gridworks.expr.functions.ToUppercase; public class Parser { protected Scanner _scanner; protected Token _token; protected Evaluable _root; - static public Map functionTable = new HashMap(); - static public Map controlTable = new HashMap(); - - static { - functionTable.put("toString", new ToString()); - functionTable.put("toNumber", new ToNumber()); - - functionTable.put("toUppercase", new ToUppercase()); - functionTable.put("toLowercase", new ToLowercase()); - functionTable.put("toTitlecase", new ToTitlecase()); - - functionTable.put("get", new Get()); - functionTable.put("slice", new Slice()); - functionTable.put("substring", new Slice()); - functionTable.put("replace", new Replace()); - functionTable.put("split", new Split()); - functionTable.put("length", new Length()); - - functionTable.put("indexOf", new IndexOf()); - functionTable.put("lastIndexOf", new LastIndexOf()); - functionTable.put("startsWith", new StartsWith()); - functionTable.put("endsWith", new EndsWith()); - functionTable.put("join", new Join()); - functionTable.put("reverse", new Reverse()); - functionTable.put("sort", new Sort()); - - functionTable.put("round", new Round()); - functionTable.put("floor", new Floor()); - functionTable.put("ceil", new Ceil()); - functionTable.put("mod", new Mod()); - functionTable.put("max", new Max()); - functionTable.put("min", new Min()); - functionTable.put("log", new Log()); - functionTable.put("ln", new Ln()); - - functionTable.put("and", new And()); - functionTable.put("or", new Or()); - functionTable.put("not", new Not()); - functionTable.put("isNull", new IsNull()); - functionTable.put("isNotNull", new IsNotNull()); - functionTable.put("isBlank", new IsBlank()); - functionTable.put("isNotBlank", new IsNotBlank()); + static public class ParserException extends Exception { + private static final long serialVersionUID = 155004505172098755L; - controlTable.put("if", new If()); - controlTable.put("with", new With()); - controlTable.put("forEach", new ForEach()); - controlTable.put("forNonBlank", new ForNonBlank()); - } - - public Parser(String s) throws Exception { + protected ParserException(String message) { + super(message); + } + } + + public Parser(String s) throws ParserException { this(s, 0, s.length()); } - public Parser(String s, int from, int to) throws Exception { + public Parser(String s, int from, int to) throws ParserException { _scanner = new Scanner(s, from, to); _token = _scanner.next(); @@ -118,13 +39,13 @@ public class Parser { _token = _scanner.next(); } - protected Exception makeException(String desc) { + protected ParserException makeException(String desc) { int index = _token != null ? _token.start : _scanner.getIndex(); - return new Exception("Parsing error at offset " + index + ": " + desc); + return new ParserException("Parsing error at offset " + index + ": " + desc); } - protected Evaluable parseExpression() throws Exception { + protected Evaluable parseExpression() throws ParserException { Evaluable sub = parseSubExpression(); while (_token != null && @@ -143,7 +64,7 @@ public class Parser { return sub; } - protected Evaluable parseSubExpression() throws Exception { + protected Evaluable parseSubExpression() throws ParserException { Evaluable sub = parseTerm(); while (_token != null && @@ -162,7 +83,7 @@ public class Parser { return sub; } - protected Evaluable parseTerm() throws Exception { + protected Evaluable parseTerm() throws ParserException { Evaluable factor = parseFactor(); while (_token != null && @@ -181,7 +102,7 @@ public class Parser { return factor; } - protected Evaluable parseFactor() throws Exception { + protected Evaluable parseFactor() throws ParserException { if (_token == null) { throw makeException("Expression ends too early"); } @@ -210,8 +131,8 @@ public class Parser { if (_token == null || _token.type != TokenType.Delimiter || !_token.text.equals("(")) { eval = new VariableExpr(text); } else { - Function f = functionTable.get(text); - Control c = controlTable.get(text); + Function f = ControlFunctionRegistry.getFunction(text); + Control c = ControlFunctionRegistry.getControl(text); if (f == null && c == null) { throw makeException("Unknown function or control named " + text); } @@ -221,7 +142,12 @@ public class Parser { List args = parseExpressionList(")"); if (c != null) { - eval = new ControlCallExpr(makeArray(args), c); + Evaluable[] argsA = makeArray(args); + String errorMessage = c.checkArguments(argsA); + if (errorMessage != null) { + throw makeException(errorMessage); + } + eval = new ControlCallExpr(argsA, c); } else { eval = new FunctionCallExpr(makeArray(args), f); } @@ -254,7 +180,7 @@ public class Parser { if (_token != null && _token.type == TokenType.Delimiter && _token.text.equals("(")) { next(); // swallow ( - Function f = functionTable.get(identifier); + Function f = ControlFunctionRegistry.getFunction(identifier); if (f == null) { throw makeException("Unknown function " + identifier); } @@ -272,7 +198,7 @@ public class Parser { List args = parseExpressionList("]"); args.add(0, eval); - eval = new FunctionCallExpr(makeArray(args), functionTable.get("get")); + eval = new FunctionCallExpr(makeArray(args), ControlFunctionRegistry.getFunction("get")); } else { break; } @@ -281,7 +207,7 @@ public class Parser { return eval; } - protected List parseExpressionList(String closingDelimiter) throws Exception { + protected List parseExpressionList(String closingDelimiter) throws ParserException { List l = new LinkedList(); if (_token != null && diff --git a/src/main/java/com/metaweb/gridworks/expr/VariableExpr.java b/src/main/java/com/metaweb/gridworks/expr/VariableExpr.java index 20db1382f..00b808f4a 100644 --- a/src/main/java/com/metaweb/gridworks/expr/VariableExpr.java +++ b/src/main/java/com/metaweb/gridworks/expr/VariableExpr.java @@ -10,7 +10,11 @@ public class VariableExpr implements Evaluable { } public Object evaluate(Properties bindings) { - return bindings.get(_name); + if (bindings.containsKey(_name)) { + return bindings.get(_name); + } else { + return new EvalError("No variable named " + _name); + } } public String toString() { diff --git a/src/main/java/com/metaweb/gridworks/expr/controls/ForEach.java b/src/main/java/com/metaweb/gridworks/expr/controls/ForEach.java index 7845d88ac..d4d37d247 100644 --- a/src/main/java/com/metaweb/gridworks/expr/controls/ForEach.java +++ b/src/main/java/com/metaweb/gridworks/expr/controls/ForEach.java @@ -8,50 +8,53 @@ import org.json.JSONException; import org.json.JSONWriter; import com.metaweb.gridworks.expr.Control; +import com.metaweb.gridworks.expr.EvalError; import com.metaweb.gridworks.expr.Evaluable; +import com.metaweb.gridworks.expr.ExpressionUtils; import com.metaweb.gridworks.expr.VariableExpr; public class ForEach implements Control { - - public Object call(Properties bindings, Evaluable[] args) { - if (args.length >= 3) { - Object o = args[0].evaluate(bindings); - Evaluable var = args[1]; - String name = (var instanceof VariableExpr) ? ((VariableExpr) var).getName() : - ((String) var.evaluate(bindings)); - - if (o != null) { - Object oldValue = bindings.get(name); - try { - Object[] values; - if (o.getClass().isArray()) { - values = (Object[]) o; - } else { - values = new Object[] { o }; - } - - List results = new ArrayList(values.length); - for (Object v : values) { - bindings.put(name, v); - - Object r = args[2].evaluate(bindings); - if (r != null) { - results.add(r); - } - } - - return results.toArray(); - } finally { - if (oldValue != null) { - bindings.put(name, oldValue); - } else { - bindings.remove(name); - } - } - } + public String checkArguments(Evaluable[] args) { + if (args.length != 3) { + return "forEach expects 3 arguments"; + } else if (!(args[1] instanceof VariableExpr)) { + return "forEach expects second argument to be a variable name"; } return null; } + + public Object call(Properties bindings, Evaluable[] args) { + Object o = args[0].evaluate(bindings); + if (ExpressionUtils.isError(o)) { + return o; + } else if (o == null || !o.getClass().isArray()) { + return new EvalError("First argument to forEach is not an array"); + } + + String name = ((VariableExpr) args[1]).getName(); + + Object oldValue = bindings.get(name); + try { + Object[] values = (Object[]) o; + + List results = new ArrayList(values.length); + for (Object v : values) { + bindings.put(name, v); + + Object r = args[2].evaluate(bindings); + + results.add(r); + } + + return results.toArray(); + } finally { + if (oldValue != null) { + bindings.put(name, oldValue); + } else { + bindings.remove(name); + } + } + } public void write(JSONWriter writer, Properties options) throws JSONException { diff --git a/src/main/java/com/metaweb/gridworks/expr/controls/ForNonBlank.java b/src/main/java/com/metaweb/gridworks/expr/controls/ForNonBlank.java index 3ddb60746..12d24a080 100644 --- a/src/main/java/com/metaweb/gridworks/expr/controls/ForNonBlank.java +++ b/src/main/java/com/metaweb/gridworks/expr/controls/ForNonBlank.java @@ -11,33 +11,38 @@ import com.metaweb.gridworks.expr.ExpressionUtils; import com.metaweb.gridworks.expr.VariableExpr; public class ForNonBlank implements Control { - - public Object call(Properties bindings, Evaluable[] args) { - if (args.length >= 3) { - Object o = args[0].evaluate(bindings); - Evaluable var = args[1]; - String name = (var instanceof VariableExpr) ? ((VariableExpr) var).getName() : - ((String) var.evaluate(bindings)); - - if (!ExpressionUtils.isBlank(o)) { - Object oldValue = bindings.containsKey(name) ? bindings.get(name) : null; - bindings.put(name, o); - - try { - return args[2].evaluate(bindings); - } finally { - if (oldValue != null) { - bindings.put(name, oldValue); - } else { - bindings.remove(name); - } - } - } else if (args.length >= 4) { - return args[3].evaluate(bindings); - } + public String checkArguments(Evaluable[] args) { + if (args.length != 4) { + return "forNonBlank expects 4 arguments"; + } else if (!(args[1] instanceof VariableExpr)) { + return "forNonBlank expects second argument to be a variable name"; } return null; } + + public Object call(Properties bindings, Evaluable[] args) { + Object o = args[0].evaluate(bindings); + + Evaluable var = args[1]; + String name = ((VariableExpr) var).getName(); + + if (ExpressionUtils.isNonBlankData(o)) { + Object oldValue = bindings.containsKey(name) ? bindings.get(name) : null; + bindings.put(name, o); + + try { + return args[2].evaluate(bindings); + } finally { + if (oldValue != null) { + bindings.put(name, oldValue); + } else { + bindings.remove(name); + } + } + } else { + return args[3].evaluate(bindings); + } + } public void write(JSONWriter writer, Properties options) throws JSONException { diff --git a/src/main/java/com/metaweb/gridworks/expr/controls/If.java b/src/main/java/com/metaweb/gridworks/expr/controls/If.java index 43e6ad0dd..63b5732de 100644 --- a/src/main/java/com/metaweb/gridworks/expr/controls/If.java +++ b/src/main/java/com/metaweb/gridworks/expr/controls/If.java @@ -1,6 +1,6 @@ package com.metaweb.gridworks.expr.controls; - import java.util.Properties; +import java.util.Properties; import org.json.JSONException; import org.json.JSONWriter; @@ -10,19 +10,23 @@ import com.metaweb.gridworks.expr.Evaluable; import com.metaweb.gridworks.expr.ExpressionUtils; public class If implements Control { - - public Object call(Properties bindings, Evaluable[] args) { - if (args.length >= 3) { - Object o = args[0].evaluate(bindings); - - if (ExpressionUtils.isTrue(o)) { - return args[1].evaluate(bindings); - } else if (args.length >= 3) { - return args[2].evaluate(bindings); - } + public String checkArguments(Evaluable[] args) { + if (args.length != 3) { + return "if expects 3 arguments"; } return null; } + + public Object call(Properties bindings, Evaluable[] args) { + Object o = args[0].evaluate(bindings); + if (ExpressionUtils.isError(o)) { + return o; + } else if (ExpressionUtils.isTrue(o)) { + return args[1].evaluate(bindings); + } else { + return args[2].evaluate(bindings); + } + } public void write(JSONWriter writer, Properties options) throws JSONException { diff --git a/src/main/java/com/metaweb/gridworks/expr/controls/With.java b/src/main/java/com/metaweb/gridworks/expr/controls/With.java index 31d41b7a1..f4288645a 100644 --- a/src/main/java/com/metaweb/gridworks/expr/controls/With.java +++ b/src/main/java/com/metaweb/gridworks/expr/controls/With.java @@ -7,34 +7,44 @@ import org.json.JSONWriter; import com.metaweb.gridworks.expr.Control; import com.metaweb.gridworks.expr.Evaluable; +import com.metaweb.gridworks.expr.ExpressionUtils; import com.metaweb.gridworks.expr.VariableExpr; public class With implements Control { - - public Object call(Properties bindings, Evaluable[] args) { - if (args.length >= 3) { - Object o = args[0].evaluate(bindings); - Evaluable var = args[1]; - String name = (var instanceof VariableExpr) ? ((VariableExpr) var).getName() : - ((String) var.evaluate(bindings)); - - if (o != null) { - Object oldValue = bindings.get(name); - try { - bindings.put(name, o); - - return args[2].evaluate(bindings); - } finally { - if (oldValue != null) { - bindings.put(name, oldValue); - } else { - bindings.remove(name); - } - } - } + public String checkArguments(Evaluable[] args) { + if (args.length != 3) { + return "with expects 3 arguments"; + } else if (!(args[1] instanceof VariableExpr)) { + return "with expects second argument to be a variable name"; } return null; } + + public Object call(Properties bindings, Evaluable[] args) { + Object o = args[0].evaluate(bindings); + if (ExpressionUtils.isError(o)) { + return o; + } + + String name = ((VariableExpr) args[1]).getName(); + + Object oldValue = bindings.get(name); + try { + if (o != null) { + bindings.put(name, o); + } else { + bindings.remove(name); + } + + return args[2].evaluate(bindings); + } finally { + if (oldValue != null) { + bindings.put(name, oldValue); + } else { + bindings.remove(name); + } + } + } public void write(JSONWriter writer, Properties options) throws JSONException { diff --git a/src/main/java/com/metaweb/gridworks/expr/functions/Ceil.java b/src/main/java/com/metaweb/gridworks/expr/functions/Ceil.java index 6d9b2207a..23fcd151d 100644 --- a/src/main/java/com/metaweb/gridworks/expr/functions/Ceil.java +++ b/src/main/java/com/metaweb/gridworks/expr/functions/Ceil.java @@ -5,15 +5,17 @@ import java.util.Properties; import org.json.JSONException; import org.json.JSONWriter; +import com.metaweb.gridworks.expr.ControlFunctionRegistry; import com.metaweb.gridworks.expr.Function; +import com.metaweb.gridworks.expr.EvalError; public class Ceil implements Function { public Object call(Properties bindings, Object[] args) { - if (args.length == 1 && args[0] instanceof Number) { + if (args.length == 1 && args[0] != null && args[0] instanceof Number) { return (long) Math.ceil(((Number) args[0]).doubleValue()); } - return null; + return new EvalError(ControlFunctionRegistry.getFunctionName(this) + " expects a number"); } public void write(JSONWriter writer, Properties options) diff --git a/src/main/java/com/metaweb/gridworks/expr/functions/EndsWith.java b/src/main/java/com/metaweb/gridworks/expr/functions/EndsWith.java index 8586c9298..18881d7e6 100644 --- a/src/main/java/com/metaweb/gridworks/expr/functions/EndsWith.java +++ b/src/main/java/com/metaweb/gridworks/expr/functions/EndsWith.java @@ -5,7 +5,9 @@ import java.util.Properties; import org.json.JSONException; import org.json.JSONWriter; +import com.metaweb.gridworks.expr.ControlFunctionRegistry; import com.metaweb.gridworks.expr.Function; +import com.metaweb.gridworks.expr.EvalError; public class EndsWith implements Function { @@ -17,7 +19,7 @@ public class EndsWith implements Function { return ((String) s1).endsWith((String) s2); } } - return null; + return new EvalError(ControlFunctionRegistry.getFunctionName(this) + " expects 2 strings"); } public void write(JSONWriter writer, Properties options) diff --git a/src/main/java/com/metaweb/gridworks/expr/functions/Floor.java b/src/main/java/com/metaweb/gridworks/expr/functions/Floor.java index 30e773e59..4c8aa0041 100644 --- a/src/main/java/com/metaweb/gridworks/expr/functions/Floor.java +++ b/src/main/java/com/metaweb/gridworks/expr/functions/Floor.java @@ -5,15 +5,17 @@ import java.util.Properties; import org.json.JSONException; import org.json.JSONWriter; +import com.metaweb.gridworks.expr.ControlFunctionRegistry; import com.metaweb.gridworks.expr.Function; +import com.metaweb.gridworks.expr.EvalError; public class Floor implements Function { public Object call(Properties bindings, Object[] args) { - if (args.length == 1 && args[0] instanceof Number) { + if (args.length == 1 && args[0] != null && args[0] instanceof Number) { return (long) Math.floor(((Number) args[0]).doubleValue()); } - return null; + return new EvalError(ControlFunctionRegistry.getFunctionName(this) + " expects a number"); } public void write(JSONWriter writer, Properties options) diff --git a/src/main/java/com/metaweb/gridworks/expr/functions/IndexOf.java b/src/main/java/com/metaweb/gridworks/expr/functions/IndexOf.java index 09f586373..486e0fad8 100644 --- a/src/main/java/com/metaweb/gridworks/expr/functions/IndexOf.java +++ b/src/main/java/com/metaweb/gridworks/expr/functions/IndexOf.java @@ -5,7 +5,9 @@ import java.util.Properties; import org.json.JSONException; import org.json.JSONWriter; +import com.metaweb.gridworks.expr.ControlFunctionRegistry; import com.metaweb.gridworks.expr.Function; +import com.metaweb.gridworks.expr.EvalError; public class IndexOf implements Function { @@ -17,7 +19,7 @@ public class IndexOf implements Function { return ((String) s1).indexOf((String) s2); } } - return null; + return new EvalError(ControlFunctionRegistry.getFunctionName(this) + " expects 2 strings"); } public void write(JSONWriter writer, Properties options) diff --git a/src/main/java/com/metaweb/gridworks/expr/functions/IsBlank.java b/src/main/java/com/metaweb/gridworks/expr/functions/IsBlank.java index 689e08c7e..44bcf1c82 100644 --- a/src/main/java/com/metaweb/gridworks/expr/functions/IsBlank.java +++ b/src/main/java/com/metaweb/gridworks/expr/functions/IsBlank.java @@ -11,7 +11,7 @@ import com.metaweb.gridworks.expr.Function; public class IsBlank implements Function { public Object call(Properties bindings, Object[] args) { - return args.length == 0 || ExpressionUtils.isBlank(args[0]); + return args.length == 0 || !ExpressionUtils.isNonBlankData(args[0]); } public void write(JSONWriter writer, Properties options) diff --git a/src/main/java/com/metaweb/gridworks/expr/functions/IsNotBlank.java b/src/main/java/com/metaweb/gridworks/expr/functions/IsNotBlank.java index a7231abc4..9312d7852 100644 --- a/src/main/java/com/metaweb/gridworks/expr/functions/IsNotBlank.java +++ b/src/main/java/com/metaweb/gridworks/expr/functions/IsNotBlank.java @@ -11,14 +11,14 @@ import com.metaweb.gridworks.expr.Function; public class IsNotBlank implements Function { public Object call(Properties bindings, Object[] args) { - return args.length > 0 && !ExpressionUtils.isBlank(args[0]); + return args.length > 0 && ExpressionUtils.isNonBlankData(args[0]); } public void write(JSONWriter writer, Properties options) throws JSONException { writer.object(); - writer.key("description"); writer.value("Returns whether o is not null and not an empty string"); + writer.key("description"); writer.value("Returns whether o is not null, not an error, and not an empty string"); writer.key("params"); writer.value("o"); writer.key("returns"); writer.value("boolean"); writer.endObject(); diff --git a/src/main/java/com/metaweb/gridworks/expr/functions/Join.java b/src/main/java/com/metaweb/gridworks/expr/functions/Join.java index 111b2b9b5..db58cb5aa 100644 --- a/src/main/java/com/metaweb/gridworks/expr/functions/Join.java +++ b/src/main/java/com/metaweb/gridworks/expr/functions/Join.java @@ -5,7 +5,9 @@ import java.util.Properties; import org.json.JSONException; import org.json.JSONWriter; +import com.metaweb.gridworks.expr.ControlFunctionRegistry; import com.metaweb.gridworks.expr.Function; +import com.metaweb.gridworks.expr.EvalError; public class Join implements Function { @@ -33,7 +35,7 @@ public class Join implements Function { return sb.toString(); } } - return null; + return new EvalError(ControlFunctionRegistry.getFunctionName(this) + " expects an array and a string"); } public void write(JSONWriter writer, Properties options) diff --git a/src/main/java/com/metaweb/gridworks/expr/functions/LastIndexOf.java b/src/main/java/com/metaweb/gridworks/expr/functions/LastIndexOf.java index f27d64f24..d7bd8930a 100644 --- a/src/main/java/com/metaweb/gridworks/expr/functions/LastIndexOf.java +++ b/src/main/java/com/metaweb/gridworks/expr/functions/LastIndexOf.java @@ -5,7 +5,9 @@ import java.util.Properties; import org.json.JSONException; import org.json.JSONWriter; +import com.metaweb.gridworks.expr.ControlFunctionRegistry; import com.metaweb.gridworks.expr.Function; +import com.metaweb.gridworks.expr.EvalError; public class LastIndexOf implements Function { @@ -17,7 +19,7 @@ public class LastIndexOf implements Function { return ((String) s1).lastIndexOf((String) s2); } } - return null; + return new EvalError(ControlFunctionRegistry.getFunctionName(this) + " expects 2 strings"); } public void write(JSONWriter writer, Properties options) diff --git a/src/main/java/com/metaweb/gridworks/expr/functions/Length.java b/src/main/java/com/metaweb/gridworks/expr/functions/Length.java index 432a2b711..60765cda0 100644 --- a/src/main/java/com/metaweb/gridworks/expr/functions/Length.java +++ b/src/main/java/com/metaweb/gridworks/expr/functions/Length.java @@ -5,7 +5,9 @@ import java.util.Properties; import org.json.JSONException; import org.json.JSONWriter; +import com.metaweb.gridworks.expr.ControlFunctionRegistry; import com.metaweb.gridworks.expr.Function; +import com.metaweb.gridworks.expr.EvalError; public class Length implements Function { @@ -23,7 +25,7 @@ public class Length implements Function { } } } - return null; + return new EvalError(ControlFunctionRegistry.getFunctionName(this) + " expects an array or a string"); } public void write(JSONWriter writer, Properties options) diff --git a/src/main/java/com/metaweb/gridworks/expr/functions/Ln.java b/src/main/java/com/metaweb/gridworks/expr/functions/Ln.java index 7eda0fb21..3f51abb9a 100644 --- a/src/main/java/com/metaweb/gridworks/expr/functions/Ln.java +++ b/src/main/java/com/metaweb/gridworks/expr/functions/Ln.java @@ -5,15 +5,17 @@ import java.util.Properties; import org.json.JSONException; import org.json.JSONWriter; +import com.metaweb.gridworks.expr.ControlFunctionRegistry; import com.metaweb.gridworks.expr.Function; +import com.metaweb.gridworks.expr.EvalError; public class Ln implements Function { public Object call(Properties bindings, Object[] args) { - if (args.length == 1 && args[0] instanceof Number) { + if (args.length == 1 && args[0] != null && args[0] instanceof Number) { return Math.log(((Number) args[0]).doubleValue()); } - return null; + return new EvalError(ControlFunctionRegistry.getFunctionName(this) + " expects a number"); } public void write(JSONWriter writer, Properties options) diff --git a/src/main/java/com/metaweb/gridworks/expr/functions/Log.java b/src/main/java/com/metaweb/gridworks/expr/functions/Log.java index de4273e5a..f4d3a1578 100644 --- a/src/main/java/com/metaweb/gridworks/expr/functions/Log.java +++ b/src/main/java/com/metaweb/gridworks/expr/functions/Log.java @@ -5,15 +5,17 @@ import java.util.Properties; import org.json.JSONException; import org.json.JSONWriter; +import com.metaweb.gridworks.expr.ControlFunctionRegistry; import com.metaweb.gridworks.expr.Function; +import com.metaweb.gridworks.expr.EvalError; public class Log implements Function { public Object call(Properties bindings, Object[] args) { - if (args.length == 1 && args[0] instanceof Number) { + if (args.length == 1 && args[0] != null && args[0] instanceof Number) { return Math.log10(((Number) args[0]).doubleValue()); } - return null; + return new EvalError(ControlFunctionRegistry.getFunctionName(this) + " expects a number"); } public void write(JSONWriter writer, Properties options) diff --git a/src/main/java/com/metaweb/gridworks/expr/functions/Max.java b/src/main/java/com/metaweb/gridworks/expr/functions/Max.java index 33c0a9832..285c49a82 100644 --- a/src/main/java/com/metaweb/gridworks/expr/functions/Max.java +++ b/src/main/java/com/metaweb/gridworks/expr/functions/Max.java @@ -5,17 +5,21 @@ import java.util.Properties; import org.json.JSONException; import org.json.JSONWriter; +import com.metaweb.gridworks.expr.ControlFunctionRegistry; import com.metaweb.gridworks.expr.Function; +import com.metaweb.gridworks.expr.EvalError; public class Max implements Function { public Object call(Properties bindings, Object[] args) { - if (args.length == 2 && args[0] instanceof Number && args[1] instanceof Number) { + if (args.length == 2 && + args[0] != null && args[0] instanceof Number && + args[1] != null && args[1] instanceof Number) { return Math.max( ((Number) args[0]).doubleValue(), ((Number) args[1]).doubleValue()); } - return null; + return new EvalError(ControlFunctionRegistry.getFunctionName(this) + " expects 2 numbers"); } public void write(JSONWriter writer, Properties options) diff --git a/src/main/java/com/metaweb/gridworks/expr/functions/Min.java b/src/main/java/com/metaweb/gridworks/expr/functions/Min.java index 7df1b8f74..1d1272729 100644 --- a/src/main/java/com/metaweb/gridworks/expr/functions/Min.java +++ b/src/main/java/com/metaweb/gridworks/expr/functions/Min.java @@ -5,17 +5,21 @@ import java.util.Properties; import org.json.JSONException; import org.json.JSONWriter; +import com.metaweb.gridworks.expr.ControlFunctionRegistry; import com.metaweb.gridworks.expr.Function; +import com.metaweb.gridworks.expr.EvalError; public class Min implements Function { public Object call(Properties bindings, Object[] args) { - if (args.length == 2 && args[0] instanceof Number && args[1] instanceof Number) { + if (args.length == 2 && + args[0] != null && args[0] instanceof Number && + args[1] != null && args[1] instanceof Number) { return Math.min( ((Number) args[0]).doubleValue(), ((Number) args[1]).doubleValue()); } - return null; + return new EvalError(ControlFunctionRegistry.getFunctionName(this) + " expects 2 numbers"); } public void write(JSONWriter writer, Properties options) diff --git a/src/main/java/com/metaweb/gridworks/expr/functions/Mod.java b/src/main/java/com/metaweb/gridworks/expr/functions/Mod.java index 09dd2b0f8..873c296d7 100644 --- a/src/main/java/com/metaweb/gridworks/expr/functions/Mod.java +++ b/src/main/java/com/metaweb/gridworks/expr/functions/Mod.java @@ -5,18 +5,22 @@ import java.util.Properties; import org.json.JSONException; import org.json.JSONWriter; +import com.metaweb.gridworks.expr.ControlFunctionRegistry; import com.metaweb.gridworks.expr.Function; +import com.metaweb.gridworks.expr.EvalError; public class Mod implements Function { public Object call(Properties bindings, Object[] args) { - if (args.length == 2 && args[0] instanceof Number && args[1] instanceof Number) { + if (args.length == 2 && + args[0] != null && args[0] instanceof Number && + args[1] != null && args[1] instanceof Number) { int a = ((Number) args[0]).intValue(); int b = ((Number) args[0]).intValue(); return a % b; } - return null; + return new EvalError(ControlFunctionRegistry.getFunctionName(this) + " expects 2 numbers"); } public void write(JSONWriter writer, Properties options) diff --git a/src/main/java/com/metaweb/gridworks/expr/functions/Not.java b/src/main/java/com/metaweb/gridworks/expr/functions/Not.java index f639dcac5..0cfe0be5b 100644 --- a/src/main/java/com/metaweb/gridworks/expr/functions/Not.java +++ b/src/main/java/com/metaweb/gridworks/expr/functions/Not.java @@ -5,15 +5,17 @@ import java.util.Properties; import org.json.JSONException; import org.json.JSONWriter; +import com.metaweb.gridworks.expr.ControlFunctionRegistry; import com.metaweb.gridworks.expr.Function; +import com.metaweb.gridworks.expr.EvalError; public class Not implements Function { public Object call(Properties bindings, Object[] args) { - if (args.length > 0) { + if (args.length == 1) { return !objectToBoolean(args[0]); } - return true; + return new EvalError(ControlFunctionRegistry.getFunctionName(this) + " expects a boolean"); } public static boolean objectToBoolean(Object o) { diff --git a/src/main/java/com/metaweb/gridworks/expr/functions/Replace.java b/src/main/java/com/metaweb/gridworks/expr/functions/Replace.java index 2adea29e2..14a7cdf2b 100644 --- a/src/main/java/com/metaweb/gridworks/expr/functions/Replace.java +++ b/src/main/java/com/metaweb/gridworks/expr/functions/Replace.java @@ -5,7 +5,9 @@ import java.util.Properties; import org.json.JSONException; import org.json.JSONWriter; +import com.metaweb.gridworks.expr.ControlFunctionRegistry; import com.metaweb.gridworks.expr.Function; +import com.metaweb.gridworks.expr.EvalError; public class Replace implements Function { @@ -19,7 +21,7 @@ public class Replace implements Function { return (v instanceof String ? (String) v : v.toString()).replace((String) find, (String) replace); } } - return null; + return new EvalError(ControlFunctionRegistry.getFunctionName(this) + " expects 3 strings"); } diff --git a/src/main/java/com/metaweb/gridworks/expr/functions/Reverse.java b/src/main/java/com/metaweb/gridworks/expr/functions/Reverse.java index 6fad5ccd6..a5fccd941 100644 --- a/src/main/java/com/metaweb/gridworks/expr/functions/Reverse.java +++ b/src/main/java/com/metaweb/gridworks/expr/functions/Reverse.java @@ -5,7 +5,9 @@ import java.util.Properties; import org.json.JSONException; import org.json.JSONWriter; +import com.metaweb.gridworks.expr.ControlFunctionRegistry; import com.metaweb.gridworks.expr.Function; +import com.metaweb.gridworks.expr.EvalError; public class Reverse implements Function { @@ -24,7 +26,7 @@ public class Reverse implements Function { return r; } } - return null; + return new EvalError(ControlFunctionRegistry.getFunctionName(this) + " expects an array"); } public void write(JSONWriter writer, Properties options) diff --git a/src/main/java/com/metaweb/gridworks/expr/functions/Round.java b/src/main/java/com/metaweb/gridworks/expr/functions/Round.java index 397028716..9851f1544 100644 --- a/src/main/java/com/metaweb/gridworks/expr/functions/Round.java +++ b/src/main/java/com/metaweb/gridworks/expr/functions/Round.java @@ -5,15 +5,17 @@ import java.util.Properties; import org.json.JSONException; import org.json.JSONWriter; +import com.metaweb.gridworks.expr.ControlFunctionRegistry; import com.metaweb.gridworks.expr.Function; +import com.metaweb.gridworks.expr.EvalError; public class Round implements Function { public Object call(Properties bindings, Object[] args) { - if (args.length == 1 && args[0] instanceof Number) { + if (args.length == 1 && args[0] != null && args[0] instanceof Number) { return ((Number) args[0]).longValue(); } - return null; + return new EvalError(ControlFunctionRegistry.getFunctionName(this) + " expects a number"); } public void write(JSONWriter writer, Properties options) diff --git a/src/main/java/com/metaweb/gridworks/expr/functions/Sort.java b/src/main/java/com/metaweb/gridworks/expr/functions/Sort.java index bac802828..8934625e5 100644 --- a/src/main/java/com/metaweb/gridworks/expr/functions/Sort.java +++ b/src/main/java/com/metaweb/gridworks/expr/functions/Sort.java @@ -6,7 +6,9 @@ import java.util.Properties; import org.json.JSONException; import org.json.JSONWriter; +import com.metaweb.gridworks.expr.ControlFunctionRegistry; import com.metaweb.gridworks.expr.Function; +import com.metaweb.gridworks.expr.EvalError; public class Sort implements Function { @@ -24,7 +26,7 @@ public class Sort implements Function { return r; } } - return null; + return new EvalError(ControlFunctionRegistry.getFunctionName(this) + " expects an array"); } public void write(JSONWriter writer, Properties options) diff --git a/src/main/java/com/metaweb/gridworks/expr/functions/Split.java b/src/main/java/com/metaweb/gridworks/expr/functions/Split.java index e625393ec..d310573fa 100644 --- a/src/main/java/com/metaweb/gridworks/expr/functions/Split.java +++ b/src/main/java/com/metaweb/gridworks/expr/functions/Split.java @@ -5,7 +5,9 @@ import java.util.Properties; import org.json.JSONException; import org.json.JSONWriter; +import com.metaweb.gridworks.expr.ControlFunctionRegistry; import com.metaweb.gridworks.expr.Function; +import com.metaweb.gridworks.expr.EvalError; public class Split implements Function { @@ -17,7 +19,7 @@ public class Split implements Function { return (v instanceof String ? (String) v : v.toString()).split((String) split); } } - return null; + return new EvalError(ControlFunctionRegistry.getFunctionName(this) + " expects 2 strings"); } public void write(JSONWriter writer, Properties options) diff --git a/src/main/java/com/metaweb/gridworks/expr/functions/StartsWith.java b/src/main/java/com/metaweb/gridworks/expr/functions/StartsWith.java index bd52e4dbb..143c54866 100644 --- a/src/main/java/com/metaweb/gridworks/expr/functions/StartsWith.java +++ b/src/main/java/com/metaweb/gridworks/expr/functions/StartsWith.java @@ -5,7 +5,9 @@ import java.util.Properties; import org.json.JSONException; import org.json.JSONWriter; +import com.metaweb.gridworks.expr.ControlFunctionRegistry; import com.metaweb.gridworks.expr.Function; +import com.metaweb.gridworks.expr.EvalError; public class StartsWith implements Function { @@ -17,7 +19,7 @@ public class StartsWith implements Function { return ((String) s1).startsWith((String) s2); } } - return null; + return new EvalError(ControlFunctionRegistry.getFunctionName(this) + " expects 2 strings"); } public void write(JSONWriter writer, Properties options) throws JSONException { diff --git a/src/main/java/com/metaweb/gridworks/expr/functions/ToLowercase.java b/src/main/java/com/metaweb/gridworks/expr/functions/ToLowercase.java index c6877034e..49c8a0cce 100644 --- a/src/main/java/com/metaweb/gridworks/expr/functions/ToLowercase.java +++ b/src/main/java/com/metaweb/gridworks/expr/functions/ToLowercase.java @@ -5,7 +5,9 @@ import java.util.Properties; import org.json.JSONException; import org.json.JSONWriter; +import com.metaweb.gridworks.expr.ControlFunctionRegistry; import com.metaweb.gridworks.expr.Function; +import com.metaweb.gridworks.expr.EvalError; public class ToLowercase implements Function { @@ -14,7 +16,7 @@ public class ToLowercase implements Function { Object o = args[0]; return (o instanceof String ? (String) o : o.toString()).toLowerCase(); } - return null; + return new EvalError(ControlFunctionRegistry.getFunctionName(this) + " expects a string"); } public void write(JSONWriter writer, Properties options) diff --git a/src/main/java/com/metaweb/gridworks/expr/functions/ToTitlecase.java b/src/main/java/com/metaweb/gridworks/expr/functions/ToTitlecase.java index 8963eb8e2..c357484c6 100644 --- a/src/main/java/com/metaweb/gridworks/expr/functions/ToTitlecase.java +++ b/src/main/java/com/metaweb/gridworks/expr/functions/ToTitlecase.java @@ -5,7 +5,9 @@ import java.util.Properties; import org.json.JSONException; import org.json.JSONWriter; +import com.metaweb.gridworks.expr.ControlFunctionRegistry; import com.metaweb.gridworks.expr.Function; +import com.metaweb.gridworks.expr.EvalError; public class ToTitlecase implements Function { @@ -28,7 +30,7 @@ public class ToTitlecase implements Function { return sb.toString(); } - return null; + return new EvalError(ControlFunctionRegistry.getFunctionName(this) + " expects a string"); } public void write(JSONWriter writer, Properties options) diff --git a/src/main/java/com/metaweb/gridworks/expr/functions/ToUppercase.java b/src/main/java/com/metaweb/gridworks/expr/functions/ToUppercase.java index 0e236580e..dbfd58e62 100644 --- a/src/main/java/com/metaweb/gridworks/expr/functions/ToUppercase.java +++ b/src/main/java/com/metaweb/gridworks/expr/functions/ToUppercase.java @@ -5,7 +5,9 @@ import java.util.Properties; import org.json.JSONException; import org.json.JSONWriter; +import com.metaweb.gridworks.expr.ControlFunctionRegistry; import com.metaweb.gridworks.expr.Function; +import com.metaweb.gridworks.expr.EvalError; public class ToUppercase implements Function { @@ -14,7 +16,7 @@ public class ToUppercase implements Function { Object o = args[0]; return (o instanceof String ? (String) o : o.toString()).toUpperCase(); } - return null; + return new EvalError(ControlFunctionRegistry.getFunctionName(this) + " expects a string"); } public void write(JSONWriter writer, Properties options) diff --git a/src/main/java/com/metaweb/gridworks/importers/ImporterUtilities.java b/src/main/java/com/metaweb/gridworks/importers/ImporterUtilities.java index f1a3c6f3b..96d232290 100644 --- a/src/main/java/com/metaweb/gridworks/importers/ImporterUtilities.java +++ b/src/main/java/com/metaweb/gridworks/importers/ImporterUtilities.java @@ -53,11 +53,11 @@ public class ImporterUtilities { } Object value = parseCellValue(text); - if (ExpressionUtils.isBlank(value)) { - row.cells.add(null); - } else { - row.cells.add(new Cell(value, null)); + if (ExpressionUtils.isNonBlankData(value)) { + row.cells.add(new Cell(value, null)); hasData = true; + } else { + row.cells.add(null); } } @@ -72,11 +72,11 @@ public class ImporterUtilities { String text = cells[c]; Object value = parseCellValue(text); - if (ExpressionUtils.isBlank(value)) { - row.cells.add(null); - } else { + if (ExpressionUtils.isNonBlankData(value)) { row.cells.add(new Cell(value, null)); hasData = true; + } else { + row.cells.add(null); } } return hasData; diff --git a/src/main/java/com/metaweb/gridworks/model/Project.java b/src/main/java/com/metaweb/gridworks/model/Project.java index e4f5e95a8..694709f0c 100644 --- a/src/main/java/com/metaweb/gridworks/model/Project.java +++ b/src/main/java/com/metaweb/gridworks/model/Project.java @@ -92,11 +92,11 @@ public class Project implements Serializable { for (int g = 0; g < keyedGroups.size(); g++) { Group group = keyedGroups.get(g); - if (ExpressionUtils.isBlank(row.getCellValue(group.keyCellIndex))) { + if (!ExpressionUtils.isNonBlankData(row.getCellValue(group.keyCellIndex))) { int contextRowIndex = lastNonBlankRowsByGroup[g]; if (contextRowIndex >= 0) { for (int dependentCellIndex : group.cellIndices) { - if (!ExpressionUtils.isBlank(row.getCellValue(dependentCellIndex))) { + if (ExpressionUtils.isNonBlankData(row.getCellValue(dependentCellIndex))) { setRowDependency( row, dependentCellIndex, diff --git a/src/main/java/com/metaweb/gridworks/model/ReconStats.java b/src/main/java/com/metaweb/gridworks/model/ReconStats.java index 8d15e43d9..69fec08a2 100644 --- a/src/main/java/com/metaweb/gridworks/model/ReconStats.java +++ b/src/main/java/com/metaweb/gridworks/model/ReconStats.java @@ -40,7 +40,7 @@ public class ReconStats implements Serializable, Jsonizable { for (Row row : project.rows) { Cell cell = row.getCell(cellIndex); - if (cell != null && !ExpressionUtils.isBlank(cell.value)) { + if (cell != null && ExpressionUtils.isNonBlankData(cell.value)) { nonBlanks++; if (cell.recon != null) { diff --git a/src/main/java/com/metaweb/gridworks/operations/MultiValuedCellJoinOperation.java b/src/main/java/com/metaweb/gridworks/operations/MultiValuedCellJoinOperation.java index 37ed3a7c1..6cf0a4e22 100644 --- a/src/main/java/com/metaweb/gridworks/operations/MultiValuedCellJoinOperation.java +++ b/src/main/java/com/metaweb/gridworks/operations/MultiValuedCellJoinOperation.java @@ -95,7 +95,7 @@ public class MultiValuedCellJoinOperation extends AbstractOperation { StringBuffer sb = new StringBuffer(); for (int r3 = r; r3 < r2; r3++) { Object value = project.rows.get(r3).getCellValue(cellIndex); - if (!ExpressionUtils.isBlank(value)) { + if (ExpressionUtils.isNonBlankData(value)) { if (sb.length() > 0) { sb.append(_separator); } diff --git a/src/main/java/com/metaweb/gridworks/operations/ReconJudgeSimilarCellsOperation.java b/src/main/java/com/metaweb/gridworks/operations/ReconJudgeSimilarCellsOperation.java index 2539f5d1d..33cd2634f 100644 --- a/src/main/java/com/metaweb/gridworks/operations/ReconJudgeSimilarCellsOperation.java +++ b/src/main/java/com/metaweb/gridworks/operations/ReconJudgeSimilarCellsOperation.java @@ -164,7 +164,7 @@ public class ReconJudgeSimilarCellsOperation extends EngineDependentMassCellOper public boolean visit(Project project, int rowIndex, Row row, boolean contextual) { Cell cell = row.getCell(_cellIndex); if (cell != null && - !ExpressionUtils.isBlank(cell.value) && + ExpressionUtils.isNonBlankData(cell.value) && _similarValue.equals(cell.value)) { Recon recon = null; diff --git a/src/main/java/com/metaweb/gridworks/operations/ReconOperation.java b/src/main/java/com/metaweb/gridworks/operations/ReconOperation.java index 0cde4997c..af1e92c88 100644 --- a/src/main/java/com/metaweb/gridworks/operations/ReconOperation.java +++ b/src/main/java/com/metaweb/gridworks/operations/ReconOperation.java @@ -152,7 +152,7 @@ public class ReconOperation extends EngineDependentOperation { public boolean visit(Project project, int rowIndex, Row row, boolean contextual) { if (_cellIndex < row.cells.size()) { Cell cell = row.cells.get(_cellIndex); - if (cell != null && !ExpressionUtils.isBlank(cell.value)) { + if (cell != null && ExpressionUtils.isNonBlankData(cell.value)) { _entries.add(new ReconEntry(rowIndex, cell)); } } diff --git a/src/main/java/com/metaweb/gridworks/protograph/transpose/Transposer.java b/src/main/java/com/metaweb/gridworks/protograph/transpose/Transposer.java index fe0f39fb2..df07f6bc7 100644 --- a/src/main/java/com/metaweb/gridworks/protograph/transpose/Transposer.java +++ b/src/main/java/com/metaweb/gridworks/protograph/transpose/Transposer.java @@ -54,7 +54,7 @@ public class Transposer { CellNode node2 = (CellNode) node; Column column = project.columnModel.getColumnByName(node2.columnName); Cell cell = row.getCell(column.getCellIndex()); - if (cell != null && !ExpressionUtils.isBlank(cell.value)) { + if (cell != null && ExpressionUtils.isNonBlankData(cell.value)) { if (node2 instanceof CellTopicNode) { if (!((CellTopicNode) node2).createForNoReconMatch && (cell.recon == null || cell.recon.judgment == Judgment.None)) { diff --git a/src/main/webapp/scripts/dialogs/expression-preview-dialog.js b/src/main/webapp/scripts/dialogs/expression-preview-dialog.js index 5df517f1d..82d573691 100644 --- a/src/main/webapp/scripts/dialogs/expression-preview-dialog.js +++ b/src/main/webapp/scripts/dialogs/expression-preview-dialog.js @@ -170,13 +170,13 @@ ExpressionPreviewDialog.prototype._update = function() { } else { self._results = null; } - self._renderPreview(expression); + self._renderPreview(expression, data); }, "json" ); }; -ExpressionPreviewDialog.prototype._renderPreview = function(expression) { +ExpressionPreviewDialog.prototype._renderPreview = function(expression, data) { var container = this._elmts.previewContainer.empty(); var table = $('
').appendTo(container)[0]; @@ -211,7 +211,10 @@ ExpressionPreviewDialog.prototype._renderPreview = function(expression) { var v = this._results[i]; renderValue(tdValue, v); } else { - $('error').addClass("expression-preview-empty").appendTo(tdValue); + // error + + var message = (data.type == "parser") ? data.message : "internal error"; + $('').text(message).addClass("expression-preview-empty").appendTo(tdValue); } } }; \ No newline at end of file diff --git a/src/site/index.html b/src/site/index.html index 4dcdd0ad4..8584c361b 100644 --- a/src/site/index.html +++ b/src/site/index.html @@ -82,11 +82,11 @@

Mac OSX

- +
@@ -96,11 +96,11 @@
-

Gridworks-1.0.dmg

+

Gridworks-1.0a.dmg

Download, open, then drag
icon to Applications folder

Windows

- +
-

Gridworks-1.0.zip

+

Gridworks-1.0a.zip

Download, unzip, and
run .exe inside