public final class Context extends Object implements AutoCloseable
evaluate
code.
A polyglot context represents the global runtime state of all installed
and permitted
languages. Permitted languages are
initialized
lazily, when they are used for the first time. For many
context operations, a language identifier needs to be specified. A language identifier is
unique for each language.
Context.eval(Source)
. This is
possible by evaluating Source
objects or a given language identifier and code
String
. The evaluation
returns either the result value or throws a
PolyglotException
if a guest language error occurs.
Example for evaluation of a fragment of JavaScript code with a new context:
Context context = Context.create(); Value result = context.eval("js", "42"); assert result.asInt() == 42; context.close();In this example:
initialized
.
int
.
AutoCloseable
for use with the Java
try-with-resources
statement.
Contexts may be created either with default configuration using the create method
or with custom configuration using the builder
.
Both methods allow to specify a subset of the installed languages as permitted languages. If no
language is specified then all installed languages are permitted. Using the builder method
input
, error
and
output
streams, options
,
and application arguments
may be configured.
Options may be specified for languages
,
instruments
, the engine
and the
compiler
. For language options
, the
option key consists of the language id
plus a dot followed by the option
name (e.g. "js.Strict"). For most languages the option names start with an upper-case letter by
convention. A list of available options may be received using Language.getOptions()
.
Instrument options
are structured in the same way as language
options but start with the instrument id
instead.
If system properties are enabled
, which they
are by default, then all polyglot options maybe specified with the prefix "polyglot." (e.g.
"-Dpolyglot.js.Strict=true"). The system properties are read only once when the context or engine
instance is created. After that, changes to the system properties have no affect.
Each Graal language performs an initialization step before it can be used to execute code, after
which it remains initialized for the lifetime of the context. Initialization is by default lazy
and automatic, but initialization can be forced manually
if
needed.
Example for custom configuration using the context builder:
OutputStream myOut = new BufferedOutputStream() Context context = Context.newBuilder("js", "R") .out(myOut) .option("js.Strict", "true") .allowAllAccess(true) .build(); context.eval("js", "42"); context.eval("R", "42"); context.close();In this example:
Context.Builder.allowAllAccess(boolean)
we grant a new context instance with the same
access privileges as the host virtual machine.
initialized
as well.
AutoCloseable
for use with the Java try-with-resources
statement.
language bindings
. Each language provides its own bindings object
for a context. The bindings object may be used to read, modify, insert and delete members in the
top-most scope of the language. Certain languages may not allow write access to the bindings
object. See Context.getBindings(String)
for details.
A context instance also provides access to the polyglot
bindings.
The polyglot bindings are shared between languages and may be used to exchange values. See
Context.getPolyglotBindings()
for details.
Examples using language bindings from JavaScript:
Context context = Context.create("js"); Value jsBindings = context.getBindings("js") jsBindings.putMember("foo", 42); assert context.eval("js", "foo").asInt() == 42; context.eval("js", "var bar = 42"); assert jsBindings.getMember("bar").asInt() == 42; assert jsBindings.getMember("Math") .getMember("abs") .execute(-42) .asInt() == 42; context.close();In this example:
jsBindings
.
foo
into to the bindings object and verify that the
object is accessible within the language by reading from a global symbol with the same name.
Math.abs
symbol and execute
it with -42. This result is asserted to be 42.
Context.asValue(Object)
.
Also see Value.as(Class)
for further details.
By default only public classes, methods, and fields that are annotated with
@HostAccess.Export
are accessible to the guest language. This policy
can be customized using Context.Builder.allowHostAccess(HostAccess)
when constructing the
context.
Example using a Java object from JavaScript:
public class JavaRecord { @HostAccess.Export public int x; @HostAccess.Export public String name() { return "foo"; } } Context context = Context.create(); JavaRecord record = new JavaRecord(); context.getBindings("js").putMember("javaRecord", record); context.eval("js", "javaRecord.x = 42"); assert record.x == 42; context.eval("js", "javaRecord.name()").asString().equals("foo");
Context
and Value
API throw a
PolyglotException
in case an error occurs. See PolyglotException
for further
details on error handling.
all access
must be set to true
.
Contexts can be configured to share certain system resources
like ASTs or optimized code by specifying a single underlying engine. See Engine
for more
details about code sharing.
Context can be configured to allow value sharing between multiple contexts (allowed by default).
See Context.Builder.allowValueSharing(boolean)
for details.
proxy interfaces
allow to mimic guest language objects, arrays, executables,
primitives and native objects in Graal languages. Every Graal language will treat proxy instances
like objects of that particular language. Multiple proxy interfaces can be implemented at the
same time. For example, it is useful to provide proxy values that are objects with members and
arrays at the same time.
IllegalStateException
is thrown by the accessing
method.
Meta-data from the context's underlying engine
can be retrieved safely by
any thread at any time.
A context may be closed from any thread, but only if the context is not
currently executing code. If the context is currently executing some code, a different thread may
kill the running execution and close the context using Context.close(boolean)
.
Context.close(boolean)
method. A context may also be exited
at the guest application request. There are two ways a guest language may exit.
PolyglotException
with PolyglotException.isExit()
returning
true
and PolyglotException.getExitStatus()
returning the exit status code
specified by the guest application. The special exception does not influence other threads and
does not trigger context close on its own. Closing the context is up to the embedder.
PolyglotException
with
PolyglotException.isExit()
returning true
and
PolyglotException.getExitStatus()
returning the exit status code specified by the guest
application. However, the context is closed automatically. The hard exit can be customized using
Context.Builder.useSystemExit(boolean)
. If true
, the context threads are unwound by
calling System.exit(int)
with the exit status parameter specified by the guest
application. This operation terminates the whole host application.
The context pre-initialization is enabled by setting the system property
polyglot.image-build-time.PreinitializeContexts
to a comma separated list of language ids
which should be pre-initialized, for example:
-Dpolyglot.image-build-time.PreinitializeContexts=js,python
See
com.oracle.truffle.api.TruffleLanguage.patchContext(java.lang.Object, com.oracle.truffle.api.TruffleLanguage.Env)
for details about pre-initialization for language implementers.
Modifier and Type | Class and Description |
---|---|
class |
Context.Builder
Builder class to construct
Context instances. |
Modifier and Type | Method and Description |
---|---|
Value |
asValue(Object hostValue)
Converts a host value to a polyglot
value representation. |
void |
close()
Closes this context and frees up potentially allocated native resources.
|
void |
close(boolean cancelIfExecuting)
Closes the context and frees up potentially allocated native resources.
|
static Context |
create(String... permittedLanguages)
Creates a context with default configuration.
|
void |
enter()
Explicitly enters the context on the current thread.
|
boolean |
equals(Object obj) |
Value |
eval(Source source)
Evaluates a source object by using the language specified
in the source.
|
Value |
eval(String languageId,
CharSequence source)
Evaluates a guest language code literal, using a provided
language
id . |
Value |
getBindings(String languageId)
Returns a value that represents the top-most bindings of a language.
|
static Context |
getCurrent()
Returns the currently entered polyglot context.
|
Engine |
getEngine()
Provides access to meta-data about the underlying Graal engine.
|
Value |
getPolyglotBindings()
Returns polyglot bindings that may be used to exchange symbols between the host and guest
languages.
|
int |
hashCode() |
boolean |
initialize(String languageId)
Forces the initialization of a language.
|
void |
interrupt(Duration timeout)
Use this method to interrupt this context.
|
void |
leave()
Explicitly leaves the context on the current thread.
|
static Context.Builder |
newBuilder(String... permittedLanguages)
Creates a builder for constructing a context with custom configuration.
|
Value |
parse(Source source)
|
Value |
parse(String languageId,
CharSequence source)
Parses but does not evaluate a guest language code literal using a provided
language id and character sequence and returns a value
that can be executed . |
void |
resetLimits()
Resets all accumulators of resource limits for the associated context to zero.
|
void |
safepoint()
Polls safepoints events and executes them for the current thread.
|
public Engine getEngine()
Engine
being used by this contextpublic Value eval(Source source)
value
and never returns
null
. The first time a source is evaluated, it will be parsed. Consecutive
invocations of eval with the same source will only execute the already parsed code.
Basic Example:
try (Context context = Context.create()) { Source source = Source.newBuilder("js", "42", "mysource.js").build(); Value result = context.eval(source); assert result.asInt() == 42; }
source
- a source object to evaluatenull
, but the
result might represent a null
value.PolyglotException
- in case the guest language code parsing or evaluation failed.IllegalStateException
- if the context is already closed and the current thread is not
allowed to access it.IllegalArgumentException
- if the language of the given source is not installed or the
MIME type
is not supported with the language.public Value eval(String languageId, CharSequence source)
language
id
. The result is accessible as value
and never returns null
. The
provided CharSequence
must represent an immutable String.
Basic Example:
try (Context context = Context.create()) { Value result = context.eval("js", "42"); assert result.asInt() == 42; }
null
, but the
result might represent a null
value.PolyglotException
- in case the guest language code parsing or evaluation failed.IllegalArgumentException
- if the language does not exist or is not accessible.IllegalStateException
- if the context is already closed and the current thread is not
allowed to access it, or if the given language is not installed.public Value parse(Source source) throws PolyglotException
value
that can be
executed
. If a parsing fails, e.g. due to a syntax error in
the source, then a PolyglotException
will be thrown. In case of a syntax error the
PolyglotException.isSyntaxError()
will return true
. There is no
guarantee that only syntax errors will be thrown by this method. Any other guest language
exception might be thrown. If the validation succeeds then the method completes without
throwing an exception.
The result value only supports an empty set of arguments to execute
. If executed repeatedly then the source is evaluated multiple times.
Interactive
sources will print their result for
each execution of the parsing result to the output
stream.
If the parsing succeeds and the source is cached
then
the result will automatically be reused for consecutive calls to Context.parse(Source)
or
Context.eval(Source)
. If the validation should be performed for each invocation or the
result should not be remembered then cached
can be set
to false
. By default sources are cached.
Basic Example:
try (Context context = Context.create()) { Source source = Source.create("js", "42"); Value value; try { value = context.parse(source); // parsing succeeded } catch (PolyglotException e) { if (e.isSyntaxError()) { SourceSection location = e.getSourceLocation(); // syntax error detected at location } else { // other guest error detected } throw e; } // evaluate the parsed script value.execute(); }
source
- a source object to parsePolyglotException
- in case the guest language code parsing or validation failed.IllegalArgumentException
- if the language does not exist or is not accessible.IllegalStateException
- if the context is already closed and the current thread is not
allowed to access it, or if the given language is not installed.public Value parse(String languageId, CharSequence source)
language id
and character sequence and returns a value
that can be executed
. The provided CharSequence
must
represent an immutable String. This method represents a short-hand for Context.parse(Source)
.
The result value only supports an empty set of arguments to execute
. If executed repeatedly then the source is evaluated multiple times.
Interactive
sources will print their result for
each execution of the parsing result to the output
stream.
try (Context context = Context.create()) { Value value; try { value = context.parse("js", "42"); // parsing succeeded } catch (PolyglotException e) { if (e.isSyntaxError()) { SourceSection location = e.getSourceLocation(); // syntax error detected at location } else { // other guest error detected } throw e; } // evaluate the parsed script value.execute(); }
PolyglotException
- in case the guest language code parsing or evaluation failed.IllegalArgumentException
- if the language does not exist or is not accessible.IllegalStateException
- if the context is already closed and the current thread is not
allowed to access it, or if the given language is not installed.public Value getPolyglotBindings()
members
and its members are
readable
, writable
and removable
.
Guest languages may put and get members through language specific APIs. For example, in
JavaScript, symbols of the polyglot bindings can be accessed using
Polyglot.import("name")
and set using
Polyglot.export("name", value)
. Please see the individual language reference on
how to access these symbols.
IllegalStateException
- if context is already closed.public Value getBindings(String languageId)
member
for a symbol in the scope.
Languages may allow modifications of members of the returned bindings object at the
language's discretion. If the language has not been initialized
yet, it will be initialized when the bindings are requested.IllegalArgumentException
- if the language does not exist or is not accessible.IllegalStateException
- if the context is already closed.PolyglotException
- in case the lazy initialization failed due to a guest language
error.public boolean initialize(String languageId)
languageId
- the identifier of the language to initialize.true
if the language was initialized. Returns false
if it
was already initialized.PolyglotException
- in case the initialization failed due to a guest language error.IllegalArgumentException
- if the language does not exist or is not accessible.IllegalStateException
- if the context is already closed.public void resetLimits()
public Value asValue(Object hostValue)
value
representation. This conversion is
applied implicitly whenever execution
or
instantiation
arguments are provided,
members
and
array elements
are set or when a value is
returned by a polyglot proxy
. It is not required nor efficient to explicitly
convert to polyglot values before performing these operations. This method is useful to
convert a mapped
host value back to a polyglot value while preserving
the identity.
When a host value is converted to a polyglot value the following rules apply:
hostValue
is null
, then it will be interpreted as
polyglot null
.
hostValue
is already a polyglot value
, then it will be
cast to Value
.
hostValue
is an instance of Byte
, Short
,
Integer
, Long
, Float
or Double
, then it will be interpreted
as polyglot number
. Other subclasses of Number
will be
interpreted as host object
(see later).
hostValue
is an instance of Character
or String
, then
it will be interpreted as polyglot string
.
hostValue
is an instance of Boolean
, then it will be
interpreted as polyglot boolean
.
hostValue
is an instance of Instant
, LocalTime
,
ZonedDateTime
, Date
but not Date
or
Time
then it will be interpreted as polyglot time
.
hostValue
is an instance of Instant
, LocalDate
,
ZonedDateTime
, Date
but not Time
or
Date
then it will be interpreted as polyglot date
.
hostValue
is an instance of ZoneId
, Instant
,
ZonedDateTime
, Date
but not Time
and
Date
then it will be interpreted as polyglot time
zone
.
hostValue
is an instance of ZonedDateTime
, Instant
,
ZonedDateTime
, Date
but not Time
and
Date
then it will be interpreted as polyglot instant
.
hostValue
is an instance of Duration
then it will be
interpreted as polyglot duration
.
hostValue
is a polyglot proxy
, then it will be
interpreted according to the behavior specified by the proxy. See the javadoc of the proxy
subclass for further details.
hostValue
is a non-primitive mapped Java
value
, then the original value will be restored. For example, if a guest language object was
mapped to Map
, then the original object identity will be preserved when converting
back to a polyglot value.
hostValue
will be interpreted as host
object
. Host objects expose all their public java fields and methods as
members
. In addition, Java arrays, subtypes of List
and Map.Entry
will be interpreted as a value with array
elements
. The subtypes of Iterable
will be interpreted as a value with
Value.hasIterator()
iterator}. The subtypes of Iterator
will be interpreted
as an iterator
value. The subtypes of Map
will be
interpreted as a value with Value.hasHashEntries()
hash entries}. And single method
interfaces annotated with FunctionalInterface
are executable
directly. Java Class
instances are interpreted as
instantiable
, but they do not expose Class methods as members.
Basic Examples: The following assertion statements always hold:
Context context = Context.create(); assert context.asValue(null).isNull(); assert context.asValue(42).isNumber(); assert context.asValue("42").isString(); assert context.asValue('c').isString(); assert context.asValue(new String[0]).hasArrayElements(); assert context.asValue(new ArrayList<>()).isHostObject(); assert context.asValue(new ArrayList<>()).hasArrayElements(); assert context.asValue((Supplier) () -> 42).execute().asInt() == 42;
members
. Methods and fields are grouped by name,
so only one member is exposed for each name.
Class
objects have a member named static
referring to the class's companion
object containing the static methods of the class. Likewise, the companion object has a
member named class
that points back to the class object.
When an argument value needs to be mapped to match a required Java method parameter type,
then the semantics of host value mapping
is used. The result of the
mapping is equivalent of calling Value.as(Class)
with the parameter type. Therefore,
a ClassCastException
or NullPointerException
is thrown if a parameter value
cannot be cast to the required parameter type.
Overloaded java methods are selected based on the provided arguments. In case multiple mapped
Java methods with the same name are applicable for executions
or instantiations
, then the method with the
most concrete method with applicable arguments will be called.
The following parameter type hierarchy is used for a method resolution. Left-most parameter types are prioritized over types to their right.
Boolean
values: boolean, Boolean, Object
Advanced Example:
This example first creates a new instance of the Java class Record
and inspects
it using the polyglot value API. Later, a host value is converted to a polyglot value using
JavaScript guest language.
In the following examples all assertions hold.
class JavaRecord { public int x = 42; public double y = 42.0; public String name() { return "foo"; } } Context context = Context.create(); Value record = context.asValue(new JavaRecord()); assert record.getMember("x").asInt() == 42; assert record.getMember("y").asDouble() == 42.0d; assert record.getMember("name").execute().asString().equals("foo"); assert context.eval("js", "(function(record) record.x)") .execute(record).asInt() == 42; assert context.eval("js", "(function(record) record.y)") .execute(record).asDouble() == 42.0d; assert context.eval("js", "(function(record) record.name())") .execute(record).asString().equals("foo");
hostValue
- the host value to convert to a polyglot value.IllegalStateException
- if the context is already closedValue.as(Class)
public void enter()
execute
method. This can be inefficient if a very high
number of simple operations needs to be performed. By entering
and
leaving
once explicitly, the overhead for entering/leaving the context for
each operation can be eliminated. Contexts can be entered multiple times on the same thread.IllegalStateException
- if the context is already closed
.PolyglotException
- if a language has denied execution on the current thread.leave a context.
public void leave()
entered
before calling this method.IllegalStateException
- if the context is already closed or if the context was not
entered
on the current thread.enter a context.
public void close(boolean cancelIfExecuting)
PolyglotException
. The exception indicates that it was
cancelled
. Please note, canceling a single context
can negatively affect the performance of other executing contexts constructed with the same
engine.
If internal errors occur during context closing, then they are printed to the configured
error output stream
. If a context was closed, then its
methods will throw an IllegalStateException
when invoked. If an attempt to close a
context was successful, then consecutive calls to close have no effect.
For convenience, before the actual closing process begins, the close method leaves the
context on the current thread, if it was entered explicitly
.
cancelIfExecuting
- if true
then currently executing contexts will be
cancelled
, else an
IllegalStateException
is thrown.PolyglotException
- in case the close failed due to a guest language error, or, if
cancelIfExecuting is false
, the exception is also thrown when the
context was cancelled
or the context was
exited
at request of the guest application.IllegalStateException
- if the context is still running and cancelIfExecuting is
false
close an engine.
public void close()
IllegalStateException
is thrown. To close concurrently executing contexts see
Context.close(boolean)
.
If internal errors occur during the context closure, then they are printed to the configured
error output stream
. If a context was closed, then its
methods will throw an IllegalStateException
, when invoked. If an attempt to close a
context was successful, then consecutive calls to close have no effect.
For convenience, before the actual closing process begins, the close method leaves the
context on the current thread, if it was entered explicitly
.
close
in interface AutoCloseable
PolyglotException
- in case the close failed due to a guest language error, or the
context was cancelled
or the context was
exited
at request of the guest application.IllegalStateException
- if the context is currently executing on another thread.close an engine.
public void interrupt(Duration timeout) throws TimeoutException
close(true)
is executed.timeout
- specifies the duration the interrupt method will wait for the active threads
of the context to be finished. Setting the duration to 0
means wait indefinitely.IllegalStateException
- in case the context is entered in the current thread.TimeoutException
- in case the interrupt was not successful, i.e., not all threads were
finished within the specified time limit.public void safepoint()
In this example we allow interruption
and
cancellation
to stop the processing of our event queue.
class EventProcessor { List
PolyglotException
- in case the close failed due to a guest language error.IllegalStateException
- if the context is already closed
.public static Context getCurrent()
Context.enter()
on the current thread. The returned context may be
used to:
string literals
or
file
sources.
Convert
Java values to polyglot values
.
bindings
of other languages.
polyglot bindings
.
languages
or
options
of the engine
.
The returned context can not be used to enter
, leave
or close
the context or engine
. Invoking such
methods will cause an IllegalStateException
to be thrown. This ensures that only the
creator
of a context is allowed to enter, leave or close a
context.
The current entered context may change. It is therefore required to call getCurrent
every time a context is needed. The current entered context should not be cached
in static fields.
IllegalStateException
- if no context is currently entered.public static Context create(String... permittedLanguages)
newBuilder(permittedLanuages).build()
.Context.newBuilder(String...)
public static Context.Builder newBuilder(String... permittedLanguages)
permittedLanguages
- names of languages permitted in the context. If no languages are
provided, then all installed languages will be permitted. If an explicit
engine
was specified then only those languages may
be used that were installed and permitted
by
the specified engine. Languages are validated when the context is
built
. An IllegalArgumentException
will be thrown
if an unknown or a language denied by the engine was used.