Additions to GREL:

* modulo operator, %
* cos, sin and tan functions
* acos, asin, atan and atan2 functions
* cosh, sinh and tanh functions
* fact and combin functions
* degrees and radians functions
* odd and even functions

git-svn-id: http://google-refine.googlecode.com/svn/trunk@1908 7d457c2a-affb-35e4-300a-418c747d4874
This commit is contained in:
Iain Sproat 2010-11-20 12:11:37 +00:00
parent 1ec7cb9f7b
commit f1643565b8
20 changed files with 1255 additions and 171 deletions

View File

@ -0,0 +1,63 @@
/*
Copyright 2010, Google Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.google.refine.expr.functions.math;
import java.util.Properties;
import org.json.JSONException;
import org.json.JSONWriter;
import com.google.refine.expr.EvalError;
import com.google.refine.grel.ControlFunctionRegistry;
import com.google.refine.grel.Function;
public class ACos implements Function {
public Object call(Properties bindings, Object[] args) {
if (args.length == 1 && args[0] != null && args[0] instanceof Number) {
return Math.acos(((Number) args[0]).doubleValue());
}
return new EvalError(ControlFunctionRegistry.getFunctionName(this) + " expects a number");
}
public void write(JSONWriter writer, Properties options)
throws JSONException {
writer.object();
writer.key("description"); writer.value("Returns the arc cosine of an angle, in the range 0 through PI");
writer.key("params"); writer.value("number d");
writer.key("returns"); writer.value("number");
writer.endObject();
}
}

View File

@ -0,0 +1,63 @@
/*
Copyright 2010, Google Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.google.refine.expr.functions.math;
import java.util.Properties;
import org.json.JSONException;
import org.json.JSONWriter;
import com.google.refine.expr.EvalError;
import com.google.refine.grel.ControlFunctionRegistry;
import com.google.refine.grel.Function;
public class ASin implements Function {
public Object call(Properties bindings, Object[] args) {
if (args.length == 1 && args[0] != null && args[0] instanceof Number) {
return Math.asin(((Number) args[0]).doubleValue());
}
return new EvalError(ControlFunctionRegistry.getFunctionName(this) + " expects a number");
}
public void write(JSONWriter writer, Properties options)
throws JSONException {
writer.object();
writer.key("description"); writer.value("Returns the arc sine of an angle in the range of -PI/2 through PI/2");
writer.key("params"); writer.value("number d");
writer.key("returns"); writer.value("number");
writer.endObject();
}
}

View File

@ -0,0 +1,63 @@
/*
Copyright 2010, Google Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.google.refine.expr.functions.math;
import java.util.Properties;
import org.json.JSONException;
import org.json.JSONWriter;
import com.google.refine.expr.EvalError;
import com.google.refine.grel.ControlFunctionRegistry;
import com.google.refine.grel.Function;
public class ATan implements Function {
public Object call(Properties bindings, Object[] args) {
if (args.length == 1 && args[0] != null && args[0] instanceof Number) {
return Math.atan(((Number) args[0]).doubleValue());
}
return new EvalError(ControlFunctionRegistry.getFunctionName(this) + " expects a number");
}
public void write(JSONWriter writer, Properties options)
throws JSONException {
writer.object();
writer.key("description"); writer.value("Returns the arc tangent of an angle in the range of -PI/2 through PI/2");
writer.key("params"); writer.value("number d");
writer.key("returns"); writer.value("number");
writer.endObject();
}
}

View File

@ -0,0 +1,64 @@
/*
Copyright 2010, Google Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.google.refine.expr.functions.math;
import java.util.Properties;
import org.json.JSONException;
import org.json.JSONWriter;
import com.google.refine.expr.EvalError;
import com.google.refine.grel.ControlFunctionRegistry;
import com.google.refine.grel.Function;
public class ATan2 implements Function {
public Object call(Properties bindings, Object[] args) {
if (args.length == 2 && args[0] != null && args[0] instanceof Number
&& args[1] != null && args[1] instanceof Number) {
return Math.atan2(((Number) args[0]).doubleValue(),((Number) args[1]).doubleValue());
}
return new EvalError(ControlFunctionRegistry.getFunctionName(this) + " expects a number");
}
public void write(JSONWriter writer, Properties options)
throws JSONException {
writer.object();
writer.key("description"); writer.value("Converts rectangular coordinates (x, y) to polar (r, theta)");
writer.key("params"); writer.value("number x, number y");
writer.key("returns"); writer.value("number theta");
writer.endObject();
}
}

View File

@ -0,0 +1,78 @@
/*
Copyright 2010, Google Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.google.refine.expr.functions.math;
import java.util.Properties;
import org.json.JSONException;
import org.json.JSONWriter;
import com.google.refine.expr.EvalError;
import com.google.refine.grel.ControlFunctionRegistry;
import com.google.refine.grel.Function;
public class Combin implements Function {
public Object call(Properties bindings, Object[] args) {
if(args.length != 2)
return new EvalError(ControlFunctionRegistry.getFunctionName(this) + " expects two numbers");
if(args[0] == null || !(args[0] instanceof Number))
return new EvalError(ControlFunctionRegistry.getFunctionName(this) + " expects the first argument to be a number");
if(args[1] == null || !(args[1] instanceof Number))
return new EvalError(ControlFunctionRegistry.getFunctionName(this) + " expects the second argument to be a number");
return Combin.Combination(((Number) args[0]).intValue(), ((Number) args[1]).intValue());
}
public static int Combination(int n, int k){
if (k > n)
throw new IllegalArgumentException ("the number of elements, n, should be larger than the number of combinations, k");
if (n < 1)
throw new IllegalArgumentException ("the number of elements, n, cannot be less than 1");
int nFact = Fact.factorial(n);
int rFact = Fact.factorial(k);
int nminusrFact = Fact.factorial(n - k);
return nFact / (rFact * nminusrFact);
}
public void write(JSONWriter writer, Properties options)
throws JSONException {
writer.object();
writer.key("description"); writer.value("Returns the number of combinations for n elements as divided into k");
writer.key("params"); writer.value("number d");
writer.key("returns"); writer.value("number");
writer.endObject();
}
}

View File

@ -0,0 +1,63 @@
/*
Copyright 2010, Google Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.google.refine.expr.functions.math;
import java.util.Properties;
import org.json.JSONException;
import org.json.JSONWriter;
import com.google.refine.expr.EvalError;
import com.google.refine.grel.ControlFunctionRegistry;
import com.google.refine.grel.Function;
public class Cos implements Function {
public Object call(Properties bindings, Object[] args) {
if (args.length == 1 && args[0] != null && args[0] instanceof Number) {
return Math.cos(((Number) args[0]).doubleValue());
}
return new EvalError(ControlFunctionRegistry.getFunctionName(this) + " expects a number");
}
public void write(JSONWriter writer, Properties options)
throws JSONException {
writer.object();
writer.key("description"); writer.value("Returns the trigonometric cosine of an angle");
writer.key("params"); writer.value("number d");
writer.key("returns"); writer.value("number");
writer.endObject();
}
}

View File

@ -0,0 +1,63 @@
/*
Copyright 2010, Google Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.google.refine.expr.functions.math;
import java.util.Properties;
import org.json.JSONException;
import org.json.JSONWriter;
import com.google.refine.expr.EvalError;
import com.google.refine.grel.ControlFunctionRegistry;
import com.google.refine.grel.Function;
public class Cosh implements Function {
public Object call(Properties bindings, Object[] args) {
if (args.length == 1 && args[0] != null && args[0] instanceof Number) {
return StrictMath.cosh(((Number) args[0]).doubleValue());
}
return new EvalError(ControlFunctionRegistry.getFunctionName(this) + " expects a number");
}
public void write(JSONWriter writer, Properties options)
throws JSONException {
writer.object();
writer.key("description"); writer.value("Returns the hyperbolic cosine of a value");
writer.key("params"); writer.value("number d");
writer.key("returns"); writer.value("number");
writer.endObject();
}
}

View File

@ -0,0 +1,63 @@
/*
Copyright 2010, Google Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.google.refine.expr.functions.math;
import java.util.Properties;
import org.json.JSONException;
import org.json.JSONWriter;
import com.google.refine.expr.EvalError;
import com.google.refine.grel.ControlFunctionRegistry;
import com.google.refine.grel.Function;
public class Degrees implements Function {
public Object call(Properties bindings, Object[] args) {
if (args.length == 1 && args[0] != null && args[0] instanceof Number) {
return Math.toDegrees(((Number) args[0]).doubleValue());
}
return new EvalError(ControlFunctionRegistry.getFunctionName(this) + " expects a number");
}
public void write(JSONWriter writer, Properties options)
throws JSONException {
writer.object();
writer.key("description"); writer.value("Converts an angle from radians to degrees.");
writer.key("params"); writer.value("number d");
writer.key("returns"); writer.value("number");
writer.endObject();
}
}

View File

@ -0,0 +1,68 @@
/*
Copyright 2010, Google Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.google.refine.expr.functions.math;
import java.util.Properties;
import org.json.JSONException;
import org.json.JSONWriter;
import com.google.refine.expr.EvalError;
import com.google.refine.grel.ControlFunctionRegistry;
import com.google.refine.grel.Function;
public class Even implements Function {
public Object call(Properties bindings, Object[] args) {
if (args.length == 1 && args[0] != null && args[0] instanceof Number) {
return Even.RoundUpToEven(((Number) args[0]).doubleValue());
}
return new EvalError(ControlFunctionRegistry.getFunctionName(this) + " expects a number");
}
public static double RoundUpToEven(double d){
double temp = Math.ceil(d);
return ((temp % 2) == 0) ? temp : temp+1;
}
public void write(JSONWriter writer, Properties options)
throws JSONException {
writer.object();
writer.key("description"); writer.value("Rounds the number up to the nearest even integer");
writer.key("params"); writer.value("number d");
writer.key("returns"); writer.value("number");
writer.endObject();
}
}

View File

@ -0,0 +1,74 @@
/*
Copyright 2010, Google Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.google.refine.expr.functions.math;
import java.util.Properties;
import org.json.JSONException;
import org.json.JSONWriter;
import com.google.refine.expr.EvalError;
import com.google.refine.grel.ControlFunctionRegistry;
import com.google.refine.grel.Function;
public class Fact implements Function {
public Object call(Properties bindings, Object[] args) {
if (args.length == 1 && args[0] != null && args[0] instanceof Number) {
return Fact.factorial(((Number) args[0]).intValue());
}
return new EvalError(ControlFunctionRegistry.getFunctionName(this) + " expects a number");
}
/*
* Calculates the factorial of an integer, i.
* Returns 1 for zero and negative integers.
*/
public static int factorial(int i){
if(i <= 1)
return 1;
else
return i * Fact.factorial(i - 1);
}
public void write(JSONWriter writer, Properties options)
throws JSONException {
writer.object();
writer.key("description"); writer.value("Returns the factorial of a number");
writer.key("params"); writer.value("number i");
writer.key("returns"); writer.value("number");
writer.endObject();
}
}

View File

@ -0,0 +1,68 @@
/*
Copyright 2010, Google Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.google.refine.expr.functions.math;
import java.util.Properties;
import org.json.JSONException;
import org.json.JSONWriter;
import com.google.refine.expr.EvalError;
import com.google.refine.grel.ControlFunctionRegistry;
import com.google.refine.grel.Function;
public class Odd implements Function {
public Object call(Properties bindings, Object[] args) {
if (args.length == 1 && args[0] != null && args[0] instanceof Number) {
return Odd.RoundUpToOdd(((Number) args[0]).doubleValue());
}
return new EvalError(ControlFunctionRegistry.getFunctionName(this) + " expects a number");
}
public static double RoundUpToOdd(double d){
double temp = Math.ceil(d);
return ((temp % 2) == 0) ? temp + 1 : temp;
}
public void write(JSONWriter writer, Properties options)
throws JSONException {
writer.object();
writer.key("description"); writer.value("Rounds the number up to the nearest even integer");
writer.key("params"); writer.value("number d");
writer.key("returns"); writer.value("number");
writer.endObject();
}
}

View File

@ -0,0 +1,63 @@
/*
Copyright 2010, Google Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.google.refine.expr.functions.math;
import java.util.Properties;
import org.json.JSONException;
import org.json.JSONWriter;
import com.google.refine.expr.EvalError;
import com.google.refine.grel.ControlFunctionRegistry;
import com.google.refine.grel.Function;
public class Radians implements Function {
public Object call(Properties bindings, Object[] args) {
if (args.length == 1 && args[0] != null && args[0] instanceof Number) {
return Math.toRadians(((Number) args[0]).doubleValue());
}
return new EvalError(ControlFunctionRegistry.getFunctionName(this) + " expects a number");
}
public void write(JSONWriter writer, Properties options)
throws JSONException {
writer.object();
writer.key("description"); writer.value("Converts an angle in degrees to radians");
writer.key("params"); writer.value("number d");
writer.key("returns"); writer.value("number");
writer.endObject();
}
}

View File

@ -0,0 +1,63 @@
/*
Copyright 2010, Google Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.google.refine.expr.functions.math;
import java.util.Properties;
import org.json.JSONException;
import org.json.JSONWriter;
import com.google.refine.expr.EvalError;
import com.google.refine.grel.ControlFunctionRegistry;
import com.google.refine.grel.Function;
public class Sin implements Function {
public Object call(Properties bindings, Object[] args) {
if (args.length == 1 && args[0] != null && args[0] instanceof Number) {
return Math.sin(((Number) args[0]).doubleValue());
}
return new EvalError(ControlFunctionRegistry.getFunctionName(this) + " expects a number");
}
public void write(JSONWriter writer, Properties options)
throws JSONException {
writer.object();
writer.key("description"); writer.value("Returns the trigonometric sine of an angle");
writer.key("params"); writer.value("number d");
writer.key("returns"); writer.value("number");
writer.endObject();
}
}

View File

@ -0,0 +1,63 @@
/*
Copyright 2010, Google Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.google.refine.expr.functions.math;
import java.util.Properties;
import org.json.JSONException;
import org.json.JSONWriter;
import com.google.refine.expr.EvalError;
import com.google.refine.grel.ControlFunctionRegistry;
import com.google.refine.grel.Function;
public class Sinh implements Function {
public Object call(Properties bindings, Object[] args) {
if (args.length == 1 && args[0] != null && args[0] instanceof Number) {
return StrictMath.sinh(((Number) args[0]).doubleValue());
}
return new EvalError(ControlFunctionRegistry.getFunctionName(this) + " expects a number");
}
public void write(JSONWriter writer, Properties options)
throws JSONException {
writer.object();
writer.key("description"); writer.value("Returns the hyperbolic sine of an angle");
writer.key("params"); writer.value("number d");
writer.key("returns"); writer.value("number");
writer.endObject();
}
}

View File

@ -0,0 +1,63 @@
/*
Copyright 2010, Google Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.google.refine.expr.functions.math;
import java.util.Properties;
import org.json.JSONException;
import org.json.JSONWriter;
import com.google.refine.expr.EvalError;
import com.google.refine.grel.ControlFunctionRegistry;
import com.google.refine.grel.Function;
public class Tan implements Function {
public Object call(Properties bindings, Object[] args) {
if (args.length == 1 && args[0] != null && args[0] instanceof Number) {
return Math.tan(((Number) args[0]).doubleValue());
}
return new EvalError(ControlFunctionRegistry.getFunctionName(this) + " expects a number");
}
public void write(JSONWriter writer, Properties options)
throws JSONException {
writer.object();
writer.key("description"); writer.value("Returns the trigonometric tangent of an angle");
writer.key("params"); writer.value("number d");
writer.key("returns"); writer.value("number");
writer.endObject();
}
}

View File

@ -0,0 +1,63 @@
/*
Copyright 2010, Google Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.google.refine.expr.functions.math;
import java.util.Properties;
import org.json.JSONException;
import org.json.JSONWriter;
import com.google.refine.expr.EvalError;
import com.google.refine.grel.ControlFunctionRegistry;
import com.google.refine.grel.Function;
public class Tanh implements Function {
public Object call(Properties bindings, Object[] args) {
if (args.length == 1 && args[0] != null && args[0] instanceof Number) {
return StrictMath.tanh(((Number) args[0]).doubleValue());
}
return new EvalError(ControlFunctionRegistry.getFunctionName(this) + " expects a number");
}
public void write(JSONWriter writer, Properties options)
throws JSONException {
writer.object();
writer.key("description"); writer.value("Returns the hyperbolic tangent of a value");
writer.key("params"); writer.value("number d");
writer.key("returns"); writer.value("number");
writer.endObject();
}
}

View File

@ -23,8 +23,8 @@ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@ -59,18 +59,34 @@ import com.google.refine.expr.functions.booleans.Or;
import com.google.refine.expr.functions.date.DatePart;
import com.google.refine.expr.functions.date.Inc;
import com.google.refine.expr.functions.date.Now;
import com.google.refine.expr.functions.math.ACos;
import com.google.refine.expr.functions.math.ASin;
import com.google.refine.expr.functions.math.ATan;
import com.google.refine.expr.functions.math.ATan2;
import com.google.refine.expr.functions.math.Abs;
import com.google.refine.expr.functions.math.Ceil;
import com.google.refine.expr.functions.math.Combin;
import com.google.refine.expr.functions.math.Cos;
import com.google.refine.expr.functions.math.Cosh;
import com.google.refine.expr.functions.math.Degrees;
import com.google.refine.expr.functions.math.Even;
import com.google.refine.expr.functions.math.Exp;
import com.google.refine.expr.functions.math.Fact;
import com.google.refine.expr.functions.math.Floor;
import com.google.refine.expr.functions.math.Ln;
import com.google.refine.expr.functions.math.Log;
import com.google.refine.expr.functions.math.Max;
import com.google.refine.expr.functions.math.Min;
import com.google.refine.expr.functions.math.Mod;
import com.google.refine.expr.functions.math.Odd;
import com.google.refine.expr.functions.math.Pow;
import com.google.refine.expr.functions.math.Radians;
import com.google.refine.expr.functions.math.Round;
import com.google.refine.expr.functions.math.Sin;
import com.google.refine.expr.functions.math.Sinh;
import com.google.refine.expr.functions.math.Sum;
import com.google.refine.expr.functions.math.Tan;
import com.google.refine.expr.functions.math.Tanh;
import com.google.refine.expr.functions.strings.Chomp;
import com.google.refine.expr.functions.strings.Contains;
import com.google.refine.expr.functions.strings.Diff;
@ -212,9 +228,21 @@ public class ControlFunctionRegistry {
registerFunction("inc", new Inc());
registerFunction("datePart", new DatePart());
registerFunction("acos", new ACos());
registerFunction("asin", new ASin());
registerFunction("atan", new ATan());
registerFunction("atan2", new ATan2());
registerFunction("cos", new Cos());
registerFunction("cosh", new Cosh());
registerFunction("sin", new Sin());
registerFunction("sinh", new Sinh());
registerFunction("tan", new Tan());
registerFunction("tanh", new Tanh());
registerFunction("round", new Round());
registerFunction("floor", new Floor());
registerFunction("ceil", new Ceil());
registerFunction("even", new Even());
registerFunction("odd", new Odd());
registerFunction("abs", new Abs());
registerFunction("mod", new Mod());
registerFunction("max", new Max());
@ -224,6 +252,10 @@ public class ControlFunctionRegistry {
registerFunction("pow", new Pow());
registerFunction("exp", new Exp());
registerFunction("sum", new Sum());
registerFunction("fact", new Fact());
registerFunction("comb", new Combin());
registerFunction("degrees", new Degrees());
registerFunction("radians", new Radians());
registerFunction("and", new And());
registerFunction("or", new Or());

View File

@ -23,8 +23,8 @@ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@ -55,125 +55,125 @@ public class Parser {
protected Scanner _scanner;
protected Token _token;
protected Evaluable _root;
public Parser(String s) throws ParsingException {
this(s, 0, s.length());
}
public Parser(String s, int from, int to) throws ParsingException {
_scanner = new Scanner(s, from, to);
_token = _scanner.next(true);
_root = parseExpression();
}
public Evaluable getExpression() {
return _root;
}
protected void next(boolean regexPossible) {
_token = _scanner.next(regexPossible);
}
protected ParsingException makeException(String desc) {
int index = _token != null ? _token.start : _scanner.getIndex();
return new ParsingException("Parsing error at offset " + index + ": " + desc);
}
/**
* <expression> := <sub-expression>
* | <expression> [ "<" "<=" ">" ">=" "==" "!=" ] <sub-expression>
*/
protected Evaluable parseExpression() throws ParsingException {
Evaluable sub = parseSubExpression();
while (_token != null &&
_token.type == TokenType.Operator &&
while (_token != null &&
_token.type == TokenType.Operator &&
">=<==!=".indexOf(_token.text) >= 0) {
String op = _token.text;
next(true);
Evaluable sub2 = parseSubExpression();
sub = new OperatorCallExpr(new Evaluable[] { sub, sub2 }, op);
}
return sub;
}
/**
* <sub-expression> := <term>
* | <sub-expression> [ "+" "-" ] <term>
*/
protected Evaluable parseSubExpression() throws ParsingException {
Evaluable sub = parseTerm();
while (_token != null &&
_token.type == TokenType.Operator &&
while (_token != null &&
_token.type == TokenType.Operator &&
"+-".indexOf(_token.text) >= 0) {
String op = _token.text;
next(true);
Evaluable sub2 = parseSubExpression();
sub = new OperatorCallExpr(new Evaluable[] { sub, sub2 }, op);
}
return sub;
}
/**
* <term> := <factor>
* | <term> [ "*" "/" ] <factor>
* | <term> [ "*" "/" "%" ] <factor>
*/
protected Evaluable parseTerm() throws ParsingException {
Evaluable factor = parseFactor();
while (_token != null &&
_token.type == TokenType.Operator &&
"*/".indexOf(_token.text) >= 0) {
while (_token != null &&
_token.type == TokenType.Operator &&
"*/%".indexOf(_token.text) >= 0) {
String op = _token.text;
next(true);
Evaluable factor2 = parseFactor();
factor = new OperatorCallExpr(new Evaluable[] { factor, factor2 }, op);
}
return factor;
}
/**
* <term> := <term-start> ( <path-segment> )*
* <term> := <term-start> ( <path-segment> )*
* <term-start> :=
* <string> | <number> | - <number> | <regex> | <identifier> |
* <identifier> ( <expression-list> )
*
*
* <path-segment> := "[" <expression-list> "]"
* | "." <identifier>
* | "." <identifier> "(" <expression-list> ")"
*
*
*/
protected Evaluable parseFactor() throws ParsingException {
if (_token == null) {
throw makeException("Expecting something more at end of expression");
}
Evaluable eval = null;
if (_token.type == TokenType.String) {
eval = new LiteralExpr(_token.text);
next(false);
} else if (_token.type == TokenType.Regex) {
RegexToken t = (RegexToken) _token;
try {
Pattern pattern = Pattern.compile(_token.text, t.caseInsensitive ? Pattern.CASE_INSENSITIVE : 0);
eval = new LiteralExpr(pattern);
@ -186,12 +186,12 @@ public class Parser {
next(false);
} else if (_token.type == TokenType.Operator && _token.text.equals("-")) { // unary minus?
next(true);
if (_token != null && _token.type == TokenType.Number) {
Number n = ((NumberToken)_token).value;
eval = new LiteralExpr(n instanceof Long ? -n.longValue() : -n.doubleValue());
next(false);
} else {
throw makeException("Bad negative number");
@ -199,20 +199,23 @@ public class Parser {
} else if (_token.type == TokenType.Identifier) {
String text = _token.text;
next(false);
if (_token == null || _token.type != TokenType.Delimiter || !_token.text.equals("(")) {
eval = "null".equals(text) ? new LiteralExpr(null) : new VariableExpr(text);
} else if( "PI".equals(text) ) {
eval = new LiteralExpr(Math.PI);
next(false);
} else {
Function f = ControlFunctionRegistry.getFunction(text);
Control c = ControlFunctionRegistry.getControl(text);
if (f == null && c == null) {
throw makeException("Unknown function or control named " + text);
}
next(true); // swallow (
List<Evaluable> args = parseExpressionList(")");
if (c != null) {
Evaluable[] argsA = makeArray(args);
String errorMessage = c.checkArguments(argsA);
@ -226,9 +229,9 @@ public class Parser {
}
} else if (_token.type == TokenType.Delimiter && _token.text.equals("(")) {
next(true);
eval = parseExpression();
if (_token != null && _token.type == TokenType.Delimiter && _token.text.equals(")")) {
next(false);
} else {
@ -236,71 +239,71 @@ public class Parser {
}
} else if (_token.type == TokenType.Delimiter && _token.text.equals("[")) { // [ ... ] array
next(true); // swallow [
List<Evaluable> args = parseExpressionList("]");
eval = new FunctionCallExpr(makeArray(args), new ArgsToArray());
} else {
throw makeException("Missing number, string, identifier, regex, or parenthesized expression");
}
while (_token != null) {
if (_token.type == TokenType.Operator && _token.text.equals(".")) {
next(false); // swallow .
if (_token == null || _token.type != TokenType.Identifier) {
throw makeException("Missing function name");
}
String identifier = _token.text;
next(false);
if (_token != null && _token.type == TokenType.Delimiter && _token.text.equals("(")) {
next(true); // swallow (
Function f = ControlFunctionRegistry.getFunction(identifier);
if (f == null) {
throw makeException("Unknown function " + identifier);
}
List<Evaluable> args = parseExpressionList(")");
args.add(0, eval);
eval = new FunctionCallExpr(makeArray(args), f);
} else {
eval = new FieldAccessorExpr(eval, identifier);
}
} else if (_token.type == TokenType.Delimiter && _token.text.equals("[")) {
next(true); // swallow [
List<Evaluable> args = parseExpressionList("]");
args.add(0, eval);
eval = new FunctionCallExpr(makeArray(args), ControlFunctionRegistry.getFunction("get"));
} else {
break;
}
}
return eval;
}
/**
* <expression-list> := <empty>
* | <expression> ( "," <expression> )*
*
*
*/
protected List<Evaluable> parseExpressionList(String closingDelimiter) throws ParsingException {
List<Evaluable> l = new LinkedList<Evaluable>();
if (_token != null &&
if (_token != null &&
(_token.type != TokenType.Delimiter || !_token.text.equals(closingDelimiter))) {
while (_token != null) {
Evaluable eval = parseExpression();
l.add(eval);
if (_token != null && _token.type == TokenType.Delimiter && _token.text.equals(",")) {
next(true); // swallow comma, loop back for more
} else {
@ -308,20 +311,20 @@ public class Parser {
}
}
}
if (_token != null && _token.type == TokenType.Delimiter && _token.text.equals(closingDelimiter)) {
next(false); // swallow closing delimiter
} else {
throw makeException("Missing " + closingDelimiter);
}
return l;
}
protected Evaluable[] makeArray(List<Evaluable> l) {
Evaluable[] a = new Evaluable[l.size()];
l.toArray(a);
return a;
}
}

View File

@ -23,8 +23,8 @@ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@ -43,13 +43,13 @@ public class Scanner {
String,
Regex
}
static public class Token {
final public int start;
final public int end;
final public TokenType type;
final public String text;
Token(int start, int end, TokenType type, String text) {
this.start = start;
this.end = end;
@ -57,59 +57,59 @@ public class Scanner {
this.text = text;
}
}
static public class ErrorToken extends Token {
final public String detail; // error detail
public ErrorToken(int start, int end, String text, String detail) {
super(start, end, TokenType.Error, text);
this.detail = detail;
}
}
static public class NumberToken extends Token {
final public Number value;
public NumberToken(int start, int end, String text, Number value) {
super(start, end, TokenType.Number, text);
this.value = value;
}
}
static public class RegexToken extends Token {
final public boolean caseInsensitive;
public RegexToken(int start, int end, String text, boolean caseInsensitive) {
super(start, end, TokenType.Regex, text);
this.caseInsensitive = caseInsensitive;
}
}
protected String _text; // input text to tokenize
protected int _index; // index of the next character to process
protected int _limit; // process up to this index
public Scanner(String s) {
this(s, 0, s.length());
}
public Scanner(String s, int from, int to) {
_text = s;
_index = from;
_limit = to;
}
public int getIndex() {
return _index;
}
/**
* The regexPossible flag is used by the parser to hint the scanner what to do
* when it encounters a slash. Since the divide operator / and the opening
* when it encounters a slash. Since the divide operator / and the opening
* delimiter of a regex literal are the same, but divide operators and regex
* literals can't occur at the same place in an expression, this flag is a cheap
* way to distinguish the two without having to look ahead.
*
*
* @param regexPossible
* @return
*/
@ -121,69 +121,69 @@ public class Scanner {
if (_index == _limit) {
return null;
}
char c = _text.charAt(_index);
int start = _index;
String detail = null;
if (Character.isDigit(c)) { // number literal
long value = 0;
while (_index < _limit && Character.isDigit(c = _text.charAt(_index))) {
value = value * 10 + (c - '0');
_index++;
}
if (_index < _limit && (c == '.' || c == 'e')) {
double value2 = value;
if (c == '.') {
_index++;
double division = 1;
while (_index < _limit && Character.isDigit(c = _text.charAt(_index))) {
value2 = value2 * 10 + (c - '0');
division *= 10;
_index++;
}
value2 /= division;
}
// TODO: support exponent e notation
return new NumberToken(
start,
_index,
start,
_index,
_text.substring(start, _index),
value2
);
} else {
return new NumberToken(
start,
_index,
start,
_index,
_text.substring(start, _index),
value
);
}
} else if (c == '"' || c == '\'') {
} else if (c == '"' || c == '\'') {
/*
* String Literal
*/
StringBuffer sb = new StringBuffer();
char delimiter = c;
_index++; // skip opening delimiter
while (_index < _limit) {
c = _text.charAt(_index);
if (c == delimiter) {
_index++; // skip closing delimiter
return new Token(
start,
_index,
TokenType.String,
start,
_index,
TokenType.String,
sb.toString()
);
} else if (c == '\\') {
@ -207,10 +207,10 @@ public class Scanner {
}
_index++;
}
detail = "String not properly closed";
// fall through
} else if (Character.isLetter(c) || c == '_') { // identifier
while (_index < _limit) {
char c1 = _text.charAt(_index);
@ -220,11 +220,11 @@ public class Scanner {
break;
}
}
return new Token(
start,
_index,
TokenType.Identifier,
start,
_index,
TokenType.Identifier,
_text.substring(start, _index)
);
} else if (c == '/' && regexPossible) {
@ -232,29 +232,29 @@ public class Scanner {
* Regex literal
*/
StringBuffer sb = new StringBuffer();
_index++; // skip opening delimiter
while (_index < _limit) {
c = _text.charAt(_index);
if (c == '/') {
_index++; // skip closing delimiter
boolean caseInsensitive = false;
if (_index < _limit && _text.charAt(_index) == 'i') {
caseInsensitive = true;
_index++;
}
return new RegexToken(
start,
_index,
start,
_index,
sb.toString(),
caseInsensitive
);
} else if (c == '\\') {
sb.append(c);
_index++; // skip escaping marker
if (_index < _limit) {
sb.append(_text.charAt(_index));
@ -264,53 +264,53 @@ public class Scanner {
}
_index++;
}
detail = "Regex not properly closed";
// fall through
} else if ("+-*/.".indexOf(c) >= 0) { // operator
} else if ("+-*/.%".indexOf(c) >= 0) { // operator
_index++;
return new Token(
start,
_index,
TokenType.Operator,
start,
_index,
TokenType.Operator,
_text.substring(start, _index)
);
} else if ("()[],".indexOf(c) >= 0) { // delimiter
_index++;
return new Token(
start,
_index,
TokenType.Delimiter,
start,
_index,
TokenType.Delimiter,
_text.substring(start, _index)
);
} else if (c == '!' && _index < _limit - 1 && _text.charAt(_index + 1) == '=') {
_index += 2;
return new Token(
start,
_index,
TokenType.Operator,
start,
_index,
TokenType.Operator,
_text.substring(start, _index)
);
} else if (c == '<') {
if (_index < _limit - 1 &&
(_text.charAt(_index + 1) == '=' ||
if (_index < _limit - 1 &&
(_text.charAt(_index + 1) == '=' ||
_text.charAt(_index + 1) == '>')) {
_index += 2;
return new Token(
start,
_index,
TokenType.Operator,
start,
_index,
TokenType.Operator,
_text.substring(start, _index)
);
} else {
_index++;
return new Token(
start,
_index,
TokenType.Operator,
start,
_index,
TokenType.Operator,
_text.substring(start, _index)
);
}
@ -318,17 +318,17 @@ public class Scanner {
if (_index < _limit - 1 && _text.charAt(_index + 1) == '=') {
_index += 2;
return new Token(
start,
_index,
TokenType.Operator,
start,
_index,
TokenType.Operator,
_text.substring(start, _index)
);
} else {
_index++;
return new Token(
start,
_index,
TokenType.Operator,
start,
_index,
TokenType.Operator,
_text.substring(start, _index)
);
}
@ -336,10 +336,10 @@ public class Scanner {
_index++;
detail = "Unrecognized symbol";
}
return new ErrorToken(
start,
_index,
start,
_index,
_text.substring(start, _index),
detail
);

View File

@ -23,8 +23,8 @@ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@ -44,12 +44,12 @@ import com.google.refine.expr.ExpressionUtils;
public class OperatorCallExpr implements Evaluable {
final protected Evaluable[] _args;
final protected String _op;
public OperatorCallExpr(Evaluable[] args, String op) {
_args = args;
_op = op;
}
public Object evaluate(Properties bindings) {
Object[] args = new Object[_args.length];
for (int i = 0; i < _args.length; i++) {
@ -59,13 +59,13 @@ public class OperatorCallExpr implements Evaluable {
}
args[i] = v;
}
if (args.length == 2) {
if (args[0] != null && args[1] != null) {
if (isIntegral(args[0]) && isIntegral(args[1])) {
long n1 = ((Number) args[0]).longValue();
long n2 = ((Number) args[1]).longValue();
if ("+".equals(_op)) {
return n1 + n2;
} else if ("-".equals(_op)) {
@ -74,6 +74,8 @@ public class OperatorCallExpr implements Evaluable {
return n1 * n2;
} else if ("/".equals(_op)) {
return n1 / n2;
} else if ("%".equals(_op)) {
return n1 % n2;
} else if (">".equals(_op)) {
return n1 > n2;
} else if (">=".equals(_op)) {
@ -90,7 +92,7 @@ public class OperatorCallExpr implements Evaluable {
} else if (args[0] instanceof Number && args[1] instanceof Number) {
double n1 = ((Number) args[0]).doubleValue();
double n2 = ((Number) args[1]).doubleValue();
if ("+".equals(_op)) {
return n1 + n2;
} else if ("-".equals(_op)) {
@ -99,6 +101,8 @@ public class OperatorCallExpr implements Evaluable {
return n1 * n2;
} else if ("/".equals(_op)) {
return n1 / n2;
} else if ("%".equals(_op)) {
return n1 % n2;
} else if (">".equals(_op)) {
return n1 > n2;
} else if (">=".equals(_op)) {
@ -113,12 +117,12 @@ public class OperatorCallExpr implements Evaluable {
return n1 != n2;
}
}
if ("+".equals(_op)) {
return args[0].toString() + args[1].toString();
}
}
if ("==".equals(_op)) {
if (args[0] != null) {
return args[0].equals(args[1]);
@ -139,7 +143,7 @@ public class OperatorCallExpr implements Evaluable {
@Override
public String toString() {
StringBuffer sb = new StringBuffer();
for (Evaluable ev : _args) {
if (sb.length() > 0) {
sb.append(' ');
@ -148,10 +152,10 @@ public class OperatorCallExpr implements Evaluable {
}
sb.append(ev.toString());
}
return sb.toString();
}
private boolean isIntegral(Object n) {
return n instanceof Long || n instanceof Integer;
}