From c764fabf1d2b7907d58497a332ec46ce513f2721 Mon Sep 17 00:00:00 2001 From: Nathaniel Bauernfeind Date: Tue, 26 Oct 2021 21:36:47 -0600 Subject: [PATCH 01/14] Enable casting PyObject's to primitives; provide type param info for py lists --- .../lang/DBLanguageFunctionGenerator.java | 32 ++++++- .../tables/lang/DBLanguageFunctionUtil.java | 29 ++++++ .../db/tables/lang/DBLanguageParser.java | 20 +++-- .../io/deephaven/db/tables/select/Param.java | 90 +++++++++++++------ .../db/v2/select/AbstractConditionFilter.java | 12 ++- .../db/v2/select/ConditionFilter.java | 2 +- .../db/v2/select/DhFormulaColumn.java | 4 +- .../db/v2/select/codegen/FormulaAnalyzer.java | 13 ++- 8 files changed, 162 insertions(+), 40 deletions(-) diff --git a/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageFunctionGenerator.java b/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageFunctionGenerator.java index 6c27edd660a..880e9cc72ea 100644 --- a/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageFunctionGenerator.java +++ b/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageFunctionGenerator.java @@ -319,7 +319,8 @@ public static void main(String args[]) { buf.append("package io.deephaven.db.tables.lang;\n\n"); - buf.append("import io.deephaven.util.QueryConstants;\n\n"); + buf.append("import io.deephaven.util.QueryConstants;\n"); + buf.append("import org.jpy.PyObject;\n\n"); buf.append("@SuppressWarnings({\"unused\", \"WeakerAccess\", \"SimplifiableIfStatement\"})\n"); buf.append("public final class DBLanguageFunctionUtil {\n\n"); @@ -558,6 +559,35 @@ public static void main(String args[]) { append(buf, castFromObjFormatter, BinaryExpr.Operator.PLUS, c, Object.class); } + // Special casts for PyObject to primitive + buf.append(" public static int intPyCast(PyObject a) {\n"); + buf.append(" return a.getIntValue();\n"); + buf.append(" }\n\n"); + + buf.append(" public static double doublePyCast(PyObject a) {\n"); + buf.append(" return a.getDoubleValue();\n"); + buf.append(" }\n\n"); + + buf.append(" public static long longPyCast(PyObject a) {\n"); + buf.append(" return a.getLongValue();\n"); + buf.append(" }\n\n"); + + buf.append(" public static float floatPyCast(PyObject a) {\n"); + buf.append(" return (float) a.getDoubleValue();\n"); + buf.append(" }\n\n"); + + buf.append(" public static char charPyCast(PyObject a) {\n"); + buf.append(" return (char) a.getIntValue();\n"); + buf.append(" }\n\n"); + + buf.append(" public static byte bytePyCast(PyObject a) {\n"); + buf.append(" return (byte) a.getIntValue();\n"); + buf.append(" }\n\n"); + + buf.append(" public static short shortPyCast(PyObject a) {\n"); + buf.append(" return (short) a.getIntValue();\n"); + buf.append(" }\n\n"); + // ------------------------------------------------------------------------------------------------------------------------------------------------------------------ classes = new Class[] {int.class, double.class, long.class, float.class, char.class, byte.class, short.class}; diff --git a/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageFunctionUtil.java b/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageFunctionUtil.java index 157c4887f08..10d2b65b435 100644 --- a/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageFunctionUtil.java +++ b/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageFunctionUtil.java @@ -6,6 +6,7 @@ package io.deephaven.db.tables.lang; import io.deephaven.util.QueryConstants; +import org.jpy.PyObject; @SuppressWarnings({"unused", "WeakerAccess", "SimplifiableIfStatement"}) public final class DBLanguageFunctionUtil { @@ -19289,6 +19290,34 @@ public static short shortCast(Object a) { return a == null ? QueryConstants.NULL_SHORT : (short) a; } + public static int intPyCast(PyObject a) { + return a.getIntValue(); + } + + public static double doublePyCast(PyObject a) { + return a.getDoubleValue(); + } + + public static long longPyCast(PyObject a) { + return a.getLongValue(); + } + + public static float floatPyCast(PyObject a) { + return (float) a.getDoubleValue(); + } + + public static char charPyCast(PyObject a) { + return (char) a.getIntValue(); + } + + public static byte bytePyCast(PyObject a) { + return (byte) a.getIntValue(); + } + + public static short shortPyCast(PyObject a) { + return (short) a.getIntValue(); + } + public static int negate(int a) { return a == QueryConstants.NULL_INT ? QueryConstants.NULL_INT : -a; } diff --git a/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageParser.java b/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageParser.java index f9b64786142..54e220005ac 100644 --- a/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageParser.java +++ b/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageParser.java @@ -1003,11 +1003,15 @@ public Class visit(ArrayAccessExpr n, VisitArgs printer) { Class paramType = n.getIndex().accept(this, printer); printer.append(')'); - if (DbArray.class.isAssignableFrom(type) && (n.getName() instanceof NameExpr)) { - Class ret = variableParameterizedTypes.get(((NameExpr) n.getName()).getNameAsString())[0]; - - if (ret != null) { - return ret; + // We'll check for a known component type if this a NameExpr. + if (n.getName() instanceof NameExpr) { + Class[] classes = variableParameterizedTypes.get(((NameExpr) n.getName()).getNameAsString()); + if (classes != null && classes.length > 0) { + Class ret = classes[0]; + + if (ret != null) { + return ret; + } } } @@ -1173,7 +1177,11 @@ else if (fromBoxedType) { if (toPrimitive && !ret.equals(boolean.class) && !ret.equals(exprType)) { // Casting to a primitive, except booleans and the identity conversion printer.append(ret.getSimpleName()); - printer.append("Cast("); + if (exprType.equals(PyObject.class)) { + printer.append("PyCast((PyObject)"); + } else { + printer.append("Cast("); + } /* * When unboxing to a wider type, do an unboxing conversion followed by a widening conversion. See table diff --git a/DB/src/main/java/io/deephaven/db/tables/select/Param.java b/DB/src/main/java/io/deephaven/db/tables/select/Param.java index d3ed1544825..0d8b0856eb5 100644 --- a/DB/src/main/java/io/deephaven/db/tables/select/Param.java +++ b/DB/src/main/java/io/deephaven/db/tables/select/Param.java @@ -9,18 +9,16 @@ import groovy.lang.Closure; import java.lang.reflect.Modifier; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.function.Consumer; -import java.util.function.Function; -import java.util.stream.Collectors; -import java.util.stream.Stream; public class Param { - public static final Param[] ZERO_LENGTH_PARAM_ARRAY = new Param[0]; + public static final Param[] ZERO_LENGTH_PARAM_ARRAY = new Param[0]; private final String name; private final T value; @@ -38,54 +36,90 @@ public Param(String name, T value) { this.value = value; } - public Class getDeclaredType() { - final Class type = value == null ? Object.class - : value instanceof Enum ? ((Enum) value).getDeclaringClass() - // in newer versions of groovy, our closures will be subtypes that evade the logic in - // getDeclaredType - // (they will return a null Class#getCanonicalName b/c they are dynamic classes). - : value instanceof Closure ? Closure.class - : value.getClass(); + public Class getDeclaredClass() { + Type declaredType = getDeclaredType(); + Class cls = classFromType(declaredType); + + if (cls == null) { + throw new IllegalStateException("Unexpected declared type of type '" + + declaredType.getClass().getCanonicalName() + "'"); + } + + return cls; + } + + public static Class classFromType(final Type declaredType) { + if (declaredType instanceof Class) { + return (Class) declaredType; + } + if (declaredType instanceof ParameterizedType) { + return (Class) ((ParameterizedType) declaredType).getRawType(); + } + return null; + } + + public Type getDeclaredType() { + // in newer versions of groovy, our closures will be subtypes that evade the logic in getDeclaredType + // (they will return a null Class#getCanonicalName b/c they are dynamic classes). + final Class type; + if (value == null) { + type = Object.class; + } else if (value instanceof Enum) { + type = ((Enum) value).getDeclaringClass(); + } else if (value instanceof Closure) { + type = Closure.class; + } else { + type = value.getClass(); + } return getDeclaredType(type); } - protected static Class getDeclaredType(Class type) { - OUTER: while (type != Object.class) { + protected static Type getDeclaredType(final Class origType) { + Class type = origType; + while (type != Object.class) { if (Modifier.isPublic(type.getModifiers()) && !type.isAnonymousClass()) { break; } - Class[] interfaces = type.getInterfaces(); - for (Class iface : interfaces) { - if (iface.getMethods().length > 0) { - type = iface; - break OUTER; + + Type[] interfaces = type.getGenericInterfaces(); + for (Type ityp : interfaces) { + Class iface = null; + if (ityp instanceof Class) { + iface = (Class) ityp; + } else if (ityp instanceof ParameterizedType) { + ParameterizedType pt = (ParameterizedType) ityp; + Type rawType = pt.getRawType(); + if (rawType instanceof Class) { + iface = (Class) rawType; + } + } + + if (iface != null && iface.getMethods().length > 0) { + return ityp; } } + type = type.getSuperclass(); } - return type; + return origType; } public String getDeclaredTypeName() { - return getDeclaredType().getCanonicalName(); + return getDeclaredClass().getCanonicalName(); } public String getPrimitiveTypeNameIfAvailable() { if (value == null) { return getDeclaredTypeName(); } - Class type = getDeclaredType(); + Class type = getDeclaredClass(); if (io.deephaven.util.type.TypeUtils.isBoxedType(type)) { return TypeUtils.getUnboxedType(type).getCanonicalName(); } return getDeclaredTypeName(); } - protected static String getDeclaredTypeName(Class type) { - return getDeclaredType(type).getCanonicalName(); - } - /** * Get a map from binary name to declared type for the dynamic classes referenced by an array of param classes. * @@ -100,7 +134,7 @@ public static Map> expandParameterClasses(final List> private static void visitParameterClass(final Map> found, Class cls) { while (cls.isArray()) { - cls = getDeclaredType(cls.getComponentType()); + cls = classFromType(cls.getComponentType()); } final String name = cls.getName(); diff --git a/DB/src/main/java/io/deephaven/db/v2/select/AbstractConditionFilter.java b/DB/src/main/java/io/deephaven/db/v2/select/AbstractConditionFilter.java index b2b381a18f5..43601ffbee7 100644 --- a/DB/src/main/java/io/deephaven/db/v2/select/AbstractConditionFilter.java +++ b/DB/src/main/java/io/deephaven/db/v2/select/AbstractConditionFilter.java @@ -17,6 +17,8 @@ import org.jetbrains.annotations.NotNull; import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; import java.net.MalformedURLException; import java.util.*; @@ -84,7 +86,15 @@ public synchronized void init(TableDefinition tableDefinition) { final QueryScope queryScope = QueryScope.getScope(); for (Param param : queryScope.getParams(queryScope.getParamNames())) { possibleParams.put(param.getName(), param); - possibleVariables.put(param.getName(), param.getDeclaredType()); + possibleVariables.put(param.getName(), param.getDeclaredClass()); + Type declaredType = param.getDeclaredType(); + if (declaredType instanceof ParameterizedType) { + ParameterizedType pt = (ParameterizedType) declaredType; + Class[] paramTypes = Arrays.stream(pt.getActualTypeArguments()) + .map(Param::classFromType) + .toArray(Class[]::new); + possibleVariableParameterizedTypes.put(param.getName(), paramTypes); + } } Class compType; diff --git a/DB/src/main/java/io/deephaven/db/v2/select/ConditionFilter.java b/DB/src/main/java/io/deephaven/db/v2/select/ConditionFilter.java index c21da03e5a9..10e44e5e25d 100644 --- a/DB/src/main/java/io/deephaven/db/v2/select/ConditionFilter.java +++ b/DB/src/main/java/io/deephaven/db/v2/select/ConditionFilter.java @@ -383,7 +383,7 @@ protected void generateFilterCode(TableDefinition tableDefinition, DBTimeUtils.R addParamClass.accept(column.getComponentType()); } for (final Param param : params) { - addParamClass.accept(param.getDeclaredType()); + addParamClass.accept(param.getDeclaredClass()); } filterKernelClass = CompilerTools.compile("GeneratedFilterKernel", this.classBody = classBody.toString(), diff --git a/DB/src/main/java/io/deephaven/db/v2/select/DhFormulaColumn.java b/DB/src/main/java/io/deephaven/db/v2/select/DhFormulaColumn.java index d281f4274a8..380bc3893f2 100644 --- a/DB/src/main/java/io/deephaven/db/v2/select/DhFormulaColumn.java +++ b/DB/src/main/java/io/deephaven/db/v2/select/DhFormulaColumn.java @@ -669,7 +669,7 @@ private List visitFormulaParameters( if (paramLambda != null) { for (int ii = 0; ii < params.length; ++ii) { final Param p = params[ii]; - final ParamParameter pp = new ParamParameter(ii, p.getName(), p.getDeclaredType(), + final ParamParameter pp = new ParamParameter(ii, p.getName(), p.getDeclaredClass(), p.getDeclaredTypeName()); addIfNotNull(results, paramLambda.apply(pp)); } @@ -692,7 +692,7 @@ private JavaKernelBuilder.Result invokeKernelBuilder() { final Map> arrayDict = makeNameToTypeDict(sd.arrays, columnSources); final Map> allParamDict = new HashMap<>(); for (final Param param : params) { - allParamDict.put(param.getName(), param.getDeclaredType()); + allParamDict.put(param.getName(), param.getDeclaredClass()); } final Map> paramDict = new HashMap<>(); for (final String p : sd.params) { diff --git a/DB/src/main/java/io/deephaven/db/v2/select/codegen/FormulaAnalyzer.java b/DB/src/main/java/io/deephaven/db/v2/select/codegen/FormulaAnalyzer.java index f8445482937..9910a8e31a1 100644 --- a/DB/src/main/java/io/deephaven/db/v2/select/codegen/FormulaAnalyzer.java +++ b/DB/src/main/java/io/deephaven/db/v2/select/codegen/FormulaAnalyzer.java @@ -16,6 +16,8 @@ import io.deephaven.internal.log.LoggerFactory; import io.deephaven.io.logger.Logger; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; import java.util.*; public class FormulaAnalyzer { @@ -101,7 +103,16 @@ public static DBLanguageParser.Result getCompiledFormula(Map param : queryScope.getParams(queryScope.getParamNames())) { - possibleVariables.put(param.getName(), param.getDeclaredType()); + possibleVariables.put(param.getName(), param.getDeclaredClass()); + + Type declaredType = param.getDeclaredType(); + if (declaredType instanceof ParameterizedType) { + ParameterizedType pt = (ParameterizedType) declaredType; + Class[] paramTypes = Arrays.stream(pt.getActualTypeArguments()) + .map(Param::classFromType) + .toArray(Class[]::new); + possibleVariableParameterizedTypes.put(param.getName(), paramTypes); + } } for (ColumnDefinition columnDefinition : availableColumns.values()) { From 57ffe8969d8043a023a4730b916459d6030bdd86 Mon Sep 17 00:00:00 2001 From: Nathaniel Bauernfeind Date: Wed, 27 Oct 2021 08:50:07 -0600 Subject: [PATCH 02/14] add tests; revise behavior to better support maps --- .../db/tables/lang/DBLanguageParser.java | 13 +++++-- .../db/tables/lang/TestDBLanguageParser.java | 37 ++++++++++++++++++- 2 files changed, 45 insertions(+), 5 deletions(-) diff --git a/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageParser.java b/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageParser.java index 54e220005ac..f7e9027f82e 100644 --- a/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageParser.java +++ b/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageParser.java @@ -1006,8 +1006,15 @@ public Class visit(ArrayAccessExpr n, VisitArgs printer) { // We'll check for a known component type if this a NameExpr. if (n.getName() instanceof NameExpr) { Class[] classes = variableParameterizedTypes.get(((NameExpr) n.getName()).getNameAsString()); - if (classes != null && classes.length > 0) { - Class ret = classes[0]; + + if (classes != null) { + Class ret = null; + + if (classes.length == 1) { + ret = classes[0]; // scenario 1: this is a list-like type + } else if (classes.length == 2) { + ret = classes[1]; // scenario 2: this is a map-like type + } if (ret != null) { return ret; @@ -1177,7 +1184,7 @@ else if (fromBoxedType) { if (toPrimitive && !ret.equals(boolean.class) && !ret.equals(exprType)) { // Casting to a primitive, except booleans and the identity conversion printer.append(ret.getSimpleName()); - if (exprType.equals(PyObject.class)) { + if (isAssignableFrom(PyObject.class, exprType)) { printer.append("PyCast((PyObject)"); } else { printer.append("Cast("); diff --git a/DB/src/test/java/io/deephaven/db/tables/lang/TestDBLanguageParser.java b/DB/src/test/java/io/deephaven/db/tables/lang/TestDBLanguageParser.java index c6476fdc7f3..f33fa402f8f 100644 --- a/DB/src/test/java/io/deephaven/db/tables/lang/TestDBLanguageParser.java +++ b/DB/src/test/java/io/deephaven/db/tables/lang/TestDBLanguageParser.java @@ -19,6 +19,7 @@ import org.apache.commons.text.StringEscapeUtils; import org.apache.commons.lang3.exception.ExceptionUtils; import org.jetbrains.annotations.NotNull; +import org.jpy.PyObject; import org.junit.Before; import java.awt.*; @@ -109,6 +110,7 @@ public void setUp() throws Exception { variables.put("myDBDateTime", DBDateTime.class); variables.put("myTable", Table.class); + variables.put("myPyObject", PyObject.class); variables.put("ExampleQuantity", int.class); variables.put("ExampleQuantity2", double.class); @@ -117,6 +119,7 @@ public void setUp() throws Exception { variables.put("ExampleStr", String.class); variableParameterizedTypes = new HashMap<>(); + variableParameterizedTypes.put("myArrayList", new Class[] {Long.class}); variableParameterizedTypes.put("myHashMap", new Class[] {Integer.class, Double.class}); variableParameterizedTypes.put("myDBArray", new Class[] {Double.class}); } @@ -834,6 +837,36 @@ public void testPrimitiveAndBoxedToObjectCasts() throws Exception { } } + public void testPyObjectToPrimitiveCasts() throws Exception { + String expression = "(int)myPyObject"; + String resultExpression = "intPyCast((PyObject)myPyObject)"; + check(expression, resultExpression, int.class, new String[] {"myPyObject"}); + + expression = "(double)myPyObject"; + resultExpression = "doublePyCast((PyObject)myPyObject)"; + check(expression, resultExpression, double.class, new String[] {"myPyObject"}); + + expression = "(long)myPyObject"; + resultExpression = "longPyCast((PyObject)myPyObject)"; + check(expression, resultExpression, long.class, new String[] {"myPyObject"}); + + expression = "(float)myPyObject"; + resultExpression = "floatPyCast((PyObject)myPyObject)"; + check(expression, resultExpression, float.class, new String[] {"myPyObject"}); + + expression = "(char)myPyObject"; + resultExpression = "charPyCast((PyObject)myPyObject)"; + check(expression, resultExpression, char.class, new String[] {"myPyObject"}); + + expression = "(byte)myPyObject"; + resultExpression = "bytePyCast((PyObject)myPyObject)"; + check(expression, resultExpression, byte.class, new String[] {"myPyObject"}); + + expression = "(short)myPyObject"; + resultExpression = "shortPyCast((PyObject)myPyObject)"; + check(expression, resultExpression, short.class, new String[] {"myPyObject"}); + } + public void testVariables() throws Exception { String expression = "1+myInt"; String resultExpression = "plus(1, myInt)"; @@ -945,11 +978,11 @@ public void testArrayOperatorOverloading() throws Exception { expression = "myArrayList[15]"; resultExpression = "myArrayList.get(15)"; - check(expression, resultExpression, Object.class, new String[] {"myArrayList"}); + check(expression, resultExpression, Long.class, new String[] {"myArrayList"}); expression = "myHashMap[\"test\"]"; resultExpression = "myHashMap.get(\"test\")"; - check(expression, resultExpression, Object.class, new String[] {"myHashMap"}); + check(expression, resultExpression, Double.class, new String[] {"myHashMap"}); expression = "myIntArray==myDoubleArray"; resultExpression = "eqArray(myIntArray, myDoubleArray)"; From dfd556f0e820e56f19ebf3141207784f7a8575d6 Mon Sep 17 00:00:00 2001 From: Nathaniel Bauernfeind Date: Wed, 27 Oct 2021 10:07:35 -0600 Subject: [PATCH 03/14] bug fix --- .../main/java/io/deephaven/db/tables/lang/DBLanguageParser.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageParser.java b/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageParser.java index f7e9027f82e..b7d424847f6 100644 --- a/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageParser.java +++ b/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageParser.java @@ -1184,7 +1184,7 @@ else if (fromBoxedType) { if (toPrimitive && !ret.equals(boolean.class) && !ret.equals(exprType)) { // Casting to a primitive, except booleans and the identity conversion printer.append(ret.getSimpleName()); - if (isAssignableFrom(PyObject.class, exprType)) { + if (exprType != NULL_CLASS && isAssignableFrom(PyObject.class, exprType)) { printer.append("PyCast((PyObject)"); } else { printer.append("Cast("); From 2b7c1db4bccfc07b6904b948ded6e72fa6053ab4 Mon Sep 17 00:00:00 2001 From: Nathaniel Bauernfeind Date: Wed, 27 Oct 2021 17:23:08 -0600 Subject: [PATCH 04/14] fix a broken integration test --- .../main/java/io/deephaven/db/tables/lang/DBLanguageParser.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageParser.java b/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageParser.java index b7d424847f6..45c7c08fc9c 100644 --- a/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageParser.java +++ b/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageParser.java @@ -1503,6 +1503,8 @@ public Class visit(FieldAccessExpr n, VisitArgs printer) { // The to-be-cast expr is a Python object field accessor final String clsName = printer.pythonCastContext.getSimpleName(); printer.append(", " + clsName + ".class"); + // Let's advertise to the caller our the casted type + ret = printer.pythonCastContext; } printer.append(')'); } else { From 902282487589a5629ceaa72f4b68aea116810c53 Mon Sep 17 00:00:00 2001 From: Nathaniel Bauernfeind Date: Wed, 27 Oct 2021 19:00:16 -0600 Subject: [PATCH 05/14] colin's feedback --- .../deephaven/db/tables/lang/DBLanguageFunctionGenerator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageFunctionGenerator.java b/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageFunctionGenerator.java index 880e9cc72ea..7fb3a2735b8 100644 --- a/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageFunctionGenerator.java +++ b/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageFunctionGenerator.java @@ -585,7 +585,7 @@ public static void main(String args[]) { buf.append(" }\n\n"); buf.append(" public static short shortPyCast(PyObject a) {\n"); - buf.append(" return (short) a.getIntValue();\n"); + buf.append(" return (short) a.getIntValue();\n"); buf.append(" }\n\n"); // ------------------------------------------------------------------------------------------------------------------------------------------------------------------ From 1c389fb5ab4692f60a7adeeb5109ae0649dd1025 Mon Sep 17 00:00:00 2001 From: Nathaniel Bauernfeind Date: Fri, 29 Oct 2021 13:54:27 -0600 Subject: [PATCH 06/14] add null checking to casts; cast only in the method --- .../lang/DBLanguageFunctionGenerator.java | 118 ++++++++++++++---- .../tables/lang/DBLanguageFunctionUtil.java | 90 ++++++++++--- 2 files changed, 167 insertions(+), 41 deletions(-) diff --git a/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageFunctionGenerator.java b/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageFunctionGenerator.java index 7fb3a2735b8..7746d061838 100644 --- a/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageFunctionGenerator.java +++ b/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageFunctionGenerator.java @@ -4,8 +4,10 @@ package io.deephaven.db.tables.lang; +import io.deephaven.util.QueryConstants; import io.deephaven.util.type.TypeUtils; import com.github.javaparser.ast.expr.BinaryExpr; +import org.jpy.PyObject; import java.io.*; import java.text.*; @@ -560,33 +562,95 @@ public static void main(String args[]) { } // Special casts for PyObject to primitive - buf.append(" public static int intPyCast(PyObject a) {\n"); - buf.append(" return a.getIntValue();\n"); - buf.append(" }\n\n"); - - buf.append(" public static double doublePyCast(PyObject a) {\n"); - buf.append(" return a.getDoubleValue();\n"); - buf.append(" }\n\n"); - - buf.append(" public static long longPyCast(PyObject a) {\n"); - buf.append(" return a.getLongValue();\n"); - buf.append(" }\n\n"); - - buf.append(" public static float floatPyCast(PyObject a) {\n"); - buf.append(" return (float) a.getDoubleValue();\n"); - buf.append(" }\n\n"); - - buf.append(" public static char charPyCast(PyObject a) {\n"); - buf.append(" return (char) a.getIntValue();\n"); - buf.append(" }\n\n"); - - buf.append(" public static byte bytePyCast(PyObject a) {\n"); - buf.append(" return (byte) a.getIntValue();\n"); - buf.append(" }\n\n"); - - buf.append(" public static short shortPyCast(PyObject a) {\n"); - buf.append(" return (short) a.getIntValue();\n"); - buf.append(" }\n\n"); + buf.append(" public static int intPyCast(Object a) {\n"); + buf.append(" if (a == null) {\n"); + buf.append(" return QueryConstants.NULL_INT;\n"); + buf.append(" }\n"); + buf.append(" if (!(a instanceof PyObject)) {\n"); + buf.append(" throw new IllegalArgumentException(\"provided value is not a PyObject\");\n"); + buf.append(" }\n"); + buf.append(" return ((PyObject)a).getIntValue();\n"); + buf.append(" }\n\n"); + + buf.append(" public static double doublePyCast(Object a) {\n"); + buf.append(" if (a == null) {\n"); + buf.append(" return QueryConstants.NULL_DOUBLE;\n"); + buf.append(" }\n"); + buf.append(" if (!(a instanceof PyObject)) {\n"); + buf.append(" throw new IllegalArgumentException(\"provided value is not a PyObject\");\n"); + buf.append(" }\n"); + buf.append(" return ((PyObject)a).getDoubleValue();\n"); + buf.append(" }\n\n"); + + buf.append(" public static long longPyCast(Object a) {\n"); + buf.append(" if (a == null) {\n"); + buf.append(" return QueryConstants.NULL_LONG;\n"); + buf.append(" }\n"); + buf.append(" if (!(a instanceof PyObject)) {\n"); + buf.append(" throw new IllegalArgumentException(\"provided value is not a PyObject\");\n"); + buf.append(" }\n"); + buf.append(" return ((PyObject)a).getLongValue();\n"); + buf.append(" }\n\n"); + + buf.append(" public static float floatPyCast(Object a) {\n"); + buf.append(" if (a == null) {\n"); + buf.append(" return QueryConstants.NULL_FLOAT;\n"); + buf.append(" }\n"); + buf.append(" if (!(a instanceof PyObject)) {\n"); + buf.append(" throw new IllegalArgumentException(\"provided value is not a PyObject\");\n"); + buf.append(" }\n"); + buf.append(" return (float) ((PyObject)a).getDoubleValue();\n"); + buf.append(" }\n\n"); + + buf.append(" public static char charPyCast(Object a) {\n"); + buf.append(" if (a == null) {\n"); + buf.append(" return QueryConstants.NULL_CHAR;\n"); + buf.append(" }\n"); + buf.append(" if (!(a instanceof PyObject)) {\n"); + buf.append(" throw new IllegalArgumentException(\"provided value is not a PyObject\");\n"); + buf.append(" }\n"); + buf.append(" return (char) ((PyObject)a).getIntValue();\n"); + buf.append(" }\n\n"); + + buf.append(" public static byte bytePyCast(Object a) {\n"); + buf.append(" if (a == null) {\n"); + buf.append(" return QueryConstants.NULL_BYTE;\n"); + buf.append(" }\n"); + buf.append(" if (!(a instanceof PyObject)) {\n"); + buf.append(" throw new IllegalArgumentException(\"provided value is not a PyObject\");\n"); + buf.append(" }\n"); + buf.append(" return (byte) ((PyObject)a).getIntValue();\n"); + buf.append(" }\n\n"); + + buf.append(" public static short shortPyCast(Object a) {\n"); + buf.append(" if (a == null) {\n"); + buf.append(" return QueryConstants.NULL_SHORT;\n"); + buf.append(" }\n"); + buf.append(" if (!(a instanceof PyObject)) {\n"); + buf.append(" throw new IllegalArgumentException(\"provided value is not a PyObject\");\n"); + buf.append(" }\n"); + buf.append(" return (short) ((PyObject)a).getIntValue();\n"); + buf.append(" }\n\n"); + + buf.append(" public static String stringPyCast(Object a) {\n"); + buf.append(" if (a == null) {\n"); + buf.append(" return null;\n"); + buf.append(" }\n"); + buf.append(" if (!(a instanceof PyObject)) {\n"); + buf.append(" throw new IllegalArgumentException(\"provided value is not a PyObject\");\n"); + buf.append(" }\n"); + buf.append(" return ((PyObject) a).getStringValue();\n"); + buf.append(" }\n\n"); + + buf.append(" public static boolean booleanPyCast(Object a) {\n"); + buf.append(" if (a == null) {\n"); + buf.append(" return false;\n"); + buf.append(" }\n"); + buf.append(" if (!(a instanceof PyObject)) {\n"); + buf.append(" throw new IllegalArgumentException(\"provided value is not a PyObject\");\n"); + buf.append(" }\n"); + buf.append(" return ((PyObject)a).getBooleanValue();\n"); + buf.append(" }\n\n"); // ------------------------------------------------------------------------------------------------------------------------------------------------------------------ diff --git a/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageFunctionUtil.java b/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageFunctionUtil.java index 10d2b65b435..8bec1f79e65 100644 --- a/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageFunctionUtil.java +++ b/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageFunctionUtil.java @@ -19290,32 +19290,94 @@ public static short shortCast(Object a) { return a == null ? QueryConstants.NULL_SHORT : (short) a; } - public static int intPyCast(PyObject a) { - return a.getIntValue(); + public static int intPyCast(Object a) { + if (a == null) { + return QueryConstants.NULL_INT; + } + if (!(a instanceof PyObject)) { + throw new IllegalArgumentException("provided value is not a PyObject"); + } + return ((PyObject)a).getIntValue(); } - public static double doublePyCast(PyObject a) { - return a.getDoubleValue(); + public static double doublePyCast(Object a) { + if (a == null) { + return QueryConstants.NULL_DOUBLE; + } + if (!(a instanceof PyObject)) { + throw new IllegalArgumentException("provided value is not a PyObject"); + } + return ((PyObject)a).getDoubleValue(); } - public static long longPyCast(PyObject a) { - return a.getLongValue(); + public static long longPyCast(Object a) { + if (a == null) { + return QueryConstants.NULL_LONG; + } + if (!(a instanceof PyObject)) { + throw new IllegalArgumentException("provided value is not a PyObject"); + } + return ((PyObject)a).getLongValue(); } - public static float floatPyCast(PyObject a) { - return (float) a.getDoubleValue(); + public static float floatPyCast(Object a) { + if (a == null) { + return QueryConstants.NULL_FLOAT; + } + if (!(a instanceof PyObject)) { + throw new IllegalArgumentException("provided value is not a PyObject"); + } + return (float) ((PyObject)a).getDoubleValue(); } - public static char charPyCast(PyObject a) { - return (char) a.getIntValue(); + public static char charPyCast(Object a) { + if (a == null) { + return QueryConstants.NULL_CHAR; + } + if (!(a instanceof PyObject)) { + throw new IllegalArgumentException("provided value is not a PyObject"); + } + return (char) ((PyObject)a).getIntValue(); } - public static byte bytePyCast(PyObject a) { - return (byte) a.getIntValue(); + public static byte bytePyCast(Object a) { + if (a == null) { + return QueryConstants.NULL_BYTE; + } + if (!(a instanceof PyObject)) { + throw new IllegalArgumentException("provided value is not a PyObject"); + } + return (byte) ((PyObject)a).getIntValue(); } - public static short shortPyCast(PyObject a) { - return (short) a.getIntValue(); + public static short shortPyCast(Object a) { + if (a == null) { + return QueryConstants.NULL_SHORT; + } + if (!(a instanceof PyObject)) { + throw new IllegalArgumentException("provided value is not a PyObject"); + } + return (short) ((PyObject)a).getIntValue(); + } + + public static String stringPyCast(Object a) { + if (a == null) { + return null; + } + if (!(a instanceof PyObject)) { + throw new IllegalArgumentException("provided value is not a PyObject"); + } + return ((PyObject) a).getStringValue(); + } + + public static boolean booleanPyCast(Object a) { + if (a == null) { + return false; + } + if (!(a instanceof PyObject)) { + throw new IllegalArgumentException("provided value is not a PyObject"); + } + return ((PyObject)a).getBooleanValue(); } public static int negate(int a) { From 53e876c2af3fbe42dc6eb999aae75d2e01367692 Mon Sep 17 00:00:00 2001 From: Nathaniel Bauernfeind Date: Fri, 29 Oct 2021 15:04:42 -0600 Subject: [PATCH 07/14] Ryan's feedback --- DB/src/main/java/io/deephaven/db/tables/select/Param.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DB/src/main/java/io/deephaven/db/tables/select/Param.java b/DB/src/main/java/io/deephaven/db/tables/select/Param.java index 0d8b0856eb5..21d5d216fe2 100644 --- a/DB/src/main/java/io/deephaven/db/tables/select/Param.java +++ b/DB/src/main/java/io/deephaven/db/tables/select/Param.java @@ -94,7 +94,7 @@ protected static Type getDeclaredType(final Class origType) { } } - if (iface != null && iface.getMethods().length > 0) { + if (iface != null && Modifier.isPublic(iface.getModifiers()) && iface.getMethods().length > 0) { return ityp; } } @@ -102,7 +102,7 @@ protected static Type getDeclaredType(final Class origType) { type = type.getSuperclass(); } - return origType; + return type; } public String getDeclaredTypeName() { From 68aba0ca2390e83d9c505672a06f76c06e40059c Mon Sep 17 00:00:00 2001 From: Nathaniel Bauernfeind Date: Fri, 29 Oct 2021 16:49:18 -0600 Subject: [PATCH 08/14] fixup null per testing --- .../lang/DBLanguageFunctionGenerator.java | 203 ++++++++++-------- .../tables/lang/DBLanguageFunctionUtil.java | 99 +++++---- .../db/tables/lang/DBLanguageParser.java | 15 +- 3 files changed, 188 insertions(+), 129 deletions(-) diff --git a/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageFunctionGenerator.java b/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageFunctionGenerator.java index 7746d061838..8e26bc71698 100644 --- a/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageFunctionGenerator.java +++ b/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageFunctionGenerator.java @@ -562,95 +562,120 @@ public static void main(String args[]) { } // Special casts for PyObject to primitive - buf.append(" public static int intPyCast(Object a) {\n"); - buf.append(" if (a == null) {\n"); - buf.append(" return QueryConstants.NULL_INT;\n"); - buf.append(" }\n"); - buf.append(" if (!(a instanceof PyObject)) {\n"); - buf.append(" throw new IllegalArgumentException(\"provided value is not a PyObject\");\n"); - buf.append(" }\n"); - buf.append(" return ((PyObject)a).getIntValue();\n"); - buf.append(" }\n\n"); - - buf.append(" public static double doublePyCast(Object a) {\n"); - buf.append(" if (a == null) {\n"); - buf.append(" return QueryConstants.NULL_DOUBLE;\n"); - buf.append(" }\n"); - buf.append(" if (!(a instanceof PyObject)) {\n"); - buf.append(" throw new IllegalArgumentException(\"provided value is not a PyObject\");\n"); - buf.append(" }\n"); - buf.append(" return ((PyObject)a).getDoubleValue();\n"); - buf.append(" }\n\n"); - - buf.append(" public static long longPyCast(Object a) {\n"); - buf.append(" if (a == null) {\n"); - buf.append(" return QueryConstants.NULL_LONG;\n"); - buf.append(" }\n"); - buf.append(" if (!(a instanceof PyObject)) {\n"); - buf.append(" throw new IllegalArgumentException(\"provided value is not a PyObject\");\n"); - buf.append(" }\n"); - buf.append(" return ((PyObject)a).getLongValue();\n"); - buf.append(" }\n\n"); - - buf.append(" public static float floatPyCast(Object a) {\n"); - buf.append(" if (a == null) {\n"); - buf.append(" return QueryConstants.NULL_FLOAT;\n"); - buf.append(" }\n"); - buf.append(" if (!(a instanceof PyObject)) {\n"); - buf.append(" throw new IllegalArgumentException(\"provided value is not a PyObject\");\n"); - buf.append(" }\n"); - buf.append(" return (float) ((PyObject)a).getDoubleValue();\n"); - buf.append(" }\n\n"); - - buf.append(" public static char charPyCast(Object a) {\n"); - buf.append(" if (a == null) {\n"); - buf.append(" return QueryConstants.NULL_CHAR;\n"); - buf.append(" }\n"); - buf.append(" if (!(a instanceof PyObject)) {\n"); - buf.append(" throw new IllegalArgumentException(\"provided value is not a PyObject\");\n"); - buf.append(" }\n"); - buf.append(" return (char) ((PyObject)a).getIntValue();\n"); - buf.append(" }\n\n"); - - buf.append(" public static byte bytePyCast(Object a) {\n"); - buf.append(" if (a == null) {\n"); - buf.append(" return QueryConstants.NULL_BYTE;\n"); - buf.append(" }\n"); - buf.append(" if (!(a instanceof PyObject)) {\n"); - buf.append(" throw new IllegalArgumentException(\"provided value is not a PyObject\");\n"); - buf.append(" }\n"); - buf.append(" return (byte) ((PyObject)a).getIntValue();\n"); - buf.append(" }\n\n"); - - buf.append(" public static short shortPyCast(Object a) {\n"); - buf.append(" if (a == null) {\n"); - buf.append(" return QueryConstants.NULL_SHORT;\n"); - buf.append(" }\n"); - buf.append(" if (!(a instanceof PyObject)) {\n"); - buf.append(" throw new IllegalArgumentException(\"provided value is not a PyObject\");\n"); - buf.append(" }\n"); - buf.append(" return (short) ((PyObject)a).getIntValue();\n"); - buf.append(" }\n\n"); - - buf.append(" public static String stringPyCast(Object a) {\n"); - buf.append(" if (a == null) {\n"); - buf.append(" return null;\n"); - buf.append(" }\n"); - buf.append(" if (!(a instanceof PyObject)) {\n"); - buf.append(" throw new IllegalArgumentException(\"provided value is not a PyObject\");\n"); - buf.append(" }\n"); - buf.append(" return ((PyObject) a).getStringValue();\n"); - buf.append(" }\n\n"); - - buf.append(" public static boolean booleanPyCast(Object a) {\n"); - buf.append(" if (a == null) {\n"); - buf.append(" return false;\n"); - buf.append(" }\n"); - buf.append(" if (!(a instanceof PyObject)) {\n"); - buf.append(" throw new IllegalArgumentException(\"provided value is not a PyObject\");\n"); - buf.append(" }\n"); - buf.append(" return ((PyObject)a).getBooleanValue();\n"); - buf.append(" }\n\n"); +buf.append(" public static int intPyCast(Object a) {\n"); +buf.append(" if (a != null && !(a instanceof PyObject)) {\n"); +buf.append(" throw new IllegalArgumentException(\"provided value is not a PyObject\");\n"); +buf.append(" }\n"); +buf.append(" PyObject o = (PyObject) a;\n"); +buf.append(" if (o == null || o.isNone()) {\n"); +buf.append(" return QueryConstants.NULL_INT;\n"); +buf.append(" }\n"); +buf.append(" return o.getIntValue();\n"); +buf.append(" }\n\n"); + +buf.append(" public static double doublePyCast(Object a) {\n"); +buf.append(" if (a != null && !(a instanceof PyObject)) {\n"); +buf.append(" throw new IllegalArgumentException(\"provided value is not a PyObject\");\n"); +buf.append(" }\n"); +buf.append(" PyObject o = (PyObject) a;\n"); +buf.append(" if (o == null || o.isNone()) {\n"); +buf.append(" return QueryConstants.NULL_DOUBLE;\n"); +buf.append(" }\n"); +buf.append(" return o.getDoubleValue();\n"); +buf.append(" }\n\n"); + +buf.append(" public static long longPyCast(Object a) {\n"); +buf.append(" if (a != null && !(a instanceof PyObject)) {\n"); +buf.append(" throw new IllegalArgumentException(\"provided value is not a PyObject\");\n"); +buf.append(" }\n"); +buf.append(" PyObject o = (PyObject) a;\n"); +buf.append(" if (o == null || o.isNone()) {\n"); +buf.append(" return QueryConstants.NULL_LONG;\n"); +buf.append(" }\n"); +buf.append(" return o.getLongValue();\n"); +buf.append(" }\n\n"); + +buf.append(" public static float floatPyCast(Object a) {\n"); +buf.append(" if (a != null && !(a instanceof PyObject)) {\n"); +buf.append(" throw new IllegalArgumentException(\"provided value is not a PyObject\");\n"); +buf.append(" }\n"); +buf.append(" PyObject o = (PyObject) a;\n"); +buf.append(" if (o == null || o.isNone()) {\n"); +buf.append(" return QueryConstants.NULL_FLOAT;\n"); +buf.append(" }\n"); +buf.append(" return (float) o.getDoubleValue();\n"); +buf.append(" }\n\n"); + +buf.append(" public static char charPyCast(Object a) {\n"); +buf.append(" if (a != null && !(a instanceof PyObject)) {\n"); +buf.append(" throw new IllegalArgumentException(\"provided value is not a PyObject\");\n"); +buf.append(" }\n"); +buf.append(" PyObject o = (PyObject) a;\n"); +buf.append(" if (o == null || o.isNone()) {\n"); +buf.append(" return QueryConstants.NULL_CHAR;\n"); +buf.append(" }\n"); +buf.append(" return (char) o.getIntValue();\n"); +buf.append(" }\n\n"); + +buf.append(" public static byte bytePyCast(Object a) {\n"); +buf.append(" if (a != null && !(a instanceof PyObject)) {\n"); +buf.append(" throw new IllegalArgumentException(\"provided value is not a PyObject\");\n"); +buf.append(" }\n"); +buf.append(" PyObject o = (PyObject) a;\n"); +buf.append(" if (o == null || o.isNone()) {\n"); +buf.append(" return QueryConstants.NULL_BYTE;\n"); +buf.append(" }\n"); +buf.append(" return (byte) o.getIntValue();\n"); +buf.append(" }\n\n"); + +buf.append(" public static short shortPyCast(Object a) {\n"); +buf.append(" if (a != null && !(a instanceof PyObject)) {\n"); +buf.append(" throw new IllegalArgumentException(\"provided value is not a PyObject\");\n"); +buf.append(" }\n"); +buf.append(" PyObject o = (PyObject) a;\n"); +buf.append(" if (o == null || o.isNone()) {\n"); +buf.append(" return QueryConstants.NULL_SHORT;\n"); +buf.append(" }\n"); +buf.append(" return (short) o.getIntValue();\n"); +buf.append(" }\n\n"); + +buf.append(" public static String doStringPyCast(Object a) {\n"); +buf.append(" if (a == null) {\n"); +buf.append(" return null;\n"); +buf.append(" }\n"); +buf.append(" if (!(a instanceof PyObject)) {\n"); +buf.append(" throw new IllegalArgumentException(\"provided value is not a PyObject\");\n"); +buf.append(" }\n"); +buf.append(" PyObject o = (PyObject) a;\n"); +buf.append(" if (o.isNone()) {\n"); +buf.append(" return null;\n"); +buf.append(" }\n"); +buf.append(" return o.getStringValue();\n"); +buf.append(" }\n\n"); + +buf.append(" public static boolean booleanPyCast(Object a) {\n"); +buf.append(" if (a == null) {\n"); +buf.append(" return false;\n"); +buf.append(" }\n"); +buf.append(" if (!(a instanceof PyObject)) {\n"); +buf.append(" throw new IllegalArgumentException(\"provided value is not a PyObject\");\n"); +buf.append(" }\n"); +buf.append(" return ((PyObject) a).getBooleanValue();\n"); +buf.append(" }\n\n"); + +buf.append(" public static Boolean doBooleanPyCast(Object a) {\n"); +buf.append(" if (a == null) {\n"); +buf.append(" return null;\n"); +buf.append(" }\n"); +buf.append(" if (!(a instanceof PyObject)) {\n"); +buf.append(" throw new IllegalArgumentException(\"provided value is not a PyObject\");\n"); +buf.append(" }\n"); +buf.append(" PyObject o = (PyObject) a;\n"); +buf.append(" if (o.isNone()) {\n"); +buf.append(" return null;\n"); +buf.append(" }\n"); +buf.append(" return o.getBooleanValue();\n"); +buf.append(" }\n\n"); // ------------------------------------------------------------------------------------------------------------------------------------------------------------------ diff --git a/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageFunctionUtil.java b/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageFunctionUtil.java index 8bec1f79e65..b56d9bd179b 100644 --- a/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageFunctionUtil.java +++ b/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageFunctionUtil.java @@ -19291,93 +19291,118 @@ public static short shortCast(Object a) { } public static int intPyCast(Object a) { - if (a == null) { - return QueryConstants.NULL_INT; - } - if (!(a instanceof PyObject)) { + if (a != null && !(a instanceof PyObject)) { throw new IllegalArgumentException("provided value is not a PyObject"); } - return ((PyObject)a).getIntValue(); + PyObject o = (PyObject) a; + if (o == null || o.isNone()) { + return QueryConstants.NULL_INT; + } + return o.getIntValue(); } public static double doublePyCast(Object a) { - if (a == null) { - return QueryConstants.NULL_DOUBLE; - } - if (!(a instanceof PyObject)) { + if (a != null && !(a instanceof PyObject)) { throw new IllegalArgumentException("provided value is not a PyObject"); } - return ((PyObject)a).getDoubleValue(); + PyObject o = (PyObject) a; + if (o == null || o.isNone()) { + return QueryConstants.NULL_DOUBLE; + } + return o.getDoubleValue(); } public static long longPyCast(Object a) { - if (a == null) { - return QueryConstants.NULL_LONG; - } - if (!(a instanceof PyObject)) { + if (a != null && !(a instanceof PyObject)) { throw new IllegalArgumentException("provided value is not a PyObject"); } - return ((PyObject)a).getLongValue(); + PyObject o = (PyObject) a; + if (o == null || o.isNone()) { + return QueryConstants.NULL_LONG; + } + return o.getLongValue(); } public static float floatPyCast(Object a) { - if (a == null) { - return QueryConstants.NULL_FLOAT; - } - if (!(a instanceof PyObject)) { + if (a != null && !(a instanceof PyObject)) { throw new IllegalArgumentException("provided value is not a PyObject"); } - return (float) ((PyObject)a).getDoubleValue(); + PyObject o = (PyObject) a; + if (o == null || o.isNone()) { + return QueryConstants.NULL_FLOAT; + } + return (float) o.getDoubleValue(); } public static char charPyCast(Object a) { - if (a == null) { - return QueryConstants.NULL_CHAR; - } - if (!(a instanceof PyObject)) { + if (a != null && !(a instanceof PyObject)) { throw new IllegalArgumentException("provided value is not a PyObject"); } - return (char) ((PyObject)a).getIntValue(); + PyObject o = (PyObject) a; + if (o == null || o.isNone()) { + return QueryConstants.NULL_CHAR; + } + return (char) o.getIntValue(); } public static byte bytePyCast(Object a) { - if (a == null) { + if (a != null && !(a instanceof PyObject)) { + throw new IllegalArgumentException("provided value is not a PyObject"); + } + PyObject o = (PyObject) a; + if (o == null || o.isNone()) { return QueryConstants.NULL_BYTE; } - if (!(a instanceof PyObject)) { + return (byte) o.getIntValue(); + } + + public static short shortPyCast(Object a) { + if (a != null && !(a instanceof PyObject)) { throw new IllegalArgumentException("provided value is not a PyObject"); } - return (byte) ((PyObject)a).getIntValue(); + PyObject o = (PyObject) a; + if (o == null || o.isNone()) { + return QueryConstants.NULL_SHORT; + } + return (short) o.getIntValue(); } - public static short shortPyCast(Object a) { + public static String doStringPyCast(Object a) { if (a == null) { - return QueryConstants.NULL_SHORT; + return null; } if (!(a instanceof PyObject)) { throw new IllegalArgumentException("provided value is not a PyObject"); } - return (short) ((PyObject)a).getIntValue(); + PyObject o = (PyObject) a; + if (o.isNone()) { + return null; + } + return o.getStringValue(); } - public static String stringPyCast(Object a) { + public static boolean booleanPyCast(Object a) { if (a == null) { - return null; + return false; } if (!(a instanceof PyObject)) { throw new IllegalArgumentException("provided value is not a PyObject"); } - return ((PyObject) a).getStringValue(); + return ((PyObject) a).getBooleanValue(); } - public static boolean booleanPyCast(Object a) { + public static Boolean doBooleanPyCast(Object a) { if (a == null) { - return false; + return null; } if (!(a instanceof PyObject)) { throw new IllegalArgumentException("provided value is not a PyObject"); } - return ((PyObject)a).getBooleanValue(); + PyObject o = (PyObject) a; + if (o.isNone()) { + return null; + } + return o.getBooleanValue(); } public static int negate(int a) { diff --git a/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageParser.java b/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageParser.java index 45c7c08fc9c..d9df85547f7 100644 --- a/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageParser.java +++ b/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageParser.java @@ -1177,15 +1177,24 @@ else if (fromBoxedType) { * Now actually print the cast. For casts to primitives (except boolean), we use special null-safe functions * (e.g. intCast()) to perform the cast. * - * There is no "booleanCast()" function. + * There is no "booleanCast()" function. However, we do try to cast to String and Boolean from PyObjects. * * There are also no special functions for the identity conversion -- e.g. "intCast(int)" */ - if (toPrimitive && !ret.equals(boolean.class) && !ret.equals(exprType)) { + final boolean isPyUpgrade = + ((ret.equals(boolean.class) || ret.equals(Boolean.class) || ret.equals(String.class)) + && exprType.equals(PyObject.class)); + + if (toPrimitive && !ret.equals(boolean.class) && !ret.equals(exprType) || isPyUpgrade) { // Casting to a primitive, except booleans and the identity conversion + if (!toPrimitive) { + // these methods look like `doStringPyCast` and `doBooleanPyCast` + printer.append("do"); + } printer.append(ret.getSimpleName()); + if (exprType != NULL_CLASS && isAssignableFrom(PyObject.class, exprType)) { - printer.append("PyCast((PyObject)"); + printer.append("PyCast("); } else { printer.append("Cast("); } From 2ec4d6506575aaaf1110e6724ad9977256bb85ff Mon Sep 17 00:00:00 2001 From: Nathaniel Bauernfeind Date: Sat, 30 Oct 2021 13:13:54 -0600 Subject: [PATCH 09/14] spotless --- .../lang/DBLanguageFunctionGenerator.java | 228 +++++++++--------- 1 file changed, 114 insertions(+), 114 deletions(-) diff --git a/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageFunctionGenerator.java b/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageFunctionGenerator.java index 8e26bc71698..87355eadc21 100644 --- a/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageFunctionGenerator.java +++ b/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageFunctionGenerator.java @@ -562,120 +562,120 @@ public static void main(String args[]) { } // Special casts for PyObject to primitive -buf.append(" public static int intPyCast(Object a) {\n"); -buf.append(" if (a != null && !(a instanceof PyObject)) {\n"); -buf.append(" throw new IllegalArgumentException(\"provided value is not a PyObject\");\n"); -buf.append(" }\n"); -buf.append(" PyObject o = (PyObject) a;\n"); -buf.append(" if (o == null || o.isNone()) {\n"); -buf.append(" return QueryConstants.NULL_INT;\n"); -buf.append(" }\n"); -buf.append(" return o.getIntValue();\n"); -buf.append(" }\n\n"); - -buf.append(" public static double doublePyCast(Object a) {\n"); -buf.append(" if (a != null && !(a instanceof PyObject)) {\n"); -buf.append(" throw new IllegalArgumentException(\"provided value is not a PyObject\");\n"); -buf.append(" }\n"); -buf.append(" PyObject o = (PyObject) a;\n"); -buf.append(" if (o == null || o.isNone()) {\n"); -buf.append(" return QueryConstants.NULL_DOUBLE;\n"); -buf.append(" }\n"); -buf.append(" return o.getDoubleValue();\n"); -buf.append(" }\n\n"); - -buf.append(" public static long longPyCast(Object a) {\n"); -buf.append(" if (a != null && !(a instanceof PyObject)) {\n"); -buf.append(" throw new IllegalArgumentException(\"provided value is not a PyObject\");\n"); -buf.append(" }\n"); -buf.append(" PyObject o = (PyObject) a;\n"); -buf.append(" if (o == null || o.isNone()) {\n"); -buf.append(" return QueryConstants.NULL_LONG;\n"); -buf.append(" }\n"); -buf.append(" return o.getLongValue();\n"); -buf.append(" }\n\n"); - -buf.append(" public static float floatPyCast(Object a) {\n"); -buf.append(" if (a != null && !(a instanceof PyObject)) {\n"); -buf.append(" throw new IllegalArgumentException(\"provided value is not a PyObject\");\n"); -buf.append(" }\n"); -buf.append(" PyObject o = (PyObject) a;\n"); -buf.append(" if (o == null || o.isNone()) {\n"); -buf.append(" return QueryConstants.NULL_FLOAT;\n"); -buf.append(" }\n"); -buf.append(" return (float) o.getDoubleValue();\n"); -buf.append(" }\n\n"); - -buf.append(" public static char charPyCast(Object a) {\n"); -buf.append(" if (a != null && !(a instanceof PyObject)) {\n"); -buf.append(" throw new IllegalArgumentException(\"provided value is not a PyObject\");\n"); -buf.append(" }\n"); -buf.append(" PyObject o = (PyObject) a;\n"); -buf.append(" if (o == null || o.isNone()) {\n"); -buf.append(" return QueryConstants.NULL_CHAR;\n"); -buf.append(" }\n"); -buf.append(" return (char) o.getIntValue();\n"); -buf.append(" }\n\n"); - -buf.append(" public static byte bytePyCast(Object a) {\n"); -buf.append(" if (a != null && !(a instanceof PyObject)) {\n"); -buf.append(" throw new IllegalArgumentException(\"provided value is not a PyObject\");\n"); -buf.append(" }\n"); -buf.append(" PyObject o = (PyObject) a;\n"); -buf.append(" if (o == null || o.isNone()) {\n"); -buf.append(" return QueryConstants.NULL_BYTE;\n"); -buf.append(" }\n"); -buf.append(" return (byte) o.getIntValue();\n"); -buf.append(" }\n\n"); - -buf.append(" public static short shortPyCast(Object a) {\n"); -buf.append(" if (a != null && !(a instanceof PyObject)) {\n"); -buf.append(" throw new IllegalArgumentException(\"provided value is not a PyObject\");\n"); -buf.append(" }\n"); -buf.append(" PyObject o = (PyObject) a;\n"); -buf.append(" if (o == null || o.isNone()) {\n"); -buf.append(" return QueryConstants.NULL_SHORT;\n"); -buf.append(" }\n"); -buf.append(" return (short) o.getIntValue();\n"); -buf.append(" }\n\n"); - -buf.append(" public static String doStringPyCast(Object a) {\n"); -buf.append(" if (a == null) {\n"); -buf.append(" return null;\n"); -buf.append(" }\n"); -buf.append(" if (!(a instanceof PyObject)) {\n"); -buf.append(" throw new IllegalArgumentException(\"provided value is not a PyObject\");\n"); -buf.append(" }\n"); -buf.append(" PyObject o = (PyObject) a;\n"); -buf.append(" if (o.isNone()) {\n"); -buf.append(" return null;\n"); -buf.append(" }\n"); -buf.append(" return o.getStringValue();\n"); -buf.append(" }\n\n"); - -buf.append(" public static boolean booleanPyCast(Object a) {\n"); -buf.append(" if (a == null) {\n"); -buf.append(" return false;\n"); -buf.append(" }\n"); -buf.append(" if (!(a instanceof PyObject)) {\n"); -buf.append(" throw new IllegalArgumentException(\"provided value is not a PyObject\");\n"); -buf.append(" }\n"); -buf.append(" return ((PyObject) a).getBooleanValue();\n"); -buf.append(" }\n\n"); - -buf.append(" public static Boolean doBooleanPyCast(Object a) {\n"); -buf.append(" if (a == null) {\n"); -buf.append(" return null;\n"); -buf.append(" }\n"); -buf.append(" if (!(a instanceof PyObject)) {\n"); -buf.append(" throw new IllegalArgumentException(\"provided value is not a PyObject\");\n"); -buf.append(" }\n"); -buf.append(" PyObject o = (PyObject) a;\n"); -buf.append(" if (o.isNone()) {\n"); -buf.append(" return null;\n"); -buf.append(" }\n"); -buf.append(" return o.getBooleanValue();\n"); -buf.append(" }\n\n"); + buf.append(" public static int intPyCast(Object a) {\n"); + buf.append(" if (a != null && !(a instanceof PyObject)) {\n"); + buf.append(" throw new IllegalArgumentException(\"provided value is not a PyObject\");\n"); + buf.append(" }\n"); + buf.append(" PyObject o = (PyObject) a;\n"); + buf.append(" if (o == null || o.isNone()) {\n"); + buf.append(" return QueryConstants.NULL_INT;\n"); + buf.append(" }\n"); + buf.append(" return o.getIntValue();\n"); + buf.append(" }\n\n"); + + buf.append(" public static double doublePyCast(Object a) {\n"); + buf.append(" if (a != null && !(a instanceof PyObject)) {\n"); + buf.append(" throw new IllegalArgumentException(\"provided value is not a PyObject\");\n"); + buf.append(" }\n"); + buf.append(" PyObject o = (PyObject) a;\n"); + buf.append(" if (o == null || o.isNone()) {\n"); + buf.append(" return QueryConstants.NULL_DOUBLE;\n"); + buf.append(" }\n"); + buf.append(" return o.getDoubleValue();\n"); + buf.append(" }\n\n"); + + buf.append(" public static long longPyCast(Object a) {\n"); + buf.append(" if (a != null && !(a instanceof PyObject)) {\n"); + buf.append(" throw new IllegalArgumentException(\"provided value is not a PyObject\");\n"); + buf.append(" }\n"); + buf.append(" PyObject o = (PyObject) a;\n"); + buf.append(" if (o == null || o.isNone()) {\n"); + buf.append(" return QueryConstants.NULL_LONG;\n"); + buf.append(" }\n"); + buf.append(" return o.getLongValue();\n"); + buf.append(" }\n\n"); + + buf.append(" public static float floatPyCast(Object a) {\n"); + buf.append(" if (a != null && !(a instanceof PyObject)) {\n"); + buf.append(" throw new IllegalArgumentException(\"provided value is not a PyObject\");\n"); + buf.append(" }\n"); + buf.append(" PyObject o = (PyObject) a;\n"); + buf.append(" if (o == null || o.isNone()) {\n"); + buf.append(" return QueryConstants.NULL_FLOAT;\n"); + buf.append(" }\n"); + buf.append(" return (float) o.getDoubleValue();\n"); + buf.append(" }\n\n"); + + buf.append(" public static char charPyCast(Object a) {\n"); + buf.append(" if (a != null && !(a instanceof PyObject)) {\n"); + buf.append(" throw new IllegalArgumentException(\"provided value is not a PyObject\");\n"); + buf.append(" }\n"); + buf.append(" PyObject o = (PyObject) a;\n"); + buf.append(" if (o == null || o.isNone()) {\n"); + buf.append(" return QueryConstants.NULL_CHAR;\n"); + buf.append(" }\n"); + buf.append(" return (char) o.getIntValue();\n"); + buf.append(" }\n\n"); + + buf.append(" public static byte bytePyCast(Object a) {\n"); + buf.append(" if (a != null && !(a instanceof PyObject)) {\n"); + buf.append(" throw new IllegalArgumentException(\"provided value is not a PyObject\");\n"); + buf.append(" }\n"); + buf.append(" PyObject o = (PyObject) a;\n"); + buf.append(" if (o == null || o.isNone()) {\n"); + buf.append(" return QueryConstants.NULL_BYTE;\n"); + buf.append(" }\n"); + buf.append(" return (byte) o.getIntValue();\n"); + buf.append(" }\n\n"); + + buf.append(" public static short shortPyCast(Object a) {\n"); + buf.append(" if (a != null && !(a instanceof PyObject)) {\n"); + buf.append(" throw new IllegalArgumentException(\"provided value is not a PyObject\");\n"); + buf.append(" }\n"); + buf.append(" PyObject o = (PyObject) a;\n"); + buf.append(" if (o == null || o.isNone()) {\n"); + buf.append(" return QueryConstants.NULL_SHORT;\n"); + buf.append(" }\n"); + buf.append(" return (short) o.getIntValue();\n"); + buf.append(" }\n\n"); + + buf.append(" public static String doStringPyCast(Object a) {\n"); + buf.append(" if (a == null) {\n"); + buf.append(" return null;\n"); + buf.append(" }\n"); + buf.append(" if (!(a instanceof PyObject)) {\n"); + buf.append(" throw new IllegalArgumentException(\"provided value is not a PyObject\");\n"); + buf.append(" }\n"); + buf.append(" PyObject o = (PyObject) a;\n"); + buf.append(" if (o.isNone()) {\n"); + buf.append(" return null;\n"); + buf.append(" }\n"); + buf.append(" return o.getStringValue();\n"); + buf.append(" }\n\n"); + + buf.append(" public static boolean booleanPyCast(Object a) {\n"); + buf.append(" if (a == null) {\n"); + buf.append(" return false;\n"); + buf.append(" }\n"); + buf.append(" if (!(a instanceof PyObject)) {\n"); + buf.append(" throw new IllegalArgumentException(\"provided value is not a PyObject\");\n"); + buf.append(" }\n"); + buf.append(" return ((PyObject) a).getBooleanValue();\n"); + buf.append(" }\n\n"); + + buf.append(" public static Boolean doBooleanPyCast(Object a) {\n"); + buf.append(" if (a == null) {\n"); + buf.append(" return null;\n"); + buf.append(" }\n"); + buf.append(" if (!(a instanceof PyObject)) {\n"); + buf.append(" throw new IllegalArgumentException(\"provided value is not a PyObject\");\n"); + buf.append(" }\n"); + buf.append(" PyObject o = (PyObject) a;\n"); + buf.append(" if (o.isNone()) {\n"); + buf.append(" return null;\n"); + buf.append(" }\n"); + buf.append(" return o.getBooleanValue();\n"); + buf.append(" }\n\n"); // ------------------------------------------------------------------------------------------------------------------------------------------------------------------ From 855e23afa47370c322e15c689450c87bfc43268e Mon Sep 17 00:00:00 2001 From: Nathaniel Bauernfeind Date: Mon, 1 Nov 2021 12:04:50 -0600 Subject: [PATCH 10/14] fix test w.r.t. latest impl --- .../db/tables/lang/TestDBLanguageParser.java | 26 ++++++++++++++----- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/DB/src/test/java/io/deephaven/db/tables/lang/TestDBLanguageParser.java b/DB/src/test/java/io/deephaven/db/tables/lang/TestDBLanguageParser.java index f33fa402f8f..8d2da3c057e 100644 --- a/DB/src/test/java/io/deephaven/db/tables/lang/TestDBLanguageParser.java +++ b/DB/src/test/java/io/deephaven/db/tables/lang/TestDBLanguageParser.java @@ -839,32 +839,44 @@ public void testPrimitiveAndBoxedToObjectCasts() throws Exception { public void testPyObjectToPrimitiveCasts() throws Exception { String expression = "(int)myPyObject"; - String resultExpression = "intPyCast((PyObject)myPyObject)"; + String resultExpression = "intPyCast(myPyObject)"; check(expression, resultExpression, int.class, new String[] {"myPyObject"}); expression = "(double)myPyObject"; - resultExpression = "doublePyCast((PyObject)myPyObject)"; + resultExpression = "doublePyCast(myPyObject)"; check(expression, resultExpression, double.class, new String[] {"myPyObject"}); expression = "(long)myPyObject"; - resultExpression = "longPyCast((PyObject)myPyObject)"; + resultExpression = "longPyCast(myPyObject)"; check(expression, resultExpression, long.class, new String[] {"myPyObject"}); expression = "(float)myPyObject"; - resultExpression = "floatPyCast((PyObject)myPyObject)"; + resultExpression = "floatPyCast(myPyObject)"; check(expression, resultExpression, float.class, new String[] {"myPyObject"}); expression = "(char)myPyObject"; - resultExpression = "charPyCast((PyObject)myPyObject)"; + resultExpression = "charPyCast(myPyObject)"; check(expression, resultExpression, char.class, new String[] {"myPyObject"}); expression = "(byte)myPyObject"; - resultExpression = "bytePyCast((PyObject)myPyObject)"; + resultExpression = "bytePyCast(myPyObject)"; check(expression, resultExpression, byte.class, new String[] {"myPyObject"}); expression = "(short)myPyObject"; - resultExpression = "shortPyCast((PyObject)myPyObject)"; + resultExpression = "shortPyCast(myPyObject)"; check(expression, resultExpression, short.class, new String[] {"myPyObject"}); + + expression = "(String)myPyObject"; + resultExpression = "doStringPyCast(myPyObject)"; + check(expression, resultExpression, String.class, new String[] {"myPyObject"}); + + expression = "(boolean)myPyObject"; + resultExpression = "booleanPyCast(myPyObject)"; + check(expression, resultExpression, boolean.class, new String[] {"myPyObject"}); + + expression = "(Boolean)myPyObject"; + resultExpression = "doBooleanPyCast(myPyObject)"; + check(expression, resultExpression, Boolean.class, new String[] {"myPyObject"}); } public void testVariables() throws Exception { From 6de58a1bf82557cec847b7df7fb8c2d826b288b6 Mon Sep 17 00:00:00 2001 From: Nathaniel Bauernfeind Date: Mon, 1 Nov 2021 16:57:04 -0600 Subject: [PATCH 11/14] feedback from ryan and chip --- .../lang/DBLanguageFunctionGenerator.java | 43 ++++++++----------- .../tables/lang/DBLanguageFunctionUtil.java | 41 ++++++++---------- .../db/tables/lang/DBLanguageParser.java | 4 +- 3 files changed, 39 insertions(+), 49 deletions(-) diff --git a/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageFunctionGenerator.java b/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageFunctionGenerator.java index 87355eadc21..1090c7281fd 100644 --- a/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageFunctionGenerator.java +++ b/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageFunctionGenerator.java @@ -4,7 +4,6 @@ package io.deephaven.db.tables.lang; -import io.deephaven.util.QueryConstants; import io.deephaven.util.type.TypeUtils; import com.github.javaparser.ast.expr.BinaryExpr; import org.jpy.PyObject; @@ -564,7 +563,7 @@ public static void main(String args[]) { // Special casts for PyObject to primitive buf.append(" public static int intPyCast(Object a) {\n"); buf.append(" if (a != null && !(a instanceof PyObject)) {\n"); - buf.append(" throw new IllegalArgumentException(\"provided value is not a PyObject\");\n"); + buf.append(" throw new IllegalArgumentException(\"Provided value is not a PyObject\");\n"); buf.append(" }\n"); buf.append(" PyObject o = (PyObject) a;\n"); buf.append(" if (o == null || o.isNone()) {\n"); @@ -575,7 +574,7 @@ public static void main(String args[]) { buf.append(" public static double doublePyCast(Object a) {\n"); buf.append(" if (a != null && !(a instanceof PyObject)) {\n"); - buf.append(" throw new IllegalArgumentException(\"provided value is not a PyObject\");\n"); + buf.append(" throw new IllegalArgumentException(\"Provided value is not a PyObject\");\n"); buf.append(" }\n"); buf.append(" PyObject o = (PyObject) a;\n"); buf.append(" if (o == null || o.isNone()) {\n"); @@ -586,7 +585,7 @@ public static void main(String args[]) { buf.append(" public static long longPyCast(Object a) {\n"); buf.append(" if (a != null && !(a instanceof PyObject)) {\n"); - buf.append(" throw new IllegalArgumentException(\"provided value is not a PyObject\");\n"); + buf.append(" throw new IllegalArgumentException(\"Provided value is not a PyObject\");\n"); buf.append(" }\n"); buf.append(" PyObject o = (PyObject) a;\n"); buf.append(" if (o == null || o.isNone()) {\n"); @@ -597,7 +596,7 @@ public static void main(String args[]) { buf.append(" public static float floatPyCast(Object a) {\n"); buf.append(" if (a != null && !(a instanceof PyObject)) {\n"); - buf.append(" throw new IllegalArgumentException(\"provided value is not a PyObject\");\n"); + buf.append(" throw new IllegalArgumentException(\"Provided value is not a PyObject\");\n"); buf.append(" }\n"); buf.append(" PyObject o = (PyObject) a;\n"); buf.append(" if (o == null || o.isNone()) {\n"); @@ -608,7 +607,7 @@ public static void main(String args[]) { buf.append(" public static char charPyCast(Object a) {\n"); buf.append(" if (a != null && !(a instanceof PyObject)) {\n"); - buf.append(" throw new IllegalArgumentException(\"provided value is not a PyObject\");\n"); + buf.append(" throw new IllegalArgumentException(\"Provided value is not a PyObject\");\n"); buf.append(" }\n"); buf.append(" PyObject o = (PyObject) a;\n"); buf.append(" if (o == null || o.isNone()) {\n"); @@ -619,7 +618,7 @@ public static void main(String args[]) { buf.append(" public static byte bytePyCast(Object a) {\n"); buf.append(" if (a != null && !(a instanceof PyObject)) {\n"); - buf.append(" throw new IllegalArgumentException(\"provided value is not a PyObject\");\n"); + buf.append(" throw new IllegalArgumentException(\"Provided value is not a PyObject\");\n"); buf.append(" }\n"); buf.append(" PyObject o = (PyObject) a;\n"); buf.append(" if (o == null || o.isNone()) {\n"); @@ -630,7 +629,7 @@ public static void main(String args[]) { buf.append(" public static short shortPyCast(Object a) {\n"); buf.append(" if (a != null && !(a instanceof PyObject)) {\n"); - buf.append(" throw new IllegalArgumentException(\"provided value is not a PyObject\");\n"); + buf.append(" throw new IllegalArgumentException(\"Provided value is not a PyObject\");\n"); buf.append(" }\n"); buf.append(" PyObject o = (PyObject) a;\n"); buf.append(" if (o == null || o.isNone()) {\n"); @@ -640,38 +639,34 @@ public static void main(String args[]) { buf.append(" }\n\n"); buf.append(" public static String doStringPyCast(Object a) {\n"); - buf.append(" if (a == null) {\n"); - buf.append(" return null;\n"); - buf.append(" }\n"); - buf.append(" if (!(a instanceof PyObject)) {\n"); - buf.append(" throw new IllegalArgumentException(\"provided value is not a PyObject\");\n"); + buf.append(" if (a != null && !(a instanceof PyObject)) {\n"); + buf.append(" throw new IllegalArgumentException(\"Provided value is not a PyObject\");\n"); buf.append(" }\n"); buf.append(" PyObject o = (PyObject) a;\n"); - buf.append(" if (o.isNone()) {\n"); + buf.append(" if (o == null || o.isNone()) {\n"); buf.append(" return null;\n"); buf.append(" }\n"); buf.append(" return o.getStringValue();\n"); buf.append(" }\n\n"); buf.append(" public static boolean booleanPyCast(Object a) {\n"); - buf.append(" if (a == null) {\n"); - buf.append(" return false;\n"); + buf.append(" if (a != null && !(a instanceof PyObject)) {\n"); + buf.append(" throw new IllegalArgumentException(\"Provided value is not a PyObject\");\n"); buf.append(" }\n"); - buf.append(" if (!(a instanceof PyObject)) {\n"); - buf.append(" throw new IllegalArgumentException(\"provided value is not a PyObject\");\n"); + buf.append(" PyObject o = (PyObject) a;\n"); + buf.append(" if (o == null || o.isNone()) {\n"); + buf.append(" throw new NullPointerException(\"Provided value is unexpectedly null;"); + buf.append(" cannot cast to boolean\");\n"); buf.append(" }\n"); buf.append(" return ((PyObject) a).getBooleanValue();\n"); buf.append(" }\n\n"); buf.append(" public static Boolean doBooleanPyCast(Object a) {\n"); - buf.append(" if (a == null) {\n"); - buf.append(" return null;\n"); - buf.append(" }\n"); - buf.append(" if (!(a instanceof PyObject)) {\n"); - buf.append(" throw new IllegalArgumentException(\"provided value is not a PyObject\");\n"); + buf.append(" if (a != null && !(a instanceof PyObject)) {\n"); + buf.append(" throw new IllegalArgumentException(\"Provided value is not a PyObject\");\n"); buf.append(" }\n"); buf.append(" PyObject o = (PyObject) a;\n"); - buf.append(" if (o.isNone()) {\n"); + buf.append(" if (o == null || o.isNone()) {\n"); buf.append(" return null;\n"); buf.append(" }\n"); buf.append(" return o.getBooleanValue();\n"); diff --git a/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageFunctionUtil.java b/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageFunctionUtil.java index b56d9bd179b..17ffae16d6d 100644 --- a/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageFunctionUtil.java +++ b/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageFunctionUtil.java @@ -19292,7 +19292,7 @@ public static short shortCast(Object a) { public static int intPyCast(Object a) { if (a != null && !(a instanceof PyObject)) { - throw new IllegalArgumentException("provided value is not a PyObject"); + throw new IllegalArgumentException("Provided value is not a PyObject"); } PyObject o = (PyObject) a; if (o == null || o.isNone()) { @@ -19303,7 +19303,7 @@ public static int intPyCast(Object a) { public static double doublePyCast(Object a) { if (a != null && !(a instanceof PyObject)) { - throw new IllegalArgumentException("provided value is not a PyObject"); + throw new IllegalArgumentException("Provided value is not a PyObject"); } PyObject o = (PyObject) a; if (o == null || o.isNone()) { @@ -19314,7 +19314,7 @@ public static double doublePyCast(Object a) { public static long longPyCast(Object a) { if (a != null && !(a instanceof PyObject)) { - throw new IllegalArgumentException("provided value is not a PyObject"); + throw new IllegalArgumentException("Provided value is not a PyObject"); } PyObject o = (PyObject) a; if (o == null || o.isNone()) { @@ -19325,7 +19325,7 @@ public static long longPyCast(Object a) { public static float floatPyCast(Object a) { if (a != null && !(a instanceof PyObject)) { - throw new IllegalArgumentException("provided value is not a PyObject"); + throw new IllegalArgumentException("Provided value is not a PyObject"); } PyObject o = (PyObject) a; if (o == null || o.isNone()) { @@ -19336,7 +19336,7 @@ public static float floatPyCast(Object a) { public static char charPyCast(Object a) { if (a != null && !(a instanceof PyObject)) { - throw new IllegalArgumentException("provided value is not a PyObject"); + throw new IllegalArgumentException("Provided value is not a PyObject"); } PyObject o = (PyObject) a; if (o == null || o.isNone()) { @@ -19347,7 +19347,7 @@ public static char charPyCast(Object a) { public static byte bytePyCast(Object a) { if (a != null && !(a instanceof PyObject)) { - throw new IllegalArgumentException("provided value is not a PyObject"); + throw new IllegalArgumentException("Provided value is not a PyObject"); } PyObject o = (PyObject) a; if (o == null || o.isNone()) { @@ -19358,7 +19358,7 @@ public static byte bytePyCast(Object a) { public static short shortPyCast(Object a) { if (a != null && !(a instanceof PyObject)) { - throw new IllegalArgumentException("provided value is not a PyObject"); + throw new IllegalArgumentException("Provided value is not a PyObject"); } PyObject o = (PyObject) a; if (o == null || o.isNone()) { @@ -19368,38 +19368,33 @@ public static short shortPyCast(Object a) { } public static String doStringPyCast(Object a) { - if (a == null) { - return null; - } - if (!(a instanceof PyObject)) { - throw new IllegalArgumentException("provided value is not a PyObject"); + if (a != null && !(a instanceof PyObject)) { + throw new IllegalArgumentException("Provided value is not a PyObject"); } PyObject o = (PyObject) a; - if (o.isNone()) { + if (o == null || o.isNone()) { return null; } return o.getStringValue(); } public static boolean booleanPyCast(Object a) { - if (a == null) { - return false; + if (a != null && !(a instanceof PyObject)) { + throw new IllegalArgumentException("Provided value is not a PyObject"); } - if (!(a instanceof PyObject)) { - throw new IllegalArgumentException("provided value is not a PyObject"); + PyObject o = (PyObject) a; + if (o == null || o.isNone()) { + throw new NullPointerException("Provided value is unexpectedly null; cannot cast to boolean"); } return ((PyObject) a).getBooleanValue(); } public static Boolean doBooleanPyCast(Object a) { - if (a == null) { - return null; - } - if (!(a instanceof PyObject)) { - throw new IllegalArgumentException("provided value is not a PyObject"); + if (a != null && !(a instanceof PyObject)) { + throw new IllegalArgumentException("Provided value is not a PyObject"); } PyObject o = (PyObject) a; - if (o.isNone()) { + if (o == null || o.isNone()) { return null; } return o.getBooleanValue(); diff --git a/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageParser.java b/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageParser.java index d9df85547f7..4004bdbdfdf 100644 --- a/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageParser.java +++ b/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageParser.java @@ -1185,7 +1185,7 @@ else if (fromBoxedType) { ((ret.equals(boolean.class) || ret.equals(Boolean.class) || ret.equals(String.class)) && exprType.equals(PyObject.class)); - if (toPrimitive && !ret.equals(boolean.class) && !ret.equals(exprType) || isPyUpgrade) { + if ((toPrimitive && !ret.equals(boolean.class) && !ret.equals(exprType)) || isPyUpgrade) { // Casting to a primitive, except booleans and the identity conversion if (!toPrimitive) { // these methods look like `doStringPyCast` and `doBooleanPyCast` @@ -1512,7 +1512,7 @@ public Class visit(FieldAccessExpr n, VisitArgs printer) { // The to-be-cast expr is a Python object field accessor final String clsName = printer.pythonCastContext.getSimpleName(); printer.append(", " + clsName + ".class"); - // Let's advertise to the caller our the casted type + // Let's advertise to the caller the cast context type ret = printer.pythonCastContext; } printer.append(')'); From 4bb2c732e895f1a97859a9b35ce4d265fa099273 Mon Sep 17 00:00:00 2001 From: Nathaniel Bauernfeind Date: Tue, 2 Nov 2021 09:57:00 -0600 Subject: [PATCH 12/14] Chip's final feedback --- .../db/tables/lang/DBLanguageFunctionGenerator.java | 10 +++++----- .../db/tables/lang/DBLanguageFunctionUtil.java | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageFunctionGenerator.java b/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageFunctionGenerator.java index 1090c7281fd..34d0eff0bc2 100644 --- a/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageFunctionGenerator.java +++ b/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageFunctionGenerator.java @@ -602,7 +602,7 @@ public static void main(String args[]) { buf.append(" if (o == null || o.isNone()) {\n"); buf.append(" return QueryConstants.NULL_FLOAT;\n"); buf.append(" }\n"); - buf.append(" return (float) o.getDoubleValue();\n"); + buf.append(" return floatCast(o.getDoubleValue());\n"); buf.append(" }\n\n"); buf.append(" public static char charPyCast(Object a) {\n"); @@ -613,7 +613,7 @@ public static void main(String args[]) { buf.append(" if (o == null || o.isNone()) {\n"); buf.append(" return QueryConstants.NULL_CHAR;\n"); buf.append(" }\n"); - buf.append(" return (char) o.getIntValue();\n"); + buf.append(" return charCast(o.getIntValue());\n"); buf.append(" }\n\n"); buf.append(" public static byte bytePyCast(Object a) {\n"); @@ -624,7 +624,7 @@ public static void main(String args[]) { buf.append(" if (o == null || o.isNone()) {\n"); buf.append(" return QueryConstants.NULL_BYTE;\n"); buf.append(" }\n"); - buf.append(" return (byte) o.getIntValue();\n"); + buf.append(" return byteCast(o.getIntValue());\n"); buf.append(" }\n\n"); buf.append(" public static short shortPyCast(Object a) {\n"); @@ -635,7 +635,7 @@ public static void main(String args[]) { buf.append(" if (o == null || o.isNone()) {\n"); buf.append(" return QueryConstants.NULL_SHORT;\n"); buf.append(" }\n"); - buf.append(" return (short) o.getIntValue();\n"); + buf.append(" return shortCast(o.getIntValue());\n"); buf.append(" }\n\n"); buf.append(" public static String doStringPyCast(Object a) {\n"); @@ -658,7 +658,7 @@ public static void main(String args[]) { buf.append(" throw new NullPointerException(\"Provided value is unexpectedly null;"); buf.append(" cannot cast to boolean\");\n"); buf.append(" }\n"); - buf.append(" return ((PyObject) a).getBooleanValue();\n"); + buf.append(" return o.getBooleanValue();\n"); buf.append(" }\n\n"); buf.append(" public static Boolean doBooleanPyCast(Object a) {\n"); diff --git a/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageFunctionUtil.java b/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageFunctionUtil.java index 17ffae16d6d..0b1516b143a 100644 --- a/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageFunctionUtil.java +++ b/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageFunctionUtil.java @@ -19331,7 +19331,7 @@ public static float floatPyCast(Object a) { if (o == null || o.isNone()) { return QueryConstants.NULL_FLOAT; } - return (float) o.getDoubleValue(); + return floatCast(o.getDoubleValue()); } public static char charPyCast(Object a) { @@ -19342,7 +19342,7 @@ public static char charPyCast(Object a) { if (o == null || o.isNone()) { return QueryConstants.NULL_CHAR; } - return (char) o.getIntValue(); + return charCast(o.getIntValue()); } public static byte bytePyCast(Object a) { @@ -19353,7 +19353,7 @@ public static byte bytePyCast(Object a) { if (o == null || o.isNone()) { return QueryConstants.NULL_BYTE; } - return (byte) o.getIntValue(); + return byteCast(o.getIntValue()); } public static short shortPyCast(Object a) { @@ -19364,7 +19364,7 @@ public static short shortPyCast(Object a) { if (o == null || o.isNone()) { return QueryConstants.NULL_SHORT; } - return (short) o.getIntValue(); + return shortCast(o.getIntValue()); } public static String doStringPyCast(Object a) { @@ -19386,7 +19386,7 @@ public static boolean booleanPyCast(Object a) { if (o == null || o.isNone()) { throw new NullPointerException("Provided value is unexpectedly null; cannot cast to boolean"); } - return ((PyObject) a).getBooleanValue(); + return o.getBooleanValue(); } public static Boolean doBooleanPyCast(Object a) { From 3c5ed54dfa488dad2166da668998536ccd9b9663 Mon Sep 17 00:00:00 2001 From: Nate Bauernfeind Date: Tue, 2 Nov 2021 16:38:11 -0500 Subject: [PATCH 13/14] Apply suggestions from code review Co-authored-by: Chip Kent <5250374+chipkent@users.noreply.github.com> --- .../db/tables/lang/DBLanguageFunctionGenerator.java | 8 ++++---- .../deephaven/db/tables/lang/DBLanguageFunctionUtil.java | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageFunctionGenerator.java b/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageFunctionGenerator.java index 34d0eff0bc2..cd5001917cb 100644 --- a/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageFunctionGenerator.java +++ b/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageFunctionGenerator.java @@ -602,7 +602,7 @@ public static void main(String args[]) { buf.append(" if (o == null || o.isNone()) {\n"); buf.append(" return QueryConstants.NULL_FLOAT;\n"); buf.append(" }\n"); - buf.append(" return floatCast(o.getDoubleValue());\n"); + buf.append(" return (float) o.getDoubleValue();\n"); buf.append(" }\n\n"); buf.append(" public static char charPyCast(Object a) {\n"); @@ -613,7 +613,7 @@ public static void main(String args[]) { buf.append(" if (o == null || o.isNone()) {\n"); buf.append(" return QueryConstants.NULL_CHAR;\n"); buf.append(" }\n"); - buf.append(" return charCast(o.getIntValue());\n"); + buf.append(" return (char) o.getIntValue();\n"); buf.append(" }\n\n"); buf.append(" public static byte bytePyCast(Object a) {\n"); @@ -624,7 +624,7 @@ public static void main(String args[]) { buf.append(" if (o == null || o.isNone()) {\n"); buf.append(" return QueryConstants.NULL_BYTE;\n"); buf.append(" }\n"); - buf.append(" return byteCast(o.getIntValue());\n"); + buf.append(" return (byte) o.getIntValue();\n"); buf.append(" }\n\n"); buf.append(" public static short shortPyCast(Object a) {\n"); @@ -635,7 +635,7 @@ public static void main(String args[]) { buf.append(" if (o == null || o.isNone()) {\n"); buf.append(" return QueryConstants.NULL_SHORT;\n"); buf.append(" }\n"); - buf.append(" return shortCast(o.getIntValue());\n"); + buf.append(" return (short) o.getIntValue();\n"); buf.append(" }\n\n"); buf.append(" public static String doStringPyCast(Object a) {\n"); diff --git a/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageFunctionUtil.java b/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageFunctionUtil.java index 0b1516b143a..cd1f59d6913 100644 --- a/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageFunctionUtil.java +++ b/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageFunctionUtil.java @@ -19331,7 +19331,7 @@ public static float floatPyCast(Object a) { if (o == null || o.isNone()) { return QueryConstants.NULL_FLOAT; } - return floatCast(o.getDoubleValue()); + return (float) o.getDoubleValue()); } public static char charPyCast(Object a) { @@ -19342,7 +19342,7 @@ public static char charPyCast(Object a) { if (o == null || o.isNone()) { return QueryConstants.NULL_CHAR; } - return charCast(o.getIntValue()); + return (char) o.getIntValue(); } public static byte bytePyCast(Object a) { @@ -19353,7 +19353,7 @@ public static byte bytePyCast(Object a) { if (o == null || o.isNone()) { return QueryConstants.NULL_BYTE; } - return byteCast(o.getIntValue()); + return (byte) o.getIntValue(); } public static short shortPyCast(Object a) { @@ -19364,7 +19364,7 @@ public static short shortPyCast(Object a) { if (o == null || o.isNone()) { return QueryConstants.NULL_SHORT; } - return shortCast(o.getIntValue()); + return (short) o.getIntValue(); } public static String doStringPyCast(Object a) { From 49a57df3b2006e704a9be7709b511afcaf925476 Mon Sep 17 00:00:00 2001 From: Nathaniel Bauernfeind Date: Tue, 2 Nov 2021 16:01:18 -0600 Subject: [PATCH 14/14] fix chips typo --- .../io/deephaven/db/tables/lang/DBLanguageFunctionUtil.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageFunctionUtil.java b/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageFunctionUtil.java index cd1f59d6913..6a01d6d64be 100644 --- a/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageFunctionUtil.java +++ b/DB/src/main/java/io/deephaven/db/tables/lang/DBLanguageFunctionUtil.java @@ -19331,7 +19331,7 @@ public static float floatPyCast(Object a) { if (o == null || o.isNone()) { return QueryConstants.NULL_FLOAT; } - return (float) o.getDoubleValue()); + return (float) o.getDoubleValue(); } public static char charPyCast(Object a) {