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 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 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.DatePart;
import com.google.refine.expr.functions.date.Inc; import com.google.refine.expr.functions.date.Inc;
import com.google.refine.expr.functions.date.Now; 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.Abs;
import com.google.refine.expr.functions.math.Ceil; 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.Exp;
import com.google.refine.expr.functions.math.Fact;
import com.google.refine.expr.functions.math.Floor; import com.google.refine.expr.functions.math.Floor;
import com.google.refine.expr.functions.math.Ln; import com.google.refine.expr.functions.math.Ln;
import com.google.refine.expr.functions.math.Log; import com.google.refine.expr.functions.math.Log;
import com.google.refine.expr.functions.math.Max; import com.google.refine.expr.functions.math.Max;
import com.google.refine.expr.functions.math.Min; import com.google.refine.expr.functions.math.Min;
import com.google.refine.expr.functions.math.Mod; 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.Pow;
import com.google.refine.expr.functions.math.Radians;
import com.google.refine.expr.functions.math.Round; 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.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.Chomp;
import com.google.refine.expr.functions.strings.Contains; import com.google.refine.expr.functions.strings.Contains;
import com.google.refine.expr.functions.strings.Diff; import com.google.refine.expr.functions.strings.Diff;
@ -212,9 +228,21 @@ public class ControlFunctionRegistry {
registerFunction("inc", new Inc()); registerFunction("inc", new Inc());
registerFunction("datePart", new DatePart()); 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("round", new Round());
registerFunction("floor", new Floor()); registerFunction("floor", new Floor());
registerFunction("ceil", new Ceil()); registerFunction("ceil", new Ceil());
registerFunction("even", new Even());
registerFunction("odd", new Odd());
registerFunction("abs", new Abs()); registerFunction("abs", new Abs());
registerFunction("mod", new Mod()); registerFunction("mod", new Mod());
registerFunction("max", new Max()); registerFunction("max", new Max());
@ -224,6 +252,10 @@ public class ControlFunctionRegistry {
registerFunction("pow", new Pow()); registerFunction("pow", new Pow());
registerFunction("exp", new Exp()); registerFunction("exp", new Exp());
registerFunction("sum", new Sum()); 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("and", new And());
registerFunction("or", new Or()); 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 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@ -55,125 +55,125 @@ public class Parser {
protected Scanner _scanner; protected Scanner _scanner;
protected Token _token; protected Token _token;
protected Evaluable _root; protected Evaluable _root;
public Parser(String s) throws ParsingException { public Parser(String s) throws ParsingException {
this(s, 0, s.length()); this(s, 0, s.length());
} }
public Parser(String s, int from, int to) throws ParsingException { public Parser(String s, int from, int to) throws ParsingException {
_scanner = new Scanner(s, from, to); _scanner = new Scanner(s, from, to);
_token = _scanner.next(true); _token = _scanner.next(true);
_root = parseExpression(); _root = parseExpression();
} }
public Evaluable getExpression() { public Evaluable getExpression() {
return _root; return _root;
} }
protected void next(boolean regexPossible) { protected void next(boolean regexPossible) {
_token = _scanner.next(regexPossible); _token = _scanner.next(regexPossible);
} }
protected ParsingException makeException(String desc) { protected ParsingException makeException(String desc) {
int index = _token != null ? _token.start : _scanner.getIndex(); int index = _token != null ? _token.start : _scanner.getIndex();
return new ParsingException("Parsing error at offset " + index + ": " + desc); return new ParsingException("Parsing error at offset " + index + ": " + desc);
} }
/** /**
* <expression> := <sub-expression> * <expression> := <sub-expression>
* | <expression> [ "<" "<=" ">" ">=" "==" "!=" ] <sub-expression> * | <expression> [ "<" "<=" ">" ">=" "==" "!=" ] <sub-expression>
*/ */
protected Evaluable parseExpression() throws ParsingException { protected Evaluable parseExpression() throws ParsingException {
Evaluable sub = parseSubExpression(); Evaluable sub = parseSubExpression();
while (_token != null && while (_token != null &&
_token.type == TokenType.Operator && _token.type == TokenType.Operator &&
">=<==!=".indexOf(_token.text) >= 0) { ">=<==!=".indexOf(_token.text) >= 0) {
String op = _token.text; String op = _token.text;
next(true); next(true);
Evaluable sub2 = parseSubExpression(); Evaluable sub2 = parseSubExpression();
sub = new OperatorCallExpr(new Evaluable[] { sub, sub2 }, op); sub = new OperatorCallExpr(new Evaluable[] { sub, sub2 }, op);
} }
return sub; return sub;
} }
/** /**
* <sub-expression> := <term> * <sub-expression> := <term>
* | <sub-expression> [ "+" "-" ] <term> * | <sub-expression> [ "+" "-" ] <term>
*/ */
protected Evaluable parseSubExpression() throws ParsingException { protected Evaluable parseSubExpression() throws ParsingException {
Evaluable sub = parseTerm(); Evaluable sub = parseTerm();
while (_token != null && while (_token != null &&
_token.type == TokenType.Operator && _token.type == TokenType.Operator &&
"+-".indexOf(_token.text) >= 0) { "+-".indexOf(_token.text) >= 0) {
String op = _token.text; String op = _token.text;
next(true); next(true);
Evaluable sub2 = parseSubExpression(); Evaluable sub2 = parseSubExpression();
sub = new OperatorCallExpr(new Evaluable[] { sub, sub2 }, op); sub = new OperatorCallExpr(new Evaluable[] { sub, sub2 }, op);
} }
return sub; return sub;
} }
/** /**
* <term> := <factor> * <term> := <factor>
* | <term> [ "*" "/" ] <factor> * | <term> [ "*" "/" "%" ] <factor>
*/ */
protected Evaluable parseTerm() throws ParsingException { protected Evaluable parseTerm() throws ParsingException {
Evaluable factor = parseFactor(); Evaluable factor = parseFactor();
while (_token != null && while (_token != null &&
_token.type == TokenType.Operator && _token.type == TokenType.Operator &&
"*/".indexOf(_token.text) >= 0) { "*/%".indexOf(_token.text) >= 0) {
String op = _token.text; String op = _token.text;
next(true); next(true);
Evaluable factor2 = parseFactor(); Evaluable factor2 = parseFactor();
factor = new OperatorCallExpr(new Evaluable[] { factor, factor2 }, op); factor = new OperatorCallExpr(new Evaluable[] { factor, factor2 }, op);
} }
return factor; return factor;
} }
/** /**
* <term> := <term-start> ( <path-segment> )* * <term> := <term-start> ( <path-segment> )*
* <term-start> := * <term-start> :=
* <string> | <number> | - <number> | <regex> | <identifier> | * <string> | <number> | - <number> | <regex> | <identifier> |
* <identifier> ( <expression-list> ) * <identifier> ( <expression-list> )
* *
* <path-segment> := "[" <expression-list> "]" * <path-segment> := "[" <expression-list> "]"
* | "." <identifier> * | "." <identifier>
* | "." <identifier> "(" <expression-list> ")" * | "." <identifier> "(" <expression-list> ")"
* *
*/ */
protected Evaluable parseFactor() throws ParsingException { protected Evaluable parseFactor() throws ParsingException {
if (_token == null) { if (_token == null) {
throw makeException("Expecting something more at end of expression"); throw makeException("Expecting something more at end of expression");
} }
Evaluable eval = null; Evaluable eval = null;
if (_token.type == TokenType.String) { if (_token.type == TokenType.String) {
eval = new LiteralExpr(_token.text); eval = new LiteralExpr(_token.text);
next(false); next(false);
} else if (_token.type == TokenType.Regex) { } else if (_token.type == TokenType.Regex) {
RegexToken t = (RegexToken) _token; RegexToken t = (RegexToken) _token;
try { try {
Pattern pattern = Pattern.compile(_token.text, t.caseInsensitive ? Pattern.CASE_INSENSITIVE : 0); Pattern pattern = Pattern.compile(_token.text, t.caseInsensitive ? Pattern.CASE_INSENSITIVE : 0);
eval = new LiteralExpr(pattern); eval = new LiteralExpr(pattern);
@ -186,12 +186,12 @@ public class Parser {
next(false); next(false);
} else if (_token.type == TokenType.Operator && _token.text.equals("-")) { // unary minus? } else if (_token.type == TokenType.Operator && _token.text.equals("-")) { // unary minus?
next(true); next(true);
if (_token != null && _token.type == TokenType.Number) { if (_token != null && _token.type == TokenType.Number) {
Number n = ((NumberToken)_token).value; Number n = ((NumberToken)_token).value;
eval = new LiteralExpr(n instanceof Long ? -n.longValue() : -n.doubleValue()); eval = new LiteralExpr(n instanceof Long ? -n.longValue() : -n.doubleValue());
next(false); next(false);
} else { } else {
throw makeException("Bad negative number"); throw makeException("Bad negative number");
@ -199,20 +199,23 @@ public class Parser {
} else if (_token.type == TokenType.Identifier) { } else if (_token.type == TokenType.Identifier) {
String text = _token.text; String text = _token.text;
next(false); next(false);
if (_token == null || _token.type != TokenType.Delimiter || !_token.text.equals("(")) { if (_token == null || _token.type != TokenType.Delimiter || !_token.text.equals("(")) {
eval = "null".equals(text) ? new LiteralExpr(null) : new VariableExpr(text); eval = "null".equals(text) ? new LiteralExpr(null) : new VariableExpr(text);
} else if( "PI".equals(text) ) {
eval = new LiteralExpr(Math.PI);
next(false);
} else { } else {
Function f = ControlFunctionRegistry.getFunction(text); Function f = ControlFunctionRegistry.getFunction(text);
Control c = ControlFunctionRegistry.getControl(text); Control c = ControlFunctionRegistry.getControl(text);
if (f == null && c == null) { if (f == null && c == null) {
throw makeException("Unknown function or control named " + text); throw makeException("Unknown function or control named " + text);
} }
next(true); // swallow ( next(true); // swallow (
List<Evaluable> args = parseExpressionList(")"); List<Evaluable> args = parseExpressionList(")");
if (c != null) { if (c != null) {
Evaluable[] argsA = makeArray(args); Evaluable[] argsA = makeArray(args);
String errorMessage = c.checkArguments(argsA); String errorMessage = c.checkArguments(argsA);
@ -226,9 +229,9 @@ public class Parser {
} }
} else if (_token.type == TokenType.Delimiter && _token.text.equals("(")) { } else if (_token.type == TokenType.Delimiter && _token.text.equals("(")) {
next(true); next(true);
eval = parseExpression(); eval = parseExpression();
if (_token != null && _token.type == TokenType.Delimiter && _token.text.equals(")")) { if (_token != null && _token.type == TokenType.Delimiter && _token.text.equals(")")) {
next(false); next(false);
} else { } else {
@ -236,71 +239,71 @@ public class Parser {
} }
} else if (_token.type == TokenType.Delimiter && _token.text.equals("[")) { // [ ... ] array } else if (_token.type == TokenType.Delimiter && _token.text.equals("[")) { // [ ... ] array
next(true); // swallow [ next(true); // swallow [
List<Evaluable> args = parseExpressionList("]"); List<Evaluable> args = parseExpressionList("]");
eval = new FunctionCallExpr(makeArray(args), new ArgsToArray()); eval = new FunctionCallExpr(makeArray(args), new ArgsToArray());
} else { } else {
throw makeException("Missing number, string, identifier, regex, or parenthesized expression"); throw makeException("Missing number, string, identifier, regex, or parenthesized expression");
} }
while (_token != null) { while (_token != null) {
if (_token.type == TokenType.Operator && _token.text.equals(".")) { if (_token.type == TokenType.Operator && _token.text.equals(".")) {
next(false); // swallow . next(false); // swallow .
if (_token == null || _token.type != TokenType.Identifier) { if (_token == null || _token.type != TokenType.Identifier) {
throw makeException("Missing function name"); throw makeException("Missing function name");
} }
String identifier = _token.text; String identifier = _token.text;
next(false); next(false);
if (_token != null && _token.type == TokenType.Delimiter && _token.text.equals("(")) { if (_token != null && _token.type == TokenType.Delimiter && _token.text.equals("(")) {
next(true); // swallow ( next(true); // swallow (
Function f = ControlFunctionRegistry.getFunction(identifier); Function f = ControlFunctionRegistry.getFunction(identifier);
if (f == null) { if (f == null) {
throw makeException("Unknown function " + identifier); throw makeException("Unknown function " + identifier);
} }
List<Evaluable> args = parseExpressionList(")"); List<Evaluable> args = parseExpressionList(")");
args.add(0, eval); args.add(0, eval);
eval = new FunctionCallExpr(makeArray(args), f); eval = new FunctionCallExpr(makeArray(args), f);
} else { } else {
eval = new FieldAccessorExpr(eval, identifier); eval = new FieldAccessorExpr(eval, identifier);
} }
} else if (_token.type == TokenType.Delimiter && _token.text.equals("[")) { } else if (_token.type == TokenType.Delimiter && _token.text.equals("[")) {
next(true); // swallow [ next(true); // swallow [
List<Evaluable> args = parseExpressionList("]"); List<Evaluable> args = parseExpressionList("]");
args.add(0, eval); args.add(0, eval);
eval = new FunctionCallExpr(makeArray(args), ControlFunctionRegistry.getFunction("get")); eval = new FunctionCallExpr(makeArray(args), ControlFunctionRegistry.getFunction("get"));
} else { } else {
break; break;
} }
} }
return eval; return eval;
} }
/** /**
* <expression-list> := <empty> * <expression-list> := <empty>
* | <expression> ( "," <expression> )* * | <expression> ( "," <expression> )*
* *
*/ */
protected List<Evaluable> parseExpressionList(String closingDelimiter) throws ParsingException { protected List<Evaluable> parseExpressionList(String closingDelimiter) throws ParsingException {
List<Evaluable> l = new LinkedList<Evaluable>(); List<Evaluable> l = new LinkedList<Evaluable>();
if (_token != null && if (_token != null &&
(_token.type != TokenType.Delimiter || !_token.text.equals(closingDelimiter))) { (_token.type != TokenType.Delimiter || !_token.text.equals(closingDelimiter))) {
while (_token != null) { while (_token != null) {
Evaluable eval = parseExpression(); Evaluable eval = parseExpression();
l.add(eval); l.add(eval);
if (_token != null && _token.type == TokenType.Delimiter && _token.text.equals(",")) { if (_token != null && _token.type == TokenType.Delimiter && _token.text.equals(",")) {
next(true); // swallow comma, loop back for more next(true); // swallow comma, loop back for more
} else { } else {
@ -308,20 +311,20 @@ public class Parser {
} }
} }
} }
if (_token != null && _token.type == TokenType.Delimiter && _token.text.equals(closingDelimiter)) { if (_token != null && _token.type == TokenType.Delimiter && _token.text.equals(closingDelimiter)) {
next(false); // swallow closing delimiter next(false); // swallow closing delimiter
} else { } else {
throw makeException("Missing " + closingDelimiter); throw makeException("Missing " + closingDelimiter);
} }
return l; return l;
} }
protected Evaluable[] makeArray(List<Evaluable> l) { protected Evaluable[] makeArray(List<Evaluable> l) {
Evaluable[] a = new Evaluable[l.size()]; Evaluable[] a = new Evaluable[l.size()];
l.toArray(a); l.toArray(a);
return 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 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@ -43,13 +43,13 @@ public class Scanner {
String, String,
Regex Regex
} }
static public class Token { static public class Token {
final public int start; final public int start;
final public int end; final public int end;
final public TokenType type; final public TokenType type;
final public String text; final public String text;
Token(int start, int end, TokenType type, String text) { Token(int start, int end, TokenType type, String text) {
this.start = start; this.start = start;
this.end = end; this.end = end;
@ -57,59 +57,59 @@ public class Scanner {
this.text = text; this.text = text;
} }
} }
static public class ErrorToken extends Token { static public class ErrorToken extends Token {
final public String detail; // error detail final public String detail; // error detail
public ErrorToken(int start, int end, String text, String detail) { public ErrorToken(int start, int end, String text, String detail) {
super(start, end, TokenType.Error, text); super(start, end, TokenType.Error, text);
this.detail = detail; this.detail = detail;
} }
} }
static public class NumberToken extends Token { static public class NumberToken extends Token {
final public Number value; final public Number value;
public NumberToken(int start, int end, String text, Number value) { public NumberToken(int start, int end, String text, Number value) {
super(start, end, TokenType.Number, text); super(start, end, TokenType.Number, text);
this.value = value; this.value = value;
} }
} }
static public class RegexToken extends Token { static public class RegexToken extends Token {
final public boolean caseInsensitive; final public boolean caseInsensitive;
public RegexToken(int start, int end, String text, boolean caseInsensitive) { public RegexToken(int start, int end, String text, boolean caseInsensitive) {
super(start, end, TokenType.Regex, text); super(start, end, TokenType.Regex, text);
this.caseInsensitive = caseInsensitive; this.caseInsensitive = caseInsensitive;
} }
} }
protected String _text; // input text to tokenize protected String _text; // input text to tokenize
protected int _index; // index of the next character to process protected int _index; // index of the next character to process
protected int _limit; // process up to this index protected int _limit; // process up to this index
public Scanner(String s) { public Scanner(String s) {
this(s, 0, s.length()); this(s, 0, s.length());
} }
public Scanner(String s, int from, int to) { public Scanner(String s, int from, int to) {
_text = s; _text = s;
_index = from; _index = from;
_limit = to; _limit = to;
} }
public int getIndex() { public int getIndex() {
return _index; return _index;
} }
/** /**
* The regexPossible flag is used by the parser to hint the scanner what to do * 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 * 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 * 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. * way to distinguish the two without having to look ahead.
* *
* @param regexPossible * @param regexPossible
* @return * @return
*/ */
@ -121,69 +121,69 @@ public class Scanner {
if (_index == _limit) { if (_index == _limit) {
return null; return null;
} }
char c = _text.charAt(_index); char c = _text.charAt(_index);
int start = _index; int start = _index;
String detail = null; String detail = null;
if (Character.isDigit(c)) { // number literal if (Character.isDigit(c)) { // number literal
long value = 0; long value = 0;
while (_index < _limit && Character.isDigit(c = _text.charAt(_index))) { while (_index < _limit && Character.isDigit(c = _text.charAt(_index))) {
value = value * 10 + (c - '0'); value = value * 10 + (c - '0');
_index++; _index++;
} }
if (_index < _limit && (c == '.' || c == 'e')) { if (_index < _limit && (c == '.' || c == 'e')) {
double value2 = value; double value2 = value;
if (c == '.') { if (c == '.') {
_index++; _index++;
double division = 1; double division = 1;
while (_index < _limit && Character.isDigit(c = _text.charAt(_index))) { while (_index < _limit && Character.isDigit(c = _text.charAt(_index))) {
value2 = value2 * 10 + (c - '0'); value2 = value2 * 10 + (c - '0');
division *= 10; division *= 10;
_index++; _index++;
} }
value2 /= division; value2 /= division;
} }
// TODO: support exponent e notation // TODO: support exponent e notation
return new NumberToken( return new NumberToken(
start, start,
_index, _index,
_text.substring(start, _index), _text.substring(start, _index),
value2 value2
); );
} else { } else {
return new NumberToken( return new NumberToken(
start, start,
_index, _index,
_text.substring(start, _index), _text.substring(start, _index),
value value
); );
} }
} else if (c == '"' || c == '\'') { } else if (c == '"' || c == '\'') {
/* /*
* String Literal * String Literal
*/ */
StringBuffer sb = new StringBuffer(); StringBuffer sb = new StringBuffer();
char delimiter = c; char delimiter = c;
_index++; // skip opening delimiter _index++; // skip opening delimiter
while (_index < _limit) { while (_index < _limit) {
c = _text.charAt(_index); c = _text.charAt(_index);
if (c == delimiter) { if (c == delimiter) {
_index++; // skip closing delimiter _index++; // skip closing delimiter
return new Token( return new Token(
start, start,
_index, _index,
TokenType.String, TokenType.String,
sb.toString() sb.toString()
); );
} else if (c == '\\') { } else if (c == '\\') {
@ -207,10 +207,10 @@ public class Scanner {
} }
_index++; _index++;
} }
detail = "String not properly closed"; detail = "String not properly closed";
// fall through // fall through
} else if (Character.isLetter(c) || c == '_') { // identifier } else if (Character.isLetter(c) || c == '_') { // identifier
while (_index < _limit) { while (_index < _limit) {
char c1 = _text.charAt(_index); char c1 = _text.charAt(_index);
@ -220,11 +220,11 @@ public class Scanner {
break; break;
} }
} }
return new Token( return new Token(
start, start,
_index, _index,
TokenType.Identifier, TokenType.Identifier,
_text.substring(start, _index) _text.substring(start, _index)
); );
} else if (c == '/' && regexPossible) { } else if (c == '/' && regexPossible) {
@ -232,29 +232,29 @@ public class Scanner {
* Regex literal * Regex literal
*/ */
StringBuffer sb = new StringBuffer(); StringBuffer sb = new StringBuffer();
_index++; // skip opening delimiter _index++; // skip opening delimiter
while (_index < _limit) { while (_index < _limit) {
c = _text.charAt(_index); c = _text.charAt(_index);
if (c == '/') { if (c == '/') {
_index++; // skip closing delimiter _index++; // skip closing delimiter
boolean caseInsensitive = false; boolean caseInsensitive = false;
if (_index < _limit && _text.charAt(_index) == 'i') { if (_index < _limit && _text.charAt(_index) == 'i') {
caseInsensitive = true; caseInsensitive = true;
_index++; _index++;
} }
return new RegexToken( return new RegexToken(
start, start,
_index, _index,
sb.toString(), sb.toString(),
caseInsensitive caseInsensitive
); );
} else if (c == '\\') { } else if (c == '\\') {
sb.append(c); sb.append(c);
_index++; // skip escaping marker _index++; // skip escaping marker
if (_index < _limit) { if (_index < _limit) {
sb.append(_text.charAt(_index)); sb.append(_text.charAt(_index));
@ -264,53 +264,53 @@ public class Scanner {
} }
_index++; _index++;
} }
detail = "Regex not properly closed"; detail = "Regex not properly closed";
// fall through // fall through
} else if ("+-*/.".indexOf(c) >= 0) { // operator } else if ("+-*/.%".indexOf(c) >= 0) { // operator
_index++; _index++;
return new Token( return new Token(
start, start,
_index, _index,
TokenType.Operator, TokenType.Operator,
_text.substring(start, _index) _text.substring(start, _index)
); );
} else if ("()[],".indexOf(c) >= 0) { // delimiter } else if ("()[],".indexOf(c) >= 0) { // delimiter
_index++; _index++;
return new Token( return new Token(
start, start,
_index, _index,
TokenType.Delimiter, TokenType.Delimiter,
_text.substring(start, _index) _text.substring(start, _index)
); );
} else if (c == '!' && _index < _limit - 1 && _text.charAt(_index + 1) == '=') { } else if (c == '!' && _index < _limit - 1 && _text.charAt(_index + 1) == '=') {
_index += 2; _index += 2;
return new Token( return new Token(
start, start,
_index, _index,
TokenType.Operator, TokenType.Operator,
_text.substring(start, _index) _text.substring(start, _index)
); );
} else if (c == '<') { } else if (c == '<') {
if (_index < _limit - 1 && if (_index < _limit - 1 &&
(_text.charAt(_index + 1) == '=' || (_text.charAt(_index + 1) == '=' ||
_text.charAt(_index + 1) == '>')) { _text.charAt(_index + 1) == '>')) {
_index += 2; _index += 2;
return new Token( return new Token(
start, start,
_index, _index,
TokenType.Operator, TokenType.Operator,
_text.substring(start, _index) _text.substring(start, _index)
); );
} else { } else {
_index++; _index++;
return new Token( return new Token(
start, start,
_index, _index,
TokenType.Operator, TokenType.Operator,
_text.substring(start, _index) _text.substring(start, _index)
); );
} }
@ -318,17 +318,17 @@ public class Scanner {
if (_index < _limit - 1 && _text.charAt(_index + 1) == '=') { if (_index < _limit - 1 && _text.charAt(_index + 1) == '=') {
_index += 2; _index += 2;
return new Token( return new Token(
start, start,
_index, _index,
TokenType.Operator, TokenType.Operator,
_text.substring(start, _index) _text.substring(start, _index)
); );
} else { } else {
_index++; _index++;
return new Token( return new Token(
start, start,
_index, _index,
TokenType.Operator, TokenType.Operator,
_text.substring(start, _index) _text.substring(start, _index)
); );
} }
@ -336,10 +336,10 @@ public class Scanner {
_index++; _index++;
detail = "Unrecognized symbol"; detail = "Unrecognized symbol";
} }
return new ErrorToken( return new ErrorToken(
start, start,
_index, _index,
_text.substring(start, _index), _text.substring(start, _index),
detail 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 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 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 { public class OperatorCallExpr implements Evaluable {
final protected Evaluable[] _args; final protected Evaluable[] _args;
final protected String _op; final protected String _op;
public OperatorCallExpr(Evaluable[] args, String op) { public OperatorCallExpr(Evaluable[] args, String op) {
_args = args; _args = args;
_op = op; _op = op;
} }
public Object evaluate(Properties bindings) { public Object evaluate(Properties bindings) {
Object[] args = new Object[_args.length]; Object[] args = new Object[_args.length];
for (int i = 0; i < _args.length; i++) { for (int i = 0; i < _args.length; i++) {
@ -59,13 +59,13 @@ public class OperatorCallExpr implements Evaluable {
} }
args[i] = v; args[i] = v;
} }
if (args.length == 2) { if (args.length == 2) {
if (args[0] != null && args[1] != null) { if (args[0] != null && args[1] != null) {
if (isIntegral(args[0]) && isIntegral(args[1])) { if (isIntegral(args[0]) && isIntegral(args[1])) {
long n1 = ((Number) args[0]).longValue(); long n1 = ((Number) args[0]).longValue();
long n2 = ((Number) args[1]).longValue(); long n2 = ((Number) args[1]).longValue();
if ("+".equals(_op)) { if ("+".equals(_op)) {
return n1 + n2; return n1 + n2;
} else if ("-".equals(_op)) { } else if ("-".equals(_op)) {
@ -74,6 +74,8 @@ public class OperatorCallExpr implements Evaluable {
return n1 * n2; return n1 * n2;
} else if ("/".equals(_op)) { } else if ("/".equals(_op)) {
return n1 / n2; return n1 / n2;
} else if ("%".equals(_op)) {
return n1 % n2;
} else if (">".equals(_op)) { } else if (">".equals(_op)) {
return n1 > n2; return n1 > n2;
} else if (">=".equals(_op)) { } else if (">=".equals(_op)) {
@ -90,7 +92,7 @@ public class OperatorCallExpr implements Evaluable {
} else if (args[0] instanceof Number && args[1] instanceof Number) { } else if (args[0] instanceof Number && args[1] instanceof Number) {
double n1 = ((Number) args[0]).doubleValue(); double n1 = ((Number) args[0]).doubleValue();
double n2 = ((Number) args[1]).doubleValue(); double n2 = ((Number) args[1]).doubleValue();
if ("+".equals(_op)) { if ("+".equals(_op)) {
return n1 + n2; return n1 + n2;
} else if ("-".equals(_op)) { } else if ("-".equals(_op)) {
@ -99,6 +101,8 @@ public class OperatorCallExpr implements Evaluable {
return n1 * n2; return n1 * n2;
} else if ("/".equals(_op)) { } else if ("/".equals(_op)) {
return n1 / n2; return n1 / n2;
} else if ("%".equals(_op)) {
return n1 % n2;
} else if (">".equals(_op)) { } else if (">".equals(_op)) {
return n1 > n2; return n1 > n2;
} else if (">=".equals(_op)) { } else if (">=".equals(_op)) {
@ -113,12 +117,12 @@ public class OperatorCallExpr implements Evaluable {
return n1 != n2; return n1 != n2;
} }
} }
if ("+".equals(_op)) { if ("+".equals(_op)) {
return args[0].toString() + args[1].toString(); return args[0].toString() + args[1].toString();
} }
} }
if ("==".equals(_op)) { if ("==".equals(_op)) {
if (args[0] != null) { if (args[0] != null) {
return args[0].equals(args[1]); return args[0].equals(args[1]);
@ -139,7 +143,7 @@ public class OperatorCallExpr implements Evaluable {
@Override @Override
public String toString() { public String toString() {
StringBuffer sb = new StringBuffer(); StringBuffer sb = new StringBuffer();
for (Evaluable ev : _args) { for (Evaluable ev : _args) {
if (sb.length() > 0) { if (sb.length() > 0) {
sb.append(' '); sb.append(' ');
@ -148,10 +152,10 @@ public class OperatorCallExpr implements Evaluable {
} }
sb.append(ev.toString()); sb.append(ev.toString());
} }
return sb.toString(); return sb.toString();
} }
private boolean isIntegral(Object n) { private boolean isIntegral(Object n) {
return n instanceof Long || n instanceof Integer; return n instanceof Long || n instanceof Integer;
} }