0
# Language Execution and Source Parsing
1
2
The GraalVM Polyglot API provides comprehensive capabilities for executing and parsing code across multiple programming languages. This includes source code creation, evaluation, parsing, and language bindings management.
3
4
## Source Creation and Management
5
6
The Source class represents source code with language and metadata information, supporting various input formats and caching strategies.
7
8
### Source Factory Methods
9
10
```java { .api }
11
// Simple source creation
12
public static Source create(String language, CharSequence source);
13
14
// Builder pattern for advanced configuration
15
public static Source.Builder newBuilder(String language, CharSequence characters, String name);
16
public static Source.Builder newBuilder(String language, ByteSequence bytes, String name);
17
public static Source.Builder newBuilder(String language, File file);
18
public static Source.Builder newBuilder(String language, URL url);
19
public static Source.Builder newBuilder(String language, Reader source, String name);
20
```
21
22
**Basic Source Creation:**
23
24
```java
25
// Inline source code
26
Source jsSource = Source.create("js", "function factorial(n) { return n <= 1 ? 1 : n * factorial(n-1); }");
27
28
// From file
29
Source pySource = Source.newBuilder("python", new File("script.py")).build();
30
31
// From URL with caching
32
Source webSource = Source.newBuilder("js", new URL("https://example.com/script.js"))
33
.cached(true)
34
.build();
35
```
36
37
### Source Builder Configuration
38
39
```java { .api }
40
public static final class Source.Builder {
41
// Content and encoding
42
public Source.Builder content(CharSequence characters);
43
public Source.Builder content(ByteSequence bytes);
44
public Source.Builder encoding(Charset encoding);
45
46
// Metadata
47
public Source.Builder name(String name);
48
public Source.Builder mimeType(String mimeType);
49
public Source.Builder uri(URI uri);
50
51
// Behavior configuration
52
public Source.Builder cached(boolean cached);
53
public Source.Builder interactive(boolean interactive);
54
public Source.Builder internal(boolean internal);
55
56
// Build the source
57
public Source build();
58
}
59
```
60
61
### Language and MIME Type Discovery
62
63
```java { .api }
64
// Language detection from file/URL
65
public static String findLanguage(File file);
66
public static String findLanguage(URL url);
67
public static String findLanguage(String mimeType);
68
69
// MIME type detection
70
public static String findMimeType(File file);
71
public static String findMimeType(URL url);
72
```
73
74
**Language Detection Example:**
75
76
```java
77
File jsFile = new File("script.js");
78
String language = Source.findLanguage(jsFile); // Returns "js"
79
String mimeType = Source.findMimeType(jsFile); // Returns "application/javascript"
80
81
// Create source with auto-detected language
82
Source source = Source.newBuilder(language, jsFile).build();
83
```
84
85
### Source Content Access
86
87
```java { .api }
88
public final class Source {
89
// Basic properties
90
public String getLanguage();
91
public String getName();
92
public String getPath();
93
public URL getURL();
94
public URI getURI();
95
public String getMimeType();
96
97
// Content access
98
public CharSequence getCharacters();
99
public CharSequence getCharacters(int lineNumber);
100
public ByteSequence getBytes();
101
public Reader getReader();
102
public InputStream getInputStream();
103
public int getLength();
104
105
// Source properties
106
public boolean isInteractive();
107
public boolean isInternal();
108
public boolean hasCharacters();
109
public boolean hasBytes();
110
111
// Line and column operations
112
public int getLineCount();
113
public int getLineNumber(int offset);
114
public int getColumnNumber(int offset);
115
}
116
```
117
118
## Code Evaluation
119
120
The Context class provides methods for evaluating source code with immediate execution and result retrieval.
121
122
### Evaluation Methods
123
124
```java { .api }
125
// Evaluate source objects
126
public Value eval(Source source);
127
128
// Evaluate inline code
129
public Value eval(String languageId, CharSequence source);
130
```
131
132
**Evaluation Examples:**
133
134
```java
135
Context context = Context.create("js", "python");
136
137
// JavaScript evaluation
138
Value jsResult = context.eval("js", "Math.PI * 2");
139
System.out.println(jsResult.asDouble()); // 6.283185307179586
140
141
// Python evaluation
142
Value pyResult = context.eval("python", "[x**2 for x in range(5)]");
143
System.out.println(pyResult.toString()); // [0, 1, 4, 9, 16]
144
145
// Source object evaluation
146
Source factorial = Source.create("js", """
147
function factorial(n) {
148
return n <= 1 ? 1 : n * factorial(n-1);
149
}
150
factorial(5);
151
""");
152
Value factResult = context.eval(factorial);
153
System.out.println(factResult.asInt()); // 120
154
```
155
156
### Multi-Language Evaluation
157
158
```java
159
Context context = Context.create("js", "python", "ruby");
160
161
// JavaScript sets up data
162
context.eval("js", "var shared = { message: 'Hello from JavaScript', count: 42 };");
163
164
// Python accesses and modifies
165
context.eval("python", """
166
import polyglot
167
shared = polyglot.eval(language="js", string="shared")
168
shared.message = "Modified by Python"
169
shared.count = shared.count * 2
170
""");
171
172
// Ruby reads the result
173
Value rubyResult = context.eval("ruby", """
174
shared = Polyglot.eval("js", "shared")
175
"#{shared[:message]} - Count: #{shared[:count]}"
176
""");
177
178
System.out.println(rubyResult.asString()); // "Modified by Python - Count: 84"
179
```
180
181
## Code Parsing
182
183
Parsing allows you to compile source code without immediate execution, enabling syntax validation and AST preparation.
184
185
### Parsing Methods
186
187
```java { .api }
188
// Parse source objects
189
public Value parse(Source source);
190
191
// Parse inline code
192
public Value parse(String languageId, CharSequence source);
193
```
194
195
**Parsing Examples:**
196
197
```java
198
Context context = Context.create("js");
199
200
// Parse without execution
201
Source jsFunction = Source.create("js", "function greet(name) { return 'Hello, ' + name; }");
202
Value parsed = context.parse(jsFunction);
203
204
// The function is now compiled but not executed
205
// Execute later with different arguments
206
Value greeting1 = context.eval("js", "greet('Alice')");
207
Value greeting2 = context.eval("js", "greet('Bob')");
208
```
209
210
### Parse vs. Eval
211
212
```java
213
Context context = Context.create("js");
214
215
// Parsing: Compiles but doesn't execute
216
Value parsed = context.parse("js", "console.log('This will not print during parsing')");
217
// No output - just compilation
218
219
// Evaluation: Compiles and executes
220
Value evaluated = context.eval("js", "console.log('This will print during evaluation')");
221
// Output: "This will print during evaluation"
222
223
// Execute the previously parsed code
224
context.eval("js", "console.log('Now executing parsed code')");
225
// Output: "This will not print during parsing"
226
```
227
228
## Language Bindings
229
230
Bindings provide a way to share values between the host (Java) and guest languages, as well as between different guest languages.
231
232
### Language-Specific Bindings
233
234
```java { .api }
235
// Get bindings for a specific language
236
public Value getBindings(String languageId);
237
238
// Get polyglot bindings (shared across languages)
239
public Value getPolyglotBindings();
240
```
241
242
### Bindings Operations
243
244
Language bindings behave like a Map-like object where you can store and retrieve values by name.
245
246
```java
247
Context context = Context.create("js", "python");
248
249
// Get JavaScript bindings
250
Value jsBindings = context.getBindings("js");
251
252
// Add host objects to JavaScript
253
jsBindings.putMember("javaList", Arrays.asList(1, 2, 3, 4, 5));
254
jsBindings.putMember("javaMap", Map.of("key1", "value1", "key2", "value2"));
255
256
// JavaScript can now access these objects
257
context.eval("js", """
258
console.log('Java list length:', javaList.length);
259
console.log('Java map key1:', javaMap.get('key1'));
260
""");
261
262
// Set values from JavaScript
263
context.eval("js", "var jsResult = javaList.reduce((sum, x) => sum + x, 0);");
264
265
// Access JavaScript values from Java
266
Value jsResult = jsBindings.getMember("jsResult");
267
System.out.println("Sum calculated in JS: " + jsResult.asInt()); // 15
268
```
269
270
### Polyglot Bindings
271
272
Polyglot bindings are shared across all languages in a context:
273
274
```java
275
Context context = Context.create("js", "python");
276
277
// Get shared polyglot bindings
278
Value polyglotBindings = context.getPolyglotBindings();
279
280
// Add shared data
281
polyglotBindings.putMember("sharedCounter", 0);
282
polyglotBindings.putMember("sharedConfig", Map.of("debug", true, "version", "1.0"));
283
284
// JavaScript increments counter
285
context.eval("js", """
286
Polyglot.import('sharedCounter');
287
var currentCount = Polyglot.import('sharedCounter');
288
Polyglot.export('sharedCounter', currentCount + 1);
289
""");
290
291
// Python also increments counter
292
context.eval("python", """
293
import polyglot
294
current = polyglot.import_value('sharedCounter')
295
polyglot.export_value('sharedCounter', current + 10)
296
""");
297
298
// Read final value
299
Value finalCount = polyglotBindings.getMember("sharedCounter");
300
System.out.println("Final counter: " + finalCount.asInt()); // 11
301
```
302
303
## Host Value Conversion
304
305
The Context provides methods to convert Java objects to polyglot values that can be used by guest languages.
306
307
### Value Conversion
308
309
```java { .api }
310
// Convert host objects to polyglot values
311
public Value asValue(Object hostValue);
312
```
313
314
**Conversion Examples:**
315
316
```java
317
Context context = Context.create("js");
318
319
// Convert various Java types
320
Value stringValue = context.asValue("Hello World");
321
Value intValue = context.asValue(42);
322
Value listValue = context.asValue(Arrays.asList(1, 2, 3));
323
Value mapValue = context.asValue(Map.of("name", "Alice", "age", 30));
324
325
// Custom objects (with HostAccess configuration)
326
public class Person {
327
@HostAccess.Export public String name;
328
@HostAccess.Export public int age;
329
330
@HostAccess.Export
331
public String greet() {
332
return "Hello, I'm " + name;
333
}
334
}
335
336
Context restrictedContext = Context.newBuilder("js")
337
.allowHostAccess(HostAccess.EXPLICIT)
338
.build();
339
340
Person person = new Person();
341
person.name = "Alice";
342
person.age = 30;
343
344
Value personValue = restrictedContext.asValue(person);
345
346
// Make available to JavaScript
347
Value jsBindings = restrictedContext.getBindings("js");
348
jsBindings.putMember("person", personValue);
349
350
restrictedContext.eval("js", """
351
console.log(person.name); // "Alice"
352
console.log(person.age); // 30
353
console.log(person.greet()); // "Hello, I'm Alice"
354
""");
355
```
356
357
## Language Initialization
358
359
Contexts support lazy initialization of languages, improving startup performance when not all languages are immediately needed.
360
361
### Language Initialization Control
362
363
```java { .api }
364
// Explicitly initialize a language
365
public boolean initialize(String languageId);
366
```
367
368
**Initialization Example:**
369
370
```java
371
Context context = Context.create("js", "python", "ruby");
372
373
// Initially, no languages are initialized
374
// First evaluation triggers initialization
375
long startTime = System.currentTimeMillis();
376
context.eval("js", "1 + 1"); // JavaScript gets initialized here
377
long jsInitTime = System.currentTimeMillis() - startTime;
378
379
// Subsequent evaluations are faster
380
startTime = System.currentTimeMillis();
381
context.eval("js", "2 + 2"); // No initialization needed
382
long jsExecTime = System.currentTimeMillis() - startTime;
383
384
// Pre-initialize Python for faster first execution
385
context.initialize("python");
386
Value pyResult = context.eval("python", "len([1, 2, 3, 4, 5])");
387
```
388
389
## Error Handling
390
391
Language execution can produce various types of errors that should be handled appropriately.
392
393
### Exception Types
394
395
```java
396
Context context = Context.create("js");
397
398
try {
399
// Syntax error
400
context.eval("js", "function malformed { missing parentheses }");
401
} catch (PolyglotException e) {
402
if (e.isSyntaxError()) {
403
System.out.println("Syntax error: " + e.getMessage());
404
SourceSection location = e.getSourceLocation();
405
if (location != null) {
406
System.out.printf("At line %d, column %d%n",
407
location.getStartLine(), location.getStartColumn());
408
}
409
}
410
}
411
412
try {
413
// Runtime error
414
context.eval("js", "nonExistentFunction()");
415
} catch (PolyglotException e) {
416
if (e.isGuestException()) {
417
System.out.println("Runtime error in guest language: " + e.getMessage());
418
Value guestObject = e.getGuestObject();
419
// Handle guest exception object
420
}
421
}
422
```
423
424
## Source Location Information
425
426
Source sections provide detailed location information for debugging and error reporting.
427
428
### SourceSection Details
429
430
```java { .api }
431
public final class SourceSection {
432
public Source getSource();
433
public int getStartLine();
434
public int getEndLine();
435
public int getStartColumn();
436
public int getEndColumn();
437
public int getCharIndex();
438
public int getCharLength();
439
public int getCharEndIndex();
440
public boolean isAvailable();
441
public boolean hasLines();
442
public boolean hasColumns();
443
public boolean hasCharIndex();
444
public CharSequence getCharacters();
445
}
446
```
447
448
**Source Location Example:**
449
450
```java
451
Source source = Source.newBuilder("js", """
452
function calculate(x, y) {
453
return x / y; // Division by zero potential
454
}
455
calculate(10, 0);
456
""", "calculator.js").build();
457
458
Context context = Context.create("js");
459
460
try {
461
context.eval(source);
462
} catch (PolyglotException e) {
463
SourceSection location = e.getSourceLocation();
464
if (location != null) {
465
System.out.printf("Error in %s:%d:%d-%d:%d%n",
466
location.getSource().getName(),
467
location.getStartLine(), location.getStartColumn(),
468
location.getEndLine(), location.getEndColumn());
469
System.out.printf("Code: %s%n", location.getCharacters());
470
}
471
}
472
```
473
474
## Performance Considerations
475
476
### Source Caching
477
478
```java
479
// Enable source caching for repeated evaluation
480
Source cachedSource = Source.newBuilder("js", new File("frequent-script.js"))
481
.cached(true)
482
.build();
483
484
// Multiple contexts can share the cached source
485
Context context1 = Context.create("js");
486
Context context2 = Context.create("js");
487
488
context1.eval(cachedSource); // Parsed and cached
489
context2.eval(cachedSource); // Uses cached parse result
490
```
491
492
### Parsing vs. Evaluation
493
494
```java
495
Context context = Context.create("js");
496
497
// For repeated execution, parse once and reference
498
Source template = Source.create("js", "function process(data) { /* complex logic */ }");
499
context.parse(template); // One-time compilation
500
501
// Then evaluate with different data
502
for (Object data : dataSet) {
503
Value bindings = context.getBindings("js");
504
bindings.putMember("currentData", data);
505
context.eval("js", "process(currentData)");
506
}
507
```