All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.oracle.truffle.tck.TruffleTCK Maven / Gradle / Ivy

Go to download

A collection of tests that can certify language implementation to be compliant with most recent requirements of the Truffle infrastructure and tooling.

There is a newer version: 1.0.0-rc7
Show newest version
/*
 * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */
package com.oracle.truffle.tck;

import com.oracle.truffle.tck.impl.LongBinaryOperation;
import com.oracle.truffle.tck.impl.ObjectBinaryOperation;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.Random;

import org.junit.Assert;
import org.junit.Test;

import com.oracle.truffle.api.TruffleLanguage;
import com.oracle.truffle.api.interop.ForeignAccess.Factory10;
import com.oracle.truffle.api.interop.Message;
import com.oracle.truffle.api.interop.TruffleObject;
import com.oracle.truffle.api.interop.java.JavaInterop;
import com.oracle.truffle.api.interop.java.MethodMessage;
import com.oracle.truffle.api.nodes.RootNode;
import com.oracle.truffle.api.source.Source;
import com.oracle.truffle.api.vm.PolyglotEngine;
import com.oracle.truffle.api.vm.PolyglotEngine.Language;
import com.oracle.truffle.api.vm.PolyglotEngine.Builder;
import com.oracle.truffle.tck.Schema.Type;
import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
import java.util.concurrent.Executors;
import org.junit.AfterClass;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

/**
 * Test compatibility kit (the TCK) is a collection of tests to certify your
 * {@link TruffleLanguage language implementation} compliance. If you want your language to be
 * compliant with most recent requirements of the Truffle infrastructure and tooling, subclass,
 * implement protected methods and include in your test suite:
 *
 * 
 * public class MyLanguageTCKTest extends {@link TruffleTCK} {
 *   {@link Override @Override}
 *   protected {@link PolyglotEngine} {@link #prepareVM() prepareVM}() {
 *     // create the engine
 *     // execute necessary scripts
 *   }
 * 
 *   {@link Override @Override}
 *   protected {@link String} fourtyTwo() {
 *     return // name of function that returns 42
 *   }
 * 
 *   // and so on...
 * }
 * 
* * The TCK is carefully designed to accommodate differences between languages. The * TCK doesn't dictate what object your language is using to represent {@link Number * numbers} or {@link String strings} internally. The TCK doesn't prescribe the precise * type of values returned from your * {@link PolyglotEngine#eval(com.oracle.truffle.api.source.Source) language evaluations}. The tests * just assume that if the result is supposed to be a number, the returned value will be an instance * of {@link Number} or be {@link Message#UNBOX convertible} to a {@link Number} and keeps * sufficient level of precision. Similarly for {@link String strings}. As such the tests in the * TCK should be applicable to wide range of languages. Should there be a test that cannot * be implemented in your language, it can be suppressed by overriding its test method and doing * nothing: * *
 *   {@link Override @Override}
 *   public void {@link #testFortyTwo() testFortyTwo}() {
 *     // do nothing
 *   }
 * 
*

* The primary goal of the TCK is to ensure your {@link TruffleLanguage language * implementation} plays well with other languages in the {@link PolyglotEngine} - e.g. that data * can be exchanged between your and other languages. The {@link com.oracle.truffle.api.interop * interop package} defines what types of data can be interchanged between the languages and the * TCK does its best to make sure all these data are really accepted as an input on a * boundary of your {@link TruffleLanguage language implementation}. That doesn't mean such data * need to be used internally, many languages do conversions in their {@link Factory10 foreign * access} {@link RootNode nodes} to more suitable internal representation. Such conversion is fully * acceptable as nobody prescribes what is the actual type of output after executing a function/code * snippet in your language. *

* Should the TCK be found unsuitable for your {@link TruffleLanguage language * implementation} please speak-up (at Truffle/Graal mailing list for example) and we do * our best to analyze your case and adjust the TCK to suite everyone's needs. * * @since 0.8 or earlier */ public abstract class TruffleTCK { private static final Random RANDOM = new Random(); private static Reference previousVMReference = new WeakReference<>(null); private PolyglotEngine tckVM; /** @since 0.8 or earlier */ protected TruffleTCK() { } /** * Disposes {@link PolyglotEngine} used during the test execution. * * @since 0.12 */ @AfterClass public static final void disposePreviousVM() { replacePreviousVM(null); } private static void replacePreviousVM(PolyglotEngine newVM) { PolyglotEngine vm = previousVMReference.get(); if (vm == newVM) { return; } if (vm != null) { vm.dispose(); } previousVMReference = new WeakReference<>(newVM); } /** * This methods is called before each test is executed. It's purpose is to set a * {@link PolyglotEngine} with your language up, so it is ready for testing. * {@link PolyglotEngine#eval(com.oracle.truffle.api.source.Source) Execute} any scripts you * need, and prepare global symbols with proper names. The symbols will then be looked up by the * infrastructure (using the names provided by you from methods like {@link #plusInt()}) and * used for internal testing. * * @return initialized Truffle virtual machine * @throws java.lang.Exception thrown when the VM preparation fails * @since 0.8 or earlier */ protected PolyglotEngine prepareVM() throws Exception { return prepareVM(PolyglotEngine.newBuilder()); } /** * Configure your language inside of provided builder. The method should do the same operations * like {@link #prepareVM()}, but rather than doing them from scratch, it is supposed to do the * changes in provided builder. The builder may be pre-configured by the TCK - for example * {@link Builder#executor(java.util.concurrent.Executor)} may be provided or * {@link Builder#globalSymbol(java.lang.String, java.lang.Object) global symbols} specified, * etc. * * @param preparedBuilder the builder to use to construct the engine * @return initialized Truffle virtual machine * @throws java.lang.Exception thrown when the VM preparation fails * @since 0.12 */ protected PolyglotEngine prepareVM(PolyglotEngine.Builder preparedBuilder) throws Exception { throw new UnsupportedOperationException(); } /** * MIME type associated with your language. The MIME type will be passed to * {@link PolyglotEngine#eval(com.oracle.truffle.api.source.Source)} method of the * {@link #prepareVM() created engine}. * * @return mime type of the tested language * @since 0.8 or earlier */ protected abstract String mimeType(); /** * Name of function which will return value 42 as a number. The return value of the method * should be instance of {@link Number} and its {@link Number#intValue()} should return * 42. * * @return name of globally exported symbol * @since 0.8 or earlier */ protected abstract String fourtyTwo(); /** * Name of a function that returns null. Truffle languages are encouraged to have * their own type representing null, but when such value is returned from * {@link PolyglotEngine#eval}, it needs to be converted to real Java null by * sending a foreign access isNull message. There is a test to verify it is really * true. * * @return name of globally exported symbol * @since 0.8 or earlier */ protected abstract String returnsNull(); /** * Name of function to add two integer values together. The symbol will be invoked with two * parameters of type {@link Integer} and expects result of type {@link Number} which's * {@link Number#intValue()} is equivalent of param1 + param2. * * @return name of globally exported symbol * @since 0.8 or earlier */ protected String plusInt() { throw new UnsupportedOperationException("Override plus(Class,Class) method!"); } /** * Name of function to add two numbers together. The symbol will be invoked with two parameters * of type1 and type2 and expects result of type {@link Number} * which's {@link Number#intValue()} is equivalent of param1 + param2. As some * languages may have different operations for different types of numbers, the actual types are * passed to the method and the implementation can decide to return different symbol based on * the parameters. * * @param type1 one of byte, short, int, long, float, double class * @param type2 one of byte, short, int, long, float, double class * @return name of globally exported symbol * @since 0.8 or earlier */ protected String plus(Class type1, Class type2) { return plusInt(); } /** * Name of a function in your language to perform a callback to foreign function. Your function * should prepare two numbers (18 and 32) and apply them to the function passed in as an * argument of your function. It should then add 10 to the returned value and return the result * back to its caller. * * @return name of globally exported symbol * @since 0.8 or earlier */ protected abstract String applyNumbers(); /** * Name of identity function. The identity function accepts one argument and returns it. The * argument should go through without any modification, e.g. the input should result in * identical output. * * @return name of globally exported symbol * @since 0.8 or earlier */ protected String identity() { throw new UnsupportedOperationException("identity() method not implemented"); } /** * Name of a function that adds up two complex numbers. The function accepts two arguments and * provides no return value. The arguments are complex numbers with members called real and * imaginary. The first argument contains the result of the addition. * * @return name of globally exported symbol * @since 0.8 or earlier */ protected String complexAdd() { throw new UnsupportedOperationException("complexAdd() method not implemented"); } /** * Name of a function that adds up two complex numbers using an add method of the first complex * number. The function accepts two arguments and provides no return value. The arguments are * complex numbers with members called real and imaginary. The first argument contains the * result of the addition. * * @return name of globally exported symbol * @since 0.8 or earlier */ protected String complexAddWithMethod() { throw new UnsupportedOperationException("complexAddWithMethod() method not implemented"); } /** * Name of a function that adds up the real part of complex numbers. The function accepts one * argument and provides the sum of all real parts. The argument is an array/buffer of complex * numbers. * * @return name of globally exported symbol, null if the test should be skipped * @since 0.8 or earlier */ protected String complexSumReal() { throw new UnsupportedOperationException("complexSumReal() method not implemented"); } /** * Name of a function that copies a list of complex numbers. The function accepts two arguments * and provides no return value. The arguments are two lists of complex numbers with members * called real and imaginary. The first argument is the destination, the second argument is the * source. * * @return name of globally exported symbol, null if the test should be skipped * @since 0.8 or earlier */ protected String complexCopy() { throw new UnsupportedOperationException("complexCopy() method not implemented"); } /** * Name of a function to return global object. The function can be executed without providing * any arguments and should return global object of the language, if the language supports it. * Global object is the one accessible via * {@link TruffleLanguage#getLanguageGlobal(java.lang.Object)}. * * @return name of globally exported symbol, return null if the language doesn't * support the concept of global object * @since 0.8 or earlier */ protected String globalObject() { throw new UnsupportedOperationException("globalObject() method not implemented"); } /** * Name of a function to parse source written in some other language. When the function is * executed, it expects two arguments. First one is MIME type identifying * {@link TruffleLanguage} and the second one is the source code to parse in that language and * execute it. The result of the execution is then returned back to the caller. * * @return name of globally exported symbol to invoke when one wants to execute some code * @since 0.8 or earlier */ protected String evaluateSource() { throw new UnsupportedOperationException("evaluateSource() method not implemented"); } /** * Code snippet to multiply two variables. The test uses the snippet as a parameter to your * language' s * {@link TruffleLanguage#parse(com.oracle.truffle.api.source.Source, com.oracle.truffle.api.nodes.Node, java.lang.String...)} * method. * * @param firstName name of the first variable to multiplyCode * @param secondName name of the second variable to multiplyCode * @return code snippet that multiplies the two variables in your language * @since 0.8 or earlier */ protected String multiplyCode(String firstName, String secondName) { throw new UnsupportedOperationException("multiply(String,String) method not implemeted!"); } /** * Name of a function to manipulate with an array. The function should take three parameters: * the array, index into the array (expected to be an instance of {@link Number}) and another * number to add to value already present at the index-location in the array. The first element * in the array has index zero. * * @since 0.14 */ protected String addToArray() { throw new UnsupportedOperationException("implement addToArray() method"); } /** * Name of a function that counts number of its invocations in current {@link PolyglotEngine} * context. Your function should somehow keep a counter to remember number of its invocations * and always increment it. The first invocation should return 1, the second * 2 and so on. The returned values are expected to be instances of {@link Number}. *

* The function will be used to test that two instances of your language can co-exist next to * each other. Without being mutually influenced. * * @return name of globally expected symbol * @since 0.8 or earlier */ protected abstract String countInvocations(); /** * Return a code snippet that is invalid in your language. Its * {@link PolyglotEngine#eval(com.oracle.truffle.api.source.Source) evaluation} should fail and * yield an exception. * * @return code snippet invalid in the tested language * @since 0.8 or earlier */ protected abstract String invalidCode(); /** * Name of a function that returns a compound object with members representing certain * operations. In the JavaScript the object should look like: * *

     * var obj = {
     *   'fourtyTwo': function {@link #fourtyTwo()},
     *   'plus': function {@link #plusInt()},
     *   'returnsNull': function {@link #returnsNull()},
     *   'returnsThis': function() { return obj; }
     * };
     * return obj;
     * 
* * The returned object shall have three functions that will be obtained and used exactly as * described in their Javadoc - e.g. {@link #fourtyTwo()}, {@link #plusInt()} and * {@link #returnsNull()}. In addition to that there should be one more function * returnsThis that will return the object itself again. * * @return name of a function that returns such compound object * @since 0.8 or earlier */ protected String compoundObject() { throw new UnsupportedOperationException("compoundObject() method not implemented"); } /** * Name of a function that returns a compound object with members representing certain primitive * types. In the JavaScript the object should look like: * *
     * var obj = {
     *   'byteValue': 0,
     *   'shortValue': 0,
     *   'intValue': 0,
     *   'longValue': 0,
     *   'floatValue': 0.0,
     *   'doubleValue': 0.0,
     *   'charValue': '0',
     *   'stringValue': '',
     *   'booleanVlaue': false
     * };
     * return obj;
     * 
* * The returned object shall have slots for these values that can be read and written to. * Various test methods try to read and modify the values. Each invocation of the function * should yield new object. * * @return name of a function that returns such values object * @since 0.8 or earlier */ protected String valuesObject() { throw new UnsupportedOperationException("valuesObject() method not implemented"); } /** * Assert two double values are the same. Various languages may have different semantics with * respect to double numbers. Some of the language may not support double or float * values at all. Those languages may override this method and compare the values with as much * precision as they like. *

* Default implementation of this method calls * {@link Assert#assertEquals(java.lang.String, double, double, double)} with delta * 0.1. * * @param msg assertion message to display in case of error * @param expectedValue the value expected by the test * @param actualValue the real value produced by the language * @throws AssertionError if the values are different according to the language semantics * @since 0.8 or earlier */ protected void assertDouble(String msg, double expectedValue, double actualValue) { assertEquals(msg, expectedValue, actualValue, 0.1); } private PolyglotEngine vm() throws Exception { if (tckVM == null) { tckVM = prepareVM(); replacePreviousVM(tckVM); } return tckVM; } // // The tests // /** @since 0.8 or earlier */ @Test public void testFortyTwo() throws Exception { PolyglotEngine.Value fourtyTwo = findGlobalSymbol(fourtyTwo()); Object res = fourtyTwo.execute().get(); assert res instanceof Number : "should yield a number, but was: " + res; Number n = (Number) res; assert 42 == n.intValue() : "The value is 42 = " + n.intValue(); } /** @since 0.8 or earlier */ @Test public void testFortyTwoWithCompoundObject() throws Exception { CompoundObject obj = findCompoundSymbol(); if (obj == null) { return; } Number res = obj.fourtyTwo(); assertEquals("Should be 42", 42, res.intValue()); } /** @since 0.8 or earlier */ @Test public void testNull() throws Exception { PolyglotEngine.Value retNull = findGlobalSymbol(returnsNull()); Object res = retNull.execute().get(); assertNull("Should yield real Java null", res); } /** @since 0.8 or earlier */ @Test public void testNullCanBeCastToAnything() throws Exception { PolyglotEngine.Value retNull = findGlobalSymbol(returnsNull()); Object res = retNull.execute().as(CompoundObject.class); assertNull("Should yield real Java null", res); } /** @since 0.8 or earlier */ @Test public void testNullInCompoundObject() throws Exception { CompoundObject obj = findCompoundSymbol(); if (obj == null) { return; } Object res = obj.returnsNull(); assertNull("Should yield real Java null", res); } /** @since 0.8 or earlier */ @Test public void testPlusWithInts() throws Exception { int a = RANDOM.nextInt(100); int b = RANDOM.nextInt(100); doPlusWithInts(a, b); } /** @since 0.8 or earlier */ @Test public void testPlusWithOneNegativeInt() throws Exception { int a = -RANDOM.nextInt(100); int b = RANDOM.nextInt(100); doPlusWithInts(a, b); } private void doPlusWithInts(int a, int b) throws Exception { PolyglotEngine.Value plus = findGlobalSymbol(plus(int.class, int.class)); Number n = plus.execute(a, b).as(Number.class); assert a + b == n.intValue() : "(" + a + " + " + b + ") = " + n.intValue(); } /** @since 0.8 or earlier */ @Test public void testPlusWithBytes() throws Exception { int a = RANDOM.nextInt(50); int b = RANDOM.nextInt(50); doPlusWithBytes(a, b); } /** @since 0.8 or earlier */ @Test public void testPlusWithOneNegativeByte() throws Exception { int a = -RANDOM.nextInt(50); int b = RANDOM.nextInt(50); doPlusWithBytes(a, b); } private void doPlusWithBytes(int a, int b) throws Exception { PolyglotEngine.Value plus = findGlobalSymbol(plus(byte.class, byte.class)); Number n = plus.execute((byte) a, (byte) b).as(Number.class); assert a + b == n.intValue() : "(" + a + " + " + b + ") = " + n.intValue(); } /** @since 0.8 or earlier */ @Test public void testPlusWithShort() throws Exception { int a = RANDOM.nextInt(100); int b = RANDOM.nextInt(100); doPlusWithShorts(a, b); } /** @since 0.8 or earlier */ @Test public void testPlusWithOneNegativeShort() throws Exception { int a = RANDOM.nextInt(100); int b = -RANDOM.nextInt(100); doPlusWithShorts(a, b); } private void doPlusWithShorts(int a, int b) throws Exception { PolyglotEngine.Value plus = findGlobalSymbol(plus(short.class, short.class)); Number n = plus.execute((short) a, (short) b).as(Number.class); assert a + b == n.intValue() : "(" + a + " + " + b + ") = " + n.intValue(); } /** @since 0.8 or earlier */ @Test public void testPlusWithLong() throws Exception { long a = RANDOM.nextInt(100); long b = RANDOM.nextInt(100); doPlusWithLong(a, b); } /** @since 0.8 or earlier */ @Test public void testPlusWithLongMaxIntMinInt() throws Exception { doPlusWithLong(Integer.MAX_VALUE, Integer.MIN_VALUE); } private void doPlusWithLong(long a, long b) throws Exception { PolyglotEngine.Value plus = findGlobalSymbol(plus(long.class, long.class)); Number n = plus.execute(a, b).as(Number.class); assert a + b == n.longValue() : "(" + a + " + " + b + ") = " + n.longValue(); } /** @since 0.8 or earlier */ @Test public void testPlusWithDoubleFloatSameAsInt() throws Exception { int x = RANDOM.nextInt(100); int y = RANDOM.nextInt(100); float a = x; float b = y; double u = a; double v = b; PolyglotEngine.Value floatPlus = findGlobalSymbol(plus(float.class, float.class)); PolyglotEngine.Value doublePlus = findGlobalSymbol(plus(double.class, double.class)); PolyglotEngine.Value intPlus = findGlobalSymbol(plus(int.class, int.class)); Number floatResult = floatPlus.execute(a, b).as(Number.class); Number doubleResult = doublePlus.execute(u, v).as(Number.class); Number intResult = intPlus.execute(x, y).as(Number.class); assertEquals("Correct value computed via int: (" + a + " + " + b + ")", x + y, intResult.intValue()); assertEquals("Correct value computed via float: (" + a + " + " + b + ")", intResult.intValue(), floatResult.intValue()); assertEquals("Correct value computed via double: (" + a + " + " + b + ")", intResult.intValue(), doubleResult.intValue()); } /** @since 0.8 or earlier */ @Test public void testPlusWithFloat() throws Exception { float a = RANDOM.nextFloat() * 100.0f; float b = RANDOM.nextFloat() * 100.0f; doPlusWithFloat(a, b); } private void doPlusWithFloat(float a, float b) throws Exception { PolyglotEngine.Value plus = findGlobalSymbol(plus(float.class, float.class)); Number n = plus.execute(a, b).as(Number.class); assertDouble("Correct value computed: (" + a + " + " + b + ")", a + b, n.floatValue()); } /** @since 0.8 or earlier */ @Test public void testPlusWithDouble() throws Exception { double a = RANDOM.nextDouble() * 100.0; double b = RANDOM.nextDouble() * 100.0; doPlusWithDouble(a, b); } /** @since 0.8 or earlier */ @Test public void testPlusWithDoubleRound() throws Exception { double a = RANDOM.nextInt(1000); double b = RANDOM.nextInt(1000); doPlusWithDouble(a, b); } /** @since 0.8 or earlier */ @Test public void testPlusWithDoubleMaxInt() throws Exception { double a = Integer.MAX_VALUE; double b = 1; doPlusWithDouble(a, b); } /** @since 0.8 or earlier */ @Test public void testPlusWithDoubleMaxMinInt() throws Exception { double a = Integer.MAX_VALUE; double b = Integer.MIN_VALUE; doPlusWithDouble(a, b); } /** @since 0.8 or earlier */ @Test public void testPlusWithDoubleMinIntMinusOne() throws Exception { double a = -1; double b = Integer.MIN_VALUE; doPlusWithDouble(a, b); } /** @since 0.8 or earlier */ @Test public void testPlusWithDoubleMaxIntPlusOne() throws Exception { double a = 1; double b = Integer.MAX_VALUE; doPlusWithDouble(a, b); } /** @since 0.8 or earlier */ @Test public void testPlusWithDoubleNaNPlusNegInf() throws Exception { double a = Double.NaN; double b = Double.NEGATIVE_INFINITY; doPlusWithDouble(a, b); } /** @since 0.8 or earlier */ @Test public void testPlusWithDoubleNaNPlusPosInf() throws Exception { double a = Double.NaN; double b = Double.POSITIVE_INFINITY; doPlusWithDouble(a, b); } /** @since 0.8 or earlier */ @Test public void testPlusWithDoubleMaxIntPlusPosInf() throws Exception { double a = Integer.MAX_VALUE; double b = Double.POSITIVE_INFINITY; doPlusWithDouble(a, b); } /** @since 0.8 or earlier */ @Test public void testPlusWithDoubleMaxIntPlusNegInf() throws Exception { double a = Integer.MAX_VALUE; double b = Double.NEGATIVE_INFINITY; doPlusWithDouble(a, b); } private void doPlusWithDouble(double a, double b) throws Exception { PolyglotEngine.Value plus = findGlobalSymbol(plus(double.class, double.class)); Number n = plus.execute(a, b).as(Number.class); assertDouble("Correct value computed: (" + a + " + " + b + ")", a + b, n.doubleValue()); } /** @since 0.8 or earlier */ @Test public void testPlusWithIntsOnCompoundObject() throws Exception { int a = RANDOM.nextInt(100); int b = RANDOM.nextInt(100); CompoundObject obj = findCompoundSymbol(); if (obj == null) { return; } Number n = obj.plus(a, b); assert a + b == n.intValue() : "(" + a + " + " + b + ") = " + n.intValue(); } /** @since 0.8 or earlier */ @Test(expected = IOException.class) public void testInvalidTestMethod() throws Exception { String mime = mimeType(); String code = invalidCode(); Object ret = vm().eval(Source.fromText(code, "Invalid code").withMimeType(mime)).get(); fail("Should yield IOException, but returned " + ret); } /** @since 0.8 or earlier */ @Test public void testMaxOrMinValue() throws Exception { PolyglotEngine.Value apply = findGlobalSymbol(applyNumbers()); TruffleObject fn = JavaInterop.asTruffleFunction(LongBinaryOperation.class, new MaxMinObject(true)); Object res = apply.execute(fn).get(); assert res instanceof Number : "result should be a number: " + res; Number n = (Number) res; assert 42 == n.intValue() : "32 > 18 and plus 10"; } /** @since 0.8 or earlier */ @Test public void testMaxOrMinValue2() throws Exception { PolyglotEngine.Value apply = findGlobalSymbol(applyNumbers()); TruffleObject fn = JavaInterop.asTruffleFunction(LongBinaryOperation.class, new MaxMinObject(false)); final PolyglotEngine.Value result = apply.execute(fn); try { Boolean res = result.as(Boolean.class); fail("Cannot be converted to Boolean: " + res); } catch (ClassCastException ex) { // correct } Number n = result.as(Number.class); assert 28 == n.intValue() : "18 < 32 and plus 10"; } /** @since 0.8 or earlier */ @Test public void testPrimitiveReturnTypeByte() throws Exception { PolyglotEngine.Value apply = findGlobalSymbol(applyNumbers()); byte value = (byte) RANDOM.nextInt(100); TruffleObject fn = JavaInterop.asTruffleFunction(ObjectBinaryOperation.class, new ConstantFunction(value)); Number n = apply.execute(fn).as(Number.class); assertEquals("The same value returned (" + value + " + 10): ", value + 10, n.byteValue()); } /** @since 0.8 or earlier */ @Test public void testPrimitiveReturnTypeShort() throws Exception { PolyglotEngine.Value apply = findGlobalSymbol(applyNumbers()); short value = (short) RANDOM.nextInt(100); TruffleObject fn = JavaInterop.asTruffleFunction(ObjectBinaryOperation.class, new ConstantFunction(value)); Number n = apply.execute(fn).as(Number.class); assertEquals("The same value returned (" + value + " + 10): ", value + 10, n.shortValue()); } /** @since 0.8 or earlier */ @Test public void testPrimitiveReturnTypeInt() throws Exception { PolyglotEngine.Value apply = findGlobalSymbol(applyNumbers()); int value = RANDOM.nextInt(100); TruffleObject fn = JavaInterop.asTruffleFunction(ObjectBinaryOperation.class, new ConstantFunction(value)); Number n = apply.execute(fn).as(Number.class); assertEquals("The same value returned (" + value + " + 10): ", value + 10, n.intValue()); } /** @since 0.8 or earlier */ @Test public void testPrimitiveReturnTypeLong() throws Exception { PolyglotEngine.Value apply = findGlobalSymbol(applyNumbers()); long value = RANDOM.nextInt(1000); TruffleObject fn = JavaInterop.asTruffleFunction(ObjectBinaryOperation.class, new ConstantFunction(value)); Number n = apply.execute(fn).as(Number.class); assertEquals("The same value returned (" + value + " + 10): ", value + 10, n.longValue()); } /** @since 0.8 or earlier */ @Test public void testPrimitiveReturnTypeFloat() throws Exception { PolyglotEngine.Value apply = findGlobalSymbol(applyNumbers()); float value = RANDOM.nextInt(1000) + RANDOM.nextFloat(); TruffleObject fn = JavaInterop.asTruffleFunction(ObjectBinaryOperation.class, new ConstantFunction(value)); Number n = apply.execute(fn).as(Number.class); assertDouble("The same value returned (" + value + " + 10): ", value + 10, n.floatValue()); } /** @since 0.8 or earlier */ @Test public void testPrimitiveReturnTypeDouble() throws Exception { PolyglotEngine.Value apply = findGlobalSymbol(applyNumbers()); double value = RANDOM.nextInt(1000) + RANDOM.nextDouble(); TruffleObject fn = JavaInterop.asTruffleFunction(ObjectBinaryOperation.class, new ConstantFunction(value)); Number n = apply.execute(fn).as(Number.class); assertDouble("The same value returned (" + value + " + 10): ", value + 10, n.doubleValue()); } /** @since 0.8 or earlier */ @Test public void testPrimitiveidentityByte() throws Exception { String id = identity(); if (id == null) { return; } PolyglotEngine.Value apply = findGlobalSymbol(id); byte value = (byte) RANDOM.nextInt(100); Number n = (Number) apply.execute(value).get(); assertEquals("The same value returned", value, n.byteValue()); } /** @since 0.8 or earlier */ @Test public void testPrimitiveidentityBoxedByte() throws Exception { String id = identity(); if (id == null) { return; } PolyglotEngine.Value apply = findGlobalSymbol(id); byte value = (byte) RANDOM.nextInt(100); BoxedValue boxed = new BoxedValue(value); Number n = (Number) apply.execute(boxed).get(); assertEquals("The same value returned", value, n.byteValue()); } /** @since 0.8 or earlier */ @Test public void testPrimitiveidentityShort() throws Exception { String id = identity(); if (id == null) { return; } PolyglotEngine.Value apply = findGlobalSymbol(id); short value = (short) RANDOM.nextInt(100); Number n = (Number) apply.execute(value).get(); assertEquals("The same value returned", value, n.shortValue()); } /** @since 0.8 or earlier */ @Test public void testPrimitiveidentityBoxedShort() throws Exception { String id = identity(); if (id == null) { return; } PolyglotEngine.Value apply = findGlobalSymbol(id); short value = (short) RANDOM.nextInt(100); BoxedValue boxed = new BoxedValue(value); Number n = (Number) apply.execute(boxed).get(); assertEquals("The same value returned", value, n.shortValue()); } /** @since 0.8 or earlier */ @Test public void testPrimitiveidentityInt() throws Exception { String id = identity(); if (id == null) { return; } PolyglotEngine.Value apply = findGlobalSymbol(id); int value = RANDOM.nextInt(100); Number n = (Number) apply.execute(value).get(); assertEquals("The same value returned", value, n.intValue()); } /** @since 0.8 or earlier */ @Test public void testPrimitiveidentityBoxedInt() throws Exception { String id = identity(); if (id == null) { return; } PolyglotEngine.Value apply = findGlobalSymbol(id); int value = RANDOM.nextInt(100); BoxedValue boxed = new BoxedValue(value); Number n = (Number) apply.execute(boxed).get(); assertEquals("The same value returned", value, n.intValue()); } /** @since 0.8 or earlier */ @Test public void testPrimitiveidentityLong() throws Exception { String id = identity(); if (id == null) { return; } PolyglotEngine.Value apply = findGlobalSymbol(id); long value = RANDOM.nextInt(1000); Number n = (Number) apply.execute(value).get(); assertEquals("The same value returned", value, n.longValue()); } /** @since 0.8 or earlier */ @Test public void testPrimitiveidentityBoxedLong() throws Exception { String id = identity(); if (id == null) { return; } PolyglotEngine.Value apply = findGlobalSymbol(id); long value = RANDOM.nextInt(1000); BoxedValue boxed = new BoxedValue(value); Number n = (Number) apply.execute(boxed).get(); assertEquals("The same value returned", value, n.longValue()); } /** @since 0.8 or earlier */ @Test public void testPrimitiveidentityFloat() throws Exception { String id = identity(); if (id == null) { return; } PolyglotEngine.Value apply = findGlobalSymbol(id); float value = RANDOM.nextInt(1000) + RANDOM.nextFloat(); Number n = (Number) apply.execute(value).get(); assertDouble("The same value returned", value, n.floatValue()); } /** @since 0.8 or earlier */ @Test public void testPrimitiveidentityBoxedFloat() throws Exception { String id = identity(); if (id == null) { return; } PolyglotEngine.Value apply = findGlobalSymbol(id); float value = RANDOM.nextInt(1000) + RANDOM.nextFloat(); BoxedValue boxed = new BoxedValue(value); Number n = (Number) apply.execute(boxed).get(); assertDouble("The same value returned", value, n.floatValue()); } /** @since 0.8 or earlier */ @Test public void testPrimitiveidentityDouble() throws Exception { String id = identity(); if (id == null) { return; } PolyglotEngine.Value apply = findGlobalSymbol(id); double value = RANDOM.nextInt(1000) + RANDOM.nextDouble(); Number n = (Number) apply.execute(value).get(); assertDouble("The same value returned", value, n.doubleValue()); } /** @since 0.8 or earlier */ @Test public void testPrimitiveidentityBoxedDouble() throws Exception { String id = identity(); if (id == null) { return; } PolyglotEngine.Value apply = findGlobalSymbol(id); double value = RANDOM.nextInt(1000) + RANDOM.nextDouble(); BoxedValue boxed = new BoxedValue(value); Number n = (Number) apply.execute(boxed).get(); assertDouble("The same value returned", value, n.doubleValue()); } /** @since 0.8 or earlier */ @Test public void testPrimitiveidentityString() throws Exception { String id = identity(); if (id == null) { return; } PolyglotEngine.Value apply = findGlobalSymbol(id); String value = "Value" + RANDOM.nextInt(1000) + RANDOM.nextDouble(); String ret = (String) apply.execute(value).get(); assertEquals("The same value returned", value, ret); } /** @since 0.8 or earlier */ @Test public void testPrimitiveidentityBoxedString() throws Exception { String id = identity(); if (id == null) { return; } PolyglotEngine.Value apply = findGlobalSymbol(id); String value = "Value" + RANDOM.nextInt(1000) + RANDOM.nextDouble(); BoxedValue boxed = new BoxedValue(value); String ret = (String) apply.execute(boxed).get(); assertEquals("The same value returned", value, ret); } /** @since 0.8 or earlier */ @Test public void testPrimitiveIdentityForeignObject() throws Exception { String id = identity(); if (id == null) { return; } PolyglotEngine.Value apply = findGlobalSymbol(id); TruffleObject fn = JavaInterop.asTruffleFunction(LongBinaryOperation.class, new MaxMinObject(true)); Object ret = apply.execute(fn).get(); assertSameTruffleObject("The same value returned", fn, ret); } /** @since 0.8 or earlier */ @Test public void testCoExistanceOfMultipleLanguageInstances() throws Exception { final String countMethod = countInvocations(); PolyglotEngine.Builder builder = PolyglotEngine.newBuilder().executor(Executors.newSingleThreadExecutor()); PolyglotEngine vm2 = prepareVM(builder); try { PolyglotEngine.Value count2 = vm2.findGlobalSymbol(countMethod); PolyglotEngine.Value count1 = findGlobalSymbol(countMethod); PolyglotEngine vm1 = tckVM; assertNotSame("Two virtual machines allocated", vm1, vm2); int prev1 = 0; int prev2 = 0; StringBuilder log = new StringBuilder(); for (int i = 0; i < 10; i++) { int quantum = RANDOM.nextInt(10); log.append("quantum" + i + " is " + quantum + "\n"); for (int j = 0; j < quantum; j++) { Object res = count1.execute().get(); assert res instanceof Number : "expecting number: " + res + "\n" + log; ++prev1; assert ((Number) res).intValue() == prev1 : "expecting " + prev1 + " but was " + res + "\n" + log; } for (int j = 0; j < quantum; j++) { Object res = count2.execute().get(); assert res instanceof Number : "expecting number: " + res + "\n" + log; ++prev2; assert ((Number) res).intValue() == prev2 : "expecting " + prev2 + " but was " + res + "\n" + log; } assert prev1 == prev2 : "At round " + i + " the same number of invocations " + prev1 + " vs. " + prev2 + "\n" + log; } } finally { vm2.dispose(); } } /** @since 0.8 or earlier */ @Test public void testGlobalObjectIsAccessible() throws Exception { String globalObjectFunction = globalObject(); if (globalObjectFunction == null) { return; } Language language = vm().getLanguages().get(mimeType()); assertNotNull("Language for " + mimeType() + " found", language); PolyglotEngine.Value function = vm().findGlobalSymbol(globalObjectFunction); Object global = function.execute().get(); assertEquals("Global from the language same with Java obtained one", language.getGlobalObject().get(), global); } /** @since 0.8 or earlier */ @Test public void testEvaluateSource() throws Exception { Language language = vm().getLanguages().get(mimeType()); assertNotNull("Language for " + mimeType() + " found", language); PolyglotEngine.Value function = vm().findGlobalSymbol(evaluateSource()); assertNotNull(evaluateSource() + " found", function); double expect = Math.floor(RANDOM.nextDouble() * 100000.0) / 10.0; Object parsed = function.execute("application/x-tck", "" + expect).get(); assertTrue("Expecting numeric result, was:" + expect, parsed instanceof Number); double value = ((Number) parsed).doubleValue(); assertDouble("Gets the double", expect, value); } /** @since 0.8 or earlier */ @Test public void multiplyTwoVariables() throws Exception { final String firstVar = "var" + (char) ('A' + RANDOM.nextInt(24)); final String secondVar = "var" + (char) ('0' + RANDOM.nextInt(10)); String mulCode = multiplyCode(firstVar, secondVar); Source source = Source.fromText("TCK42:" + mimeType() + ":" + mulCode, "evaluate " + firstVar + " * " + secondVar).withMimeType("application/x-tck"); final PolyglotEngine.Value evalSource = vm().eval(source); final PolyglotEngine.Value invokeMul = evalSource.execute(firstVar, secondVar); Object result = invokeMul.get(); assertTrue("Expecting numeric result, was:" + result + " for " + firstVar + " and " + secondVar, result instanceof Number); assertEquals("Right value for " + firstVar + " and " + secondVar, 42, ((Number) result).intValue()); } /** @since 0.8 or earlier */ @Test public void testAddComplexNumbers() throws Exception { String id = complexAdd(); if (id == null) { return; } PolyglotEngine.Value apply = findGlobalSymbol(id); ComplexNumber a = new ComplexNumber(32, 10); ComplexNumber b = new ComplexNumber(10, 32); apply.execute(a, b); assertEquals(42.0, a.get(ComplexNumber.REAL_IDENTIFIER), 0.1); assertEquals(42.0, a.get(ComplexNumber.IMAGINARY_IDENTIFIER), 0.1); } /** @since 0.8 or earlier */ @Test public void testAddComplexNumbersWithMethod() throws Exception { String id = complexAddWithMethod(); if (id == null) { return; } PolyglotEngine.Value apply = findGlobalSymbol(id); ComplexNumber a = new ComplexNumber(32, 10); ComplexNumber b = new ComplexNumber(10, 32); apply.execute(a, b); assertDouble("The same value returned", 42.0, a.get(ComplexNumber.REAL_IDENTIFIER)); assertDouble("The same value returned", 42.0, a.get(ComplexNumber.IMAGINARY_IDENTIFIER)); } /** @since 0.8 or earlier */ @Test public void testSumRealOfComplexNumbersA() throws Exception { String id = complexSumReal(); if (id == null) { return; } PolyglotEngine.Value apply = findGlobalSymbol(id); ComplexNumbersA numbers = new ComplexNumbersA(new double[]{2, -1, 30, -1, 10, -1}); Number n = (Number) apply.execute(numbers).get(); assertDouble("The same value returned", 42.0, n.doubleValue()); } /** @since 0.8 or earlier */ @Test public void testSumRealOfComplexNumbersB() throws Exception { String id = complexSumReal(); if (id == null) { return; } PolyglotEngine.Value apply = findGlobalSymbol(id); ComplexNumbersB numbers = new ComplexNumbersB(new double[]{2, 30, 10}, new double[]{-1, -1, -1}); Number n = (Number) apply.execute(numbers).get(); assertDouble("The same value returned", 42.0, n.doubleValue()); } /** @since 0.8 or earlier */ @Test public void testSumRealOfComplexNumbersAsStructuredDataRowBased() throws Exception { String id = complexSumReal(); if (id == null) { return; } PolyglotEngine.Value apply = findGlobalSymbol(id); Schema schema = new Schema(3, true, Arrays.asList(ComplexNumber.REAL_IDENTIFIER, ComplexNumber.IMAGINARY_IDENTIFIER), Arrays.asList(Type.DOUBLE, Type.DOUBLE)); byte[] buffer = new byte[(6 * Double.SIZE / Byte.SIZE)]; putDoubles(buffer, new double[]{2, -1, 30, -1, 10, -1}); StructuredData numbers = new StructuredData(buffer, schema); Number n = (Number) apply.execute(numbers).get(); assertDouble("The same value returned", 42.0, n.doubleValue()); } /** @since 0.8 or earlier */ @Test public void testSumRealOfComplexNumbersAsStructuredDataColumnBased() throws Exception { String id = complexSumReal(); if (id == null) { return; } PolyglotEngine.Value apply = findGlobalSymbol(id); Schema schema = new Schema(3, false, Arrays.asList(ComplexNumber.REAL_IDENTIFIER, ComplexNumber.IMAGINARY_IDENTIFIER), Arrays.asList(Type.DOUBLE, Type.DOUBLE)); byte[] buffer = new byte[6 * Double.SIZE / Byte.SIZE]; putDoubles(buffer, new double[]{2, 30, 10, -1, -1, -1}); StructuredData numbers = new StructuredData(buffer, schema); Number n = (Number) apply.execute(numbers).get(); assertDouble("The same value returned", 42.0, n.doubleValue()); } /** @since 0.8 or earlier */ @Test public void testCopyComplexNumbersA() throws Exception { String id = complexCopy(); if (id == null) { return; } PolyglotEngine.Value apply = findGlobalSymbol(id); ComplexNumbersA a = new ComplexNumbersA(new double[]{-1, -1, -1, -1, -1, -1}); ComplexNumbersA b = new ComplexNumbersA(new double[]{41, 42, 43, 44, 45, 46}); apply.execute(a, b); Assert.assertArrayEquals(new double[]{41, 42, 43, 44, 45, 46}, a.getData(), 0.1); } /** @since 0.8 or earlier */ @Test public void testCopyComplexNumbersB() throws Exception { String id = complexCopy(); if (id == null) { return; } PolyglotEngine.Value apply = findGlobalSymbol(id); ComplexNumbersB a = new ComplexNumbersB(new double[]{-1, -1, -1}, new double[]{-1, -1, -1}); ComplexNumbersB b = new ComplexNumbersB(new double[]{41, 43, 45}, new double[]{42, 44, 46}); apply.execute(a, b); Assert.assertArrayEquals(new double[]{41, 42, 43, 44, 45, 46}, a.getData(), 0.1); } /** @since 0.8 or earlier */ @Test public void testCopyStructuredComplexToComplexNumbersA() throws Exception { String id = complexCopy(); if (id == null) { return; } PolyglotEngine.Value apply = findGlobalSymbol(id); ComplexNumbersA a = new ComplexNumbersA(new double[]{-1, -1, -1, -1, -1, -1}); Schema schema = new Schema(3, true, Arrays.asList(ComplexNumber.REAL_IDENTIFIER, ComplexNumber.IMAGINARY_IDENTIFIER), Arrays.asList(Type.DOUBLE, Type.DOUBLE)); byte[] buffer = new byte[6 * Double.SIZE / Byte.SIZE]; putDoubles(buffer, new double[]{41, 42, 43, 44, 45, 46}); StructuredData b = new StructuredData(buffer, schema); apply.execute(a, b); Assert.assertArrayEquals(new double[]{41, 42, 43, 44, 45, 46}, a.getData(), 0.1); } /** @since 0.8 or earlier */ @Test public void readWriteByteValue() throws Exception { String id = valuesObject(); ValuesObject values = findGlobalSymbol(id).execute().as(ValuesObject.class); assertEquals("Zero", 0, values.byteValue()); final byte value = (byte) RANDOM.nextInt(128); values.byteValue(value); assertEquals("Correct value", value, values.byteValue()); } /** @since 0.8 or earlier */ @Test public void readWriteShortValue() throws Exception { String id = valuesObject(); ValuesObject values = findGlobalSymbol(id).execute().as(ValuesObject.class); assertEquals("Zero", 0, values.shortValue()); final short value = (short) RANDOM.nextInt(32768); values.shortValue(value); assertEquals("Correct value", value, values.shortValue()); } /** @since 0.8 or earlier */ @Test public void readWriteIntValue() throws Exception { String id = valuesObject(); ValuesObject values = findGlobalSymbol(id).execute().as(ValuesObject.class); assertEquals("Zero", 0, values.intValue()); final int value = RANDOM.nextInt(); values.intValue(value); assertEquals("Correct value", value, values.intValue()); } /** @since 0.8 or earlier */ @Test public void readWriteFloatValue() throws Exception { String id = valuesObject(); ValuesObject values = findGlobalSymbol(id).execute().as(ValuesObject.class); assertDouble("Zero", 0, values.floatValue()); final float value = RANDOM.nextFloat() * 1000.0f; values.floatValue(value); assertDouble("Correct value", value, values.floatValue()); } /** @since 0.8 or earlier */ @Test public void readWriteDoubleValue() throws Exception { String id = valuesObject(); ValuesObject values = findGlobalSymbol(id).execute().as(ValuesObject.class); assertDouble("Zero", 0, values.doubleValue()); final double value = RANDOM.nextDouble() * 1000.0; values.doubleValue(value); assertDouble("Correct value", value, values.doubleValue()); } /** @since 0.8 or earlier */ @Test public void readWriteCharValue() throws Exception { String id = valuesObject(); ValuesObject values = findGlobalSymbol(id).execute().as(ValuesObject.class); assertEquals("Zero", '0', values.charValue()); String letters = "P\u0159\u00EDli\u0161 \u017Elu\u0165ou\u010Dk\u00FD k\u016F\u0148 \u00FAp\u011Bl \u010F\u00E1belsk\u00E9 \u00F3dy"; final char value = letters.charAt(RANDOM.nextInt(letters.length())); values.charValue(value); assertEquals("Correct value", value, values.charValue()); } /** @since 0.8 or earlier */ @Test public void readWriteBooleanValue() throws Exception { String id = valuesObject(); ValuesObject values = findGlobalSymbol(id).execute().as(ValuesObject.class); assertEquals("False", false, values.booleanValue()); values.booleanValue(true); assertEquals("Correct value", true, values.booleanValue()); values.booleanValue(false); assertEquals("Correct value2", false, values.booleanValue()); } /** * Test for array access. Creates a {@link TruffleObject} around a Java array, fills it with * integers and asks the language to add one to each of the array elements. * * @since 0.14 */ @Test public void addOneToAnArrayElement() throws Exception { String id = addToArray(); if (id == null) { return; } PolyglotEngine.Value add = findGlobalSymbol(id); Number[] arr = new Number[10]; for (int i = 0; i < arr.length; i++) { arr[i] = i; } TruffleObject truffleArr = JavaInterop.asTruffleObject(arr); int index = RANDOM.nextInt(arr.length - 1); add.execute(truffleArr, index, 1); final Number valueAtIndex = arr[index]; final Number valueAfterIndex = arr[index + 1]; assertNotNull("Non-null value expected at index " + index, valueAtIndex); assertNotNull("Non-null value expected at index " + (index + 1), valueAfterIndex); assertEquals("Expecting same value at both indexes", valueAtIndex.intValue(), valueAfterIndex.intValue()); } private static void putDoubles(byte[] buffer, double[] values) { for (int index = 0; index < values.length; index++) { int doubleSize = Double.SIZE / Byte.SIZE; byte[] bytes = new byte[doubleSize]; ByteBuffer.wrap(bytes).putDouble(values[index]); for (int i = 0; i < doubleSize; i++) { buffer[index * doubleSize + i] = bytes[i]; } } } private PolyglotEngine.Value findGlobalSymbol(String name) throws Exception { PolyglotEngine.Value s = vm().findGlobalSymbol(name); assert s != null : "Symbol " + name + " is not found!"; return s; } private CompoundObject findCompoundSymbol() throws Exception { final String compoundObjectName = compoundObject(); PolyglotEngine.Value s = vm().findGlobalSymbol(compoundObjectName); assert s != null : "Symbol " + compoundObjectName + " is not found!"; final PolyglotEngine.Value value = s.execute(); CompoundObject obj = value.as(CompoundObject.class); assertNotNull("Compound object for " + value + " found", obj); int traverse = RANDOM.nextInt(10); for (int i = 1; i <= traverse; i++) { obj = obj.returnsThis(); assertNotNull("Remains non-null even after " + i + " iteration", obj); } return obj; } private static void assertSameTruffleObject(String msg, Object expected, Object actual) { Object unExpected = unwrapTruffleObject(expected); Object unAction = unwrapTruffleObject(actual); assertSame(msg, unExpected, unAction); } private static Object unwrapTruffleObject(Object obj) { return obj; } interface CompoundObject { Number fourtyTwo(); Number plus(int x, int y); Object returnsNull(); CompoundObject returnsThis(); } interface ValuesObject { byte byteValue(); @MethodMessage(message = "WRITE") void byteValue(byte v); short shortValue(); @MethodMessage(message = "WRITE") void shortValue(short v); int intValue(); @MethodMessage(message = "WRITE") void intValue(int v); long longValue(); @MethodMessage(message = "WRITE") void longValue(long v); float floatValue(); @MethodMessage(message = "WRITE") void floatValue(float v); double doubleValue(); @MethodMessage(message = "WRITE") void doubleValue(double v); char charValue(); @MethodMessage(message = "WRITE") void charValue(char v); boolean booleanValue(); @MethodMessage(message = "WRITE") void booleanValue(boolean v); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy