cxbrooks / test

Second test for bugzilla to git
0 stars 0 forks source link

Expression language has problems with String.format() #300

Open cxbrooks opened 12 years ago

cxbrooks commented 12 years ago

Note: the issue was created automatically with bugzilla2github tool

Original bug ID: BZ#502 From: @cxbrooks Reported version: 9.0.beta CC: pt-dev@chess.eecs.berkeley.edu

cxbrooks commented 12 years ago

Created attachment 43 Ptolemy model that calls String.format()

Guy Durrieu wrote: --start-- I read in the "Expressions" chapter of the doc (p. 25) that the static methods of java.lang.String are available as functions in the expression language. I would like to use the format method, which is a static one, within an expression actor, in order to produce textual messages during simulation, but I can't find how to do that (e.g. in order to output double values with a specified number of digits).

Is it possible ?

--end--

This looks like a limitation in the expression language. The executive summary is that tokens seem to be getting converted to strings. The expression language has a hard time creating an array of Objects, where elements of the array are expected to be types like java.lang.Double.

The short answer is that if you really want to use String.format(), I suggest writing an actor that does job. :-)

Here are the details:

There are two String.format() methods: static String format(Locale l, String format, Object... args) static String format(String format, Object... args)

I can use the second one in an Expression actor. The formatString.xml model that is attached has a StringConstant connected to an Expression with the value:

format("MyString: %s", {input})

The model works as expected.

Unfortunately, trying to format Integers does not work.

The attached formatInteger.xml model has format("MyString: %d", {input})

This fails with

ptolemy.kernel.util.IllegalActionException: Expression invalid. in .formatInteger.Expression Because: Error invoking function public static java.lang.String java.lang.String.format(java.lang.String,java.lang.Object[])

Because: d != ptolemy.data.IntToken

... Caused by: java.util.IllegalFormatConversionException: d != ptolemy.data.IntToken at java.util.Formatter$FormatSpecifier.failConversion(Formatter.java:3999) at java.util.Formatter$FormatSpecifier.printInteger(Formatter.java:2709) at java.util.Formatter$FormatSpecifier.print(Formatter.java:2661) at java.util.Formatter.format(Formatter.java:2433) at java.util.Formatter.format(Formatter.java:2367) at java.lang.String.format(String.java:2769) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at ptolemy.data.expr.CachedMethod.invoke(CachedMethod.java:569) at ptolemy.data.expr.ParseTreeEvaluator._functionCall(ParseTreeEvaluator.java:1425) at ptolemy.data.expr.ParseTreeEvaluator.visitFunctionApplicationNode(ParseTreeEvaluator.java:553) at ptolemy.data.expr.ASTPtFunctionApplicationNode.visit(ASTPtFunctionApplicationNode.java:96) at ptolemy.data.expr.ParseTreeEvaluator.evaluateParseTree(ParseTreeEvaluator.java:105) at ptolemy.actor.lib.Expression.fire(Expression.java:233) at ptolemy.actor.AtomicActor.iterate(AtomicActor.java:461) at ptolemy.actor.sched.StaticSchedulingDirector.fire(StaticSchedulingDirector.java:192) at ptolemy.actor.CompositeActor.fire(CompositeActor.java:458) at ptolemy.actor.Manager.iterate(Manager.java:747) at ptolemy.actor.Manager.execute(Manager.java:351) at ptolemy.actor.Manager.run(Manager.java:1159) at ptolemy.actor.Manager$PtolemyRunThread.run(Manager.java:1689)

What's happening here is that the String format() method is saying that %d is not a ptolemy.data.IntToken. format is expecting a java.lang.Integer, not a ptolemy.data.IntToken.

I tried various manipulations to create java.lang.Integer.

1) Use format("MyString: %d", {valueOf(input.intValue())})

The idea here is that the java.lang.Integer.valueOf(int) method will be called which will create a java.lang.Integer

Unfortunately, I get a stack trace:

ptolemy.kernel.util.IllegalActionException: Expression invalid. in .formatInteger.Expression Because: type not found: char at ptolemy.actor.lib.Expression.fire(Expression.java:238) at ptolemy.actor.AtomicActor.iterate(AtomicActor.java:461) at ptolemy.actor.sched.StaticSchedulingDirector.fire(StaticSchedulingDirector.java:192) at ptolemy.actor.CompositeActor.fire(CompositeActor.java:458) at ptolemy.actor.Manager.iterate(Manager.java:747) at ptolemy.actor.Manager.execute(Manager.java:351) at ptolemy.actor.Manager.run(Manager.java:1159) at ptolemy.actor.Manager$PtolemyRunThread.run(Manager.java:1689) Caused by: ptolemy.kernel.util.InternalErrorException: type not found: char at ptolemy.data.expr.ConversionUtilities.convertJavaTypeToTokenType(ConversionUtilities.java:337) at ptolemy.data.expr.CachedMethod._getConversion(CachedMethod.java:813) at ptolemy.data.expr.CachedMethod._polymorphicGetMethod(CachedMethod.java:902) at ptolemy.data.expr.CachedMethod._findFUNCTION(CachedMethod.java:977) at ptolemy.data.expr.CachedMethod.findMethod(CachedMethod.java:336) at ptolemy.data.expr.ParseTreeEvaluator._functionCall(ParseTreeEvaluator.java:1416) at ptolemy.data.expr.ParseTreeEvaluator.visitFunctionApplicationNode(ParseTreeEvaluator.java:553) at ptolemy.data.expr.ASTPtFunctionApplicationNode.visit(ASTPtFunctionApplicationNode.java:96) at ptolemy.data.expr.ParseTreeEvaluator._evaluateChild(ParseTreeEvaluator.java:1360) at ptolemy.data.expr.ParseTreeEvaluator._evaluateAllChildren(ParseTreeEvaluator.java:1314) at ptolemy.data.expr.ParseTreeEvaluator.visitArrayConstructNode(ParseTreeEvaluator.java:158) at ptolemy.data.expr.ASTPtArrayConstructNode.visit(ASTPtArrayConstructNode.java:64) at ptolemy.data.expr.ParseTreeEvaluator._evaluateChild(ParseTreeEvaluator.java:1360) at ptolemy.data.expr.ParseTreeEvaluator.visitFunctionApplicationNode(ParseTreeEvaluator.java:309) at ptolemy.data.expr.ASTPtFunctionApplicationNode.visit(ASTPtFunctionApplicationNode.java:96) at ptolemy.data.expr.ParseTreeEvaluator.evaluateParseTree(ParseTreeEvaluator.java:105) at ptolemy.actor.lib.Expression.fire(Expression.java:233) ... 7 more Caused by: ptolemy.kernel.util.InternalErrorException: type not found: char at ptolemy.data.expr.ConversionUtilities.convertJavaTypeToTokenType(ConversionUtilities.java:337) at ptolemy.data.expr.CachedMethod._getConversion(CachedMethod.java:813) at ptolemy.data.expr.CachedMethod._polymorphicGetMethod(CachedMethod.java:902) at ptolemy.data.expr.CachedMethod._findFUNCTION(CachedMethod.java:977) at ptolemy.data.expr.CachedMethod.findMethod(CachedMethod.java:336) at ptolemy.data.expr.ParseTreeEvaluator._functionCall(ParseTreeEvaluator.java:1416) at ptolemy.data.expr.ParseTreeEvaluator.visitFunctionApplicationNode(ParseTreeEvaluator.java:553) at ptolemy.data.expr.ASTPtFunctionApplicationNode.visit(ASTPtFunctionApplicationNode.java:96) at ptolemy.data.expr.ParseTreeEvaluator._evaluateChild(ParseTreeEvaluator.java:1360) at ptolemy.data.expr.ParseTreeEvaluator._evaluateAllChildren(ParseTreeEvaluator.java:1314) at ptolemy.data.expr.ParseTreeEvaluator.visitArrayConstructNode(ParseTreeEvaluator.java:158) at ptolemy.data.expr.ASTPtArrayConstructNode.visit(ASTPtArrayConstructNode.java:64) at ptolemy.data.expr.ParseTreeEvaluator._evaluateChild(ParseTreeEvaluator.java:1360) at ptolemy.data.expr.ParseTreeEvaluator.visitFunctionApplicationNode(ParseTreeEvaluator.java:309) at ptolemy.data.expr.ASTPtFunctionApplicationNode.visit(ASTPtFunctionApplicationNode.java:96) at ptolemy.data.expr.ParseTreeEvaluator.evaluateParseTree(ParseTreeEvaluator.java:105) at ptolemy.actor.lib.Expression.fire(Expression.java:233) at ptolemy.actor.AtomicActor.iterate(AtomicActor.java:461) at ptolemy.actor.sched.StaticSchedulingDirector.fire(StaticSchedulingDirector.java:192) at ptolemy.actor.CompositeActor.fire(CompositeActor.java:458) at ptolemy.actor.Manager.iterate(Manager.java:747) at ptolemy.actor.Manager.execute(Manager.java:351) at ptolemy.actor.Manager.run(Manager.java:1159) at ptolemy.actor.Manager$PtolemyRunThread.run(Manager.java:1689)

The offending code is in ptolemy.data.expr.ConversionUtilities:

/** Convert a java class, representing a Java type, to a

  • corresponding instance of a ptolemy type object, as consistent
  • with the convertJavaTypeToToken method.
  • @ exception IllegalActionException If the token class is not
  • recognized, or creating the type fails.
    */ public static Type convertJavaTypeToTokenType(Class tokenClass) throws ptolemy.kernel.util.IllegalActionException { try { if (tokenClass.equals(ptolemy.data.Token.class)) { return BaseType.GENERAL; } ... } else { // This should really never happen, since every class
    // should be caught by the isAssignable test above,
    // but I don't like the dangling else if.
    throw new InternalErrorException("type not found: "
    • tokenClass); }

It appears that this method is getting a char passed to it and because we don't have a char type, it fails.

I tried modifying the caller so that it catches the InternalErrorException, ignores it and moves on, but that does not help. The caller is in data.expr.CachedMethod:

try { // We have to do this because Java is stupid and doesn't
// give us a way to tell if primitive arguments are
// acceptable
if (formal.isPrimitive() || formal.isArray()) { try { Type type = ConversionUtilities .convertJavaTypeToTokenType(formal);

                if (ptolemy.graph.CPO.LOWER == TypeLattice
                        .compare(actual, type)) {
                    return new TypeArgumentConversion(type, NATIVE_CONVERSION);
                }
            } catch (InternalErrorException ex) {
                // if formal is a char, then convertJavaTypeToTokenType(formal)
                // will throw an InternalErrorException
                // Ignore.                                                                          
            }
        }
    } catch (IllegalActionException ex) {
        // Ignore..                                                                                 
        //          ex.printStackTrace();                                                           
    }

With the above change, and the expression: format("MyString: %d", {valueOf(input.intValue())})

formatInteger.xml fails with:

ptolemy.kernel.util.IllegalActionException: Expression invalid. in .formatInteger.Expression Because: Error invoking function public static java.lang.String java.lang.String.format(java.lang.String,java.lang.Object[])

Because: d != ptolemy.data.StringToken

So here, the problem is that the Ptolemy IntToken is getting converted to a StringToken.

It looks like this method is being selected: public static java.lang.String java.lang.String.valueOf(java.lang.Object) instead of public static java.lang.Integer java.lang.Integer.valueOf(int)

I started looking in to why this occurs, but have run out of time for now.

I tried using the "cast" expression language function, but that did not help.

I'll see if I can take a further look into the expression language issues, it would be nice if this worked.

_Christopher

Attached file: format.xml (text/xml, 4115 bytes) Description: Ptolemy model that calls String.format()