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
This commit is contained in:
David Huynh 2010-02-27 05:48:33 +00:00
parent f0b8268809
commit c914aa6c16
50 changed files with 456 additions and 261 deletions

View File

@ -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);

View File

@ -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<String, Function> entry : Parser.functionTable.entrySet()) {
for (Entry<String, Function> 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<String, Control> entry : Parser.controlTable.entrySet()) {
for (Entry<String, Control> entry : ControlFunctionRegistry.getControlMapping()) {
writer.key(entry.getKey());
entry.getValue().write(writer, options);
}

View File

@ -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);

View File

@ -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();

View File

@ -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);
}

View File

@ -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<String, Function> s_nameToFunction = new HashMap<String, Function>();
static private Map<Function, String> s_functionToName = new HashMap<Function, String>();
static private Map<String, Control> s_nameToControl = new HashMap<String, Control>();
static private Map<Control, String> s_controlToName = new HashMap<Control, String>();
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<Entry<String, Function>> 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<Entry<String, Control>> 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());
}
}

View File

@ -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();
}
}

View File

@ -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 &&

View File

@ -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

View File

@ -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);
}

View File

@ -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) {

View File

@ -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<String, Function> functionTable = new HashMap<String, Function>();
static public Map<String, Control> controlTable = new HashMap<String, Control>();
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<Evaluable> 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<Evaluable> 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<Evaluable> parseExpressionList(String closingDelimiter) throws Exception {
protected List<Evaluable> parseExpressionList(String closingDelimiter) throws ParserException {
List<Evaluable> l = new LinkedList<Evaluable>();
if (_token != null &&

View File

@ -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() {

View File

@ -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<Object> results = new ArrayList<Object>(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<Object> results = new ArrayList<Object>(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 {

View File

@ -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 {

View File

@ -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 {

View File

@ -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 {

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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();

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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) {

View File

@ -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");
}

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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 {

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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;

View File

@ -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,

View File

@ -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) {

View File

@ -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);
}

View File

@ -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;

View File

@ -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));
}
}

View File

@ -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)) {

View File

@ -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 = $('<table width="100%"></table>').appendTo(container)[0];
@ -211,7 +211,10 @@ ExpressionPreviewDialog.prototype._renderPreview = function(expression) {
var v = this._results[i];
renderValue(tdValue, v);
} else {
$('<span>error</span>').addClass("expression-preview-empty").appendTo(tdValue);
// error
var message = (data.type == "parser") ? data.message : "internal error";
$('<span></span>').text(message).addClass("expression-preview-empty").appendTo(tdValue);
}
}
};

View File

@ -82,11 +82,11 @@
<td><div>
<h2>Mac OSX</h2>
<center>
<a class="download-link" href="gridworks-1.0.dmg"><table class="download-card">
<a class="download-link" href="gridworks-1.0a.dmg"><table class="download-card">
<tr>
<td width="1%"><img src="gridworks.png" /></td>
<td>
<h3>Gridworks-1.0.dmg</h3>
<h3>Gridworks-1.0a.dmg</h3>
<div class="instructions">Download, open, then drag<br/>icon to Applications folder</div>
</td>
</tr>
@ -96,11 +96,11 @@
<td><div>
<h2>Windows</h2>
<center>
<a class="download-link" href="gridworks-1.0.zip"><table class="download-card">
<a class="download-link" href="gridworks-1.0a.zip"><table class="download-card">
<tr>
<td width="1%"><img src="gridworks.png" /></td>
<td>
<h3>Gridworks-1.0.zip</h3>
<h3>Gridworks-1.0a.zip</h3>
<div class="instructions">Download, unzip, and<br/>run .exe inside</div>
</td>
</tr>