Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
116 commits
Select commit Hold shift + click to select a range
e0d3161
Add CI workflow for cn1playground language smoke tests
liannacasper Apr 7, 2026
849ed16
Fix playground workflow script invocation permissions
liannacasper Apr 7, 2026
86f16ef
Fix registry generator classpath for JDK8 tools API
liannacasper Apr 7, 2026
683e241
Use Java 17 and portable checks in playground smoke CI
liannacasper Apr 7, 2026
328dfcf
Build dependent modules in playground smoke Maven step
liannacasper Apr 7, 2026
e175d28
Run playground smoke harness from common module classpath
liannacasper Apr 7, 2026
e8d16d7
Run playground smoke tests under Xvfb in CI
liannacasper Apr 7, 2026
81ab13a
Install reactor artifacts before running playground harness
liannacasper Apr 7, 2026
c25b298
Force smoke harness process exit after success
liannacasper Apr 7, 2026
273bf2e
Add playground syntax matrix harness to smoke test pipeline
liannacasper Apr 7, 2026
81e0d93
Use Java text blocks in syntax matrix snippets
liannacasper Apr 7, 2026
fac67db
Stabilize syntax matrix outcomes and always exit process
liannacasper Apr 7, 2026
b47c676
Document playground smoke workflow and syntax rollout process
liannacasper Apr 7, 2026
0bb0227
Expand syntax matrix to table-driven parse/eval coverage
liannacasper Apr 7, 2026
5e69ec2
Mark try-with-resources matrix cases as current parse gaps
liannacasper Apr 8, 2026
b720de1
Enable try-with-resources without catch/finally in parser
liannacasper Apr 8, 2026
af3477e
Throw evaluation error for enhanced-for over null
liannacasper Apr 8, 2026
4164979
Use local AutoCloseable resources in TWR matrix cases
liannacasper Apr 8, 2026
39a4611
Use StringReader resources in TWR matrix cases
liannacasper Apr 8, 2026
3c6b15d
Enable BeanShell class generation for inline class declarations
liannacasper Apr 8, 2026
f8e255d
Handle superclass invocation checked exceptions in Name
liannacasper Apr 8, 2026
5930195
Support inline AutoCloseable class snippets without ASM generator
liannacasper Apr 8, 2026
4b14ccd
Restore BeanShell class generation for playground runtime
liannacasper Apr 8, 2026
acf789b
Handle superclass invocation target exceptions in Name
liannacasper Apr 9, 2026
dfbe8d4
Remove InvocationTargetException from CN1 playground path
liannacasper Apr 9, 2026
9149b94
Remove unsupported reflection and regex usage from playground runtime
liannacasper Apr 9, 2026
bae5143
Use CN1 RE/StringUtil for inline AutoCloseable rewrite
liannacasper Apr 9, 2026
6db39d8
Rewrite try-resource helper types to AutoCloseable
liannacasper Apr 9, 2026
b7a8085
Stop rewriting inline AutoCloseable helpers in adaptScript
liannacasper Apr 9, 2026
7b80ebb
Enable scripted class declarations in BSHClassDeclaration
liannacasper Apr 9, 2026
d920b72
Remove reflection/UUID/stream usage from class generation util
liannacasper Apr 10, 2026
c0f440e
Restore strict validation hook with faux-reflection checks
liannacasper Apr 10, 2026
8a6111c
Remove ASM runtime usage and fall back to CN1-safe rewrites
liannacasper Apr 10, 2026
76c753d
Add non-bytecode class rewrite path for simple static inner case
liannacasper Apr 10, 2026
f30f1e5
Unify class/anonymous/lambda adaptation pipeline
liannacasper Apr 10, 2026
49cc1d0
Return Component in inner_class_static_member matrix case
liannacasper Apr 10, 2026
a7983a6
Fix static inner class snippet rewrite in playground runner
liannacasper Apr 10, 2026
7aa39bb
Generalize playground support for top-level class declarations
liannacasper Apr 10, 2026
489dc45
Add scripted class runtime, expand syntax matrix, fix several languag…
shai-almog Apr 19, 2026
39ba15a
Add super.method() dispatch and switch-expression source rewrite
shai-almog Apr 19, 2026
aa4e46c
Rewrite method references to one-arg lambdas before parsing
shai-almog Apr 19, 2026
96df196
Desugar Java records to a class with final fields and accessors
shai-almog Apr 19, 2026
f9860f0
Add sealed sugar, anon interface impls, and fix record canonical ctor
shai-almog Apr 19, 2026
8957529
Expand access registry for collection method dispatch
shai-almog Apr 19, 2026
ef5a8f8
Prefer scripted classes over imported Java types in declarations
shai-almog Apr 19, 2026
df6ee42
Implement common java.util.function SAMs on LambdaValue
shai-almog Apr 19, 2026
9290be7
Static nested classes + anon SAM rewrite for known function types
shai-almog Apr 19, 2026
95057fd
Pass enum-constant constructor args through to ScriptedClass.newInstance
shai-almog Apr 19, 2026
a4a8762
Support yield form for switch expressions
shai-almog Apr 19, 2026
83e81bd
Per-constant enum method bodies
shai-almog Apr 19, 2026
6f0e6e8
Accept LambdaValue at SAM call sites it implements directly
shai-almog Apr 19, 2026
dea4768
super(args) constructor forwarding + java.util.stream registry classes
shai-almog Apr 19, 2026
d2a096d
Overload resolution for scripted classes + integration test broadening
shai-almog Apr 19, 2026
90f6952
Update README + two more integration tests
shai-almog Apr 19, 2026
4e7376b
Fix multi-level super, nested switch exprs, anon enum inheritance
shai-almog Apr 19, 2026
5e2771a
Seven more integration tests + two documented gaps
shai-almog Apr 19, 2026
667a8e6
Ten more integration cases: enum values iteration, lambda composition,
shai-almog Apr 19, 2026
41cdb15
Unblock StringBuilder dispatch in registry
shai-almog Apr 19, 2026
e7848c7
Seven more integration patterns + one small BSH gap documented
shai-almog Apr 19, 2026
5e1cc85
Resolve method-level type parameters as Object in the registry generator
shai-almog Apr 19, 2026
84adbdd
Autobox wrapper values for postfix/prefix unary ++/--
shai-almog Apr 19, 2026
ce8bf7a
Support nested top-level lambdas + 6 more integration cases
shai-almog Apr 19, 2026
dd87e2f
Support var in try-with-resources declarations
shai-almog Apr 20, 2026
7481d47
Eight more integration cases
shai-almog Apr 20, 2026
88e3888
Eight more diverse integration cases
shai-almog Apr 20, 2026
e292c77
Accept Character for int-sized numeric params (char-to-int widening)
shai-almog Apr 20, 2026
38a7634
Seven more integration cases
shai-almog Apr 20, 2026
b4ac50f
Six more integration cases
shai-almog Apr 20, 2026
1dc8568
Inherit default methods from implemented interfaces
shai-almog Apr 20, 2026
0180686
Eight more integration patterns
shai-almog Apr 20, 2026
9cbf89b
Nine more integration cases
shai-almog Apr 20, 2026
5f4d5a5
Use VARIABLE-typed LHS for scripted-instance field assignments
shai-almog Apr 20, 2026
c7c1fd6
Switch rewriting inside lambda bodies + callstack null-guards
shai-almog Apr 20, 2026
920b759
Eight more CN1-centric integration cases + 2 documented gaps
shai-almog Apr 20, 2026
2ec220f
Treat interface fields as implicitly static
shai-almog Apr 20, 2026
581cba1
Eight more integration cases
shai-almog Apr 20, 2026
ab1e088
Fix scripted-field assignment through this.x and external p.x paths
shai-almog Apr 20, 2026
59e1724
Inherit interface constants into implementing class's static namespace
shai-almog Apr 20, 2026
61c583d
Exception hierarchies + Map.Entry-style nested Java class lookup
shai-almog Apr 20, 2026
7bbf136
Map.Entry method dispatch via direct interface fallback
shai-almog Apr 20, 2026
724f497
Collection.stream() via CN1StreamBridge shim
shai-almog Apr 20, 2026
3343059
Inherited static fields reachable through subclass reference
shai-almog Apr 20, 2026
e020942
Nested static classes, generic-method bounds, and local-sources runti…
shai-almog Apr 20, 2026
c8a8c96
Bump playground to CN1 7.0.234 and fix version-update scripts
shai-almog Apr 20, 2026
3d5cb84
Expand CN1StreamBridge with full terminal/intermediate op surface
shai-almog Apr 20, 2026
58c882e
Record compact constructors and pattern-switch statements
shai-almog Apr 20, 2026
300704b
Source-level sealed/permits enforcement
shai-almog Apr 21, 2026
f4cf713
UI paint verification on every SUCCESS matrix case
shai-almog Apr 21, 2026
b180579
"Did you mean" suggestions for missing static fields and methods
shai-almog Apr 21, 2026
b5fbf19
README: document Java-language coverage updates from this branch
shai-almog Apr 21, 2026
902e1f6
Defer METHOD_INDEX and FIELD_INDEX init to first use
shai-almog Apr 21, 2026
26d6d06
Non-static inner classes reach outer instance fields
shai-almog Apr 21, 2026
93a2890
Enforce interface method implementation and improve missing-method er…
shai-almog Apr 21, 2026
cc568ef
Enforce abstract-method implementation for scripted interfaces too
shai-almog Apr 21, 2026
7b207c1
outer.new Inner() and per-package lazy findClass
shai-almog Apr 21, 2026
a44e5d3
README: document inner classes, iface enforcement, diagnostics, cold-…
shai-almog Apr 21, 2026
84d5e6c
Parse-error diagnostics + 20 more matrix cases
shai-almog Apr 21, 2026
e451265
Primitive-array support + 26 more matrix cases
shai-almog Apr 21, 2026
8c7748a
replacePreview: explicit repaint after revalidate
shai-almog Apr 21, 2026
bf7baa3
Revert "replacePreview: explicit repaint after revalidate"
shai-almog Apr 21, 2026
78991d8
Fix preview staleness on side-menu script selection
shai-almog Apr 22, 2026
724bc6f
Revert "Fix preview staleness on side-menu script selection"
shai-almog Apr 22, 2026
a355dc7
Stop the 250ms side-menu theme timer while the menu is closed
shai-almog Apr 22, 2026
5ad5336
Revert "Stop the 250ms side-menu theme timer while the menu is closed"
shai-almog Apr 22, 2026
2fc5b83
Use forceRevalidate + parent revalidate in replacePreview
shai-almog Apr 22, 2026
5a05bbe
Revert "Use forceRevalidate + parent revalidate in replacePreview"
shai-almog Apr 22, 2026
2092bda
Drop HTML5Peer.removeOnDeinitialize=FALSE from editor browsers
shai-almog Apr 22, 2026
b8a3806
Revert "Drop HTML5Peer.removeOnDeinitialize=FALSE from editor browsers"
shai-almog Apr 22, 2026
a09321e
Temp: diagnostic title-bar buttons for the first 3 samples
shai-almog Apr 22, 2026
7e62f6b
Remove the 250ms side-menu theme polling timer
shai-almog Apr 22, 2026
5818f2a
Strip the remaining side-menu dark-mode hacks
shai-almog Apr 22, 2026
06e5424
Switch side-menu sample entries to Command-based API
shai-almog Apr 22, 2026
bf7db71
Revert "Switch side-menu sample entries to Command-based API"
shai-almog Apr 22, 2026
e071798
Revert "Temp: diagnostic title-bar buttons for the first 3 samples"
shai-almog Apr 22, 2026
02aff39
Revert "Strip the remaining side-menu dark-mode hacks"
shai-almog Apr 22, 2026
2774d29
Revert "Remove the 250ms side-menu theme polling timer"
shai-almog Apr 22, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions .github/workflows/cn1playground-language.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
name: CN1 Playground Language Tests

on:
pull_request:
types: [opened, synchronize, reopened, ready_for_review]
paths:
- 'scripts/cn1playground/**'
- '.github/workflows/cn1playground-language.yml'
push:
branches: [main, master]
paths:
- 'scripts/cn1playground/**'
- '.github/workflows/cn1playground-language.yml'
workflow_dispatch:

permissions:
contents: read

jobs:
language-smoke:
name: Playground language smoke
runs-on: ubuntu-latest

steps:
- name: Check out repository
uses: actions/checkout@v4

- name: Set up Java 17
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: '17'
cache: maven

- name: Ensure Xvfb is available
run: |
set -euo pipefail
if ! command -v xvfb-run >/dev/null 2>&1; then
sudo apt-get update
sudo apt-get install -y xvfb
fi

- name: Run playground language smoke tests
run: |
set -euo pipefail
cd scripts/cn1playground
xvfb-run -a bash tools/run-playground-smoke-tests.sh
223 changes: 164 additions & 59 deletions scripts/cn1playground/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -202,69 +202,146 @@ The playground uses a customized version of [BeanShell](https://github.com/beans
- **Variable capture**: Lambdas capture variables from enclosing scopes
- **Nested lambdas**: Inner lambdas are rewritten before outer lambdas execute

### Limitations

#### Class Declarations Have Limited Support

BeanShell's class generation is disabled in this playground, but single top-level classes are automatically unwrapped:

```java
// This works - playground unwraps the class:
public class DemoApp {
private Label status; // Becomes script variable: status = null;

public void start() {
status = new Label("Ready");
// ...
}
}
```

**What doesn't work**:
- Nested classes
- Multiple top-level classes
- Interfaces or enums
- Static fields or methods that reference instance fields

For complex state management, consider using loose methods with script-level variables instead of class fields.

#### Instance Field Access in Lambdas

Variables from enclosing scopes work in lambdas, but instance field references without `this` may not resolve correctly:

```java
// Works:
String prefix = "Hello ";
button.addActionListener(e -> status.setText(prefix + "World"));

// May not work as expected if 'status' is an instance field:
// Use 'this.status' or move the field to script scope
```

#### Generic Type Parameters Are Erased

Generic type parameters are erased at runtime. Methods that rely on specific generic types may require casting:
### Class, Interface, Enum, and Record Support

The playground includes a CN1-safe scripted-class runtime so user-declared
types work without runtime bytecode generation or reflection. The
`PlaygroundSyntaxMatrixHarness` (in `common/src/test/java/...`) is a
table-driven matrix that pins exactly what is supported — every entry
either reaches `SUCCESS` or documents a known gap with its diagnostic.

What works:

- **Classes** with fields, constructors (overloaded), methods (overloaded),
generic type parameters (`class Pair<T>`), inheritance with method
overrides, and `super.method()` / `super(args)` dispatch.
- **Static nested classes** (`Outer.Inner`) with `Outer.Inner.staticField` /
`new Outer.Inner()` access.
- **Interfaces** with static methods, default methods, and anonymous
implementations (`new Greeter() { public String greet() { ... } }`).
- **Enums** with simple constants, constants taking constructor args,
per-constant method bodies, and built-in `name()` / `ordinal()` /
`values()` / `valueOf()`.
- **Records** (`record Point(int x, int y) {}`) with auto-generated
accessors, an optional body block, and the compact-constructor form
(`Range { if (lo > hi) { ... } }`) which runs validation/normalisation
before the implicit field assignments.
- **Sealed / non-sealed / permits** with runtime-enforced permit lists:
declaring a subclass that isn't named in the parent's `permits` clause
fails at evaluation time with a clear diagnostic.
- **Pattern-matching switch statements** with type bindings:
`switch (o) { case Integer i -> useInt(i); case String s -> useStr(s); default -> ...; }`.
- **Non-static inner classes** — `class Outer { class Inner { ... } }`
works, with Inner's methods reading/writing Outer's instance fields
through the namespace chain. Construction via
`new Outer().new Inner()` is supported; `new Inner()` inside an
Outer method also works (the enclosing `this` is auto-resolved).
- **Interface method enforcement at declaration time** — a concrete
class that says `implements Iface` must provide every abstract
method Iface declares. Fires for both Java interfaces (signatures
pulled from the CN1 registry) and scripted interfaces (abstract
methods read from the interface's own `ScriptedClass`). A bare
`class Other implements ActionListener {}` now fails with
`class 'Other' is not abstract and does not implement all methods
from com.codename1.ui.events.ActionListener. Missing:
actionPerformed.`
- **Diagnostic suggestions** — missing static fields, static methods,
and instance methods on scripted classes all produce a "Did you
mean: X?" hint drawn from the relevant name table. Helps spot
typos like `Display.PICKER_TYP_DATE` or `myObj.sayz()`.

What still doesn't work:

- Reflection APIs (`java.lang.reflect.*`, `Class.forName`) — forbidden in
CN1 and out of scope.
- Cross-snippet sealed hierarchies — sealed enforcement operates on a
single snippet because the Interpreter is per-run.
- JDK surface that isn't in CN1's runtime (`Optional`, `List.of`,
`Map.of`, `Set.of`, `Stream.of`, `IntStream.range`, extended
Collectors, etc.). The playground mirrors CN1's actual API surface
rather than full JDK parity — scripts that compile here also run
on device.

### Streams

`Collection.stream()` is wired through a minimal in-process shim
(`bsh.cn1.CN1StreamBridge`) because CN1's collection backport doesn't
expose `stream()` natively. Supported intermediate ops: `filter`,
`map`, `flatMap`, `peek`, `sorted` / `sorted(Comparator)`, `distinct`,
`limit`, `skip`. Supported terminal ops: `forEach`, `count`, `collect`
(returns a `List`, ignores the collector argument), `toList`,
`toArray`, `iterator`, `anyMatch` / `allMatch` / `noneMatch`,
`findFirst` / `findAny`, `min` / `max`, `reduce(BinaryOperator)`,
`reduce(identity, BinaryOperator)`. Methods that ordinarily return
`Optional` return the value directly, or `null` when the stream is
empty — CN1's runtime omits `java.util.Optional`. `reduce` keys off
`BinaryOperator` rather than `BiFunction` for the same reason.

### Lambdas and Method References

- Lambdas in any context: assignment (`Runnable r = () -> {};`), return
expressions, method-call arguments, and as fields.
- Lambdas implement common SAM types directly: `Runnable`, `Supplier`,
`Consumer`, `BiConsumer`, `Function`, `Predicate`, `Comparator`. Other
CN1-specific listener interfaces are wrapped via `PlaygroundListenerBridge`.
- Method references for static (`System.out::println`), bound-instance
(`prefix::concat`), unbound-instance (`String::length` →
`(s) -> s.length()`), and constructor (`ArrayList::new`) forms.

### Switch and Pattern Matching

- Classic switch statements (int, String, fall-through with explicit break).
- Switch expression arrow form: `String s = switch (x) { case 1 -> "one"; default -> "?"; };`.
- Switch expression yield form: `case 1: yield "one"; default: yield "?";`.
- Arrow-form switch statements (no result value).
- Pattern matching for instanceof: `if (o instanceof String s) { use(s); }`.

### Try-with-resources, Multi-catch, var

- `try (Reader r = ...)` with single, multiple, and trailing-semicolon
resource lists.
- Multi-catch `catch (E1 | E2 e)`.
- Local variable type inference with `var` (BSH already treats `var` as a
loose type).

### Generic Type Parameters Are Erased

Generic type parameters are not enforced at runtime. Methods that rely on
specific generic types may require casting:

```java
// Generic types are erased, so explicit casting may be needed:
List<String> items = (List<String>) someMethod();
```

#### Some Java Syntax Is Unsupported

- **Enhanced for-each with arrays**: BeanShell's for-each works for `Collection` types but not for arrays when using the generated access registry. Use traditional `for (int i = 0; i < arr.length; i++)` loops for arrays, or convert to a List first:
```java
// Doesn't work with arrays:
String[] arr = {"a", "b", "c"};
for (String s : arr) { } // May fail

// Workaround:
for (int i = 0; i < arr.length; i++) { String s = arr[i]; }
// Or convert to List:
for (String s : java.util.Arrays.asList(arr)) { }
```
- **Method references**: `Object::toString` syntax is not supported; use lambdas instead
- **Try-with-resources**: Use try/finally blocks manually
### Error Diagnostics

When a static field, static method, or instance method on a scripted
class misses, the playground searches the relevant name table (CN1
registry for Java types, the scripted class's own method list for
user types) for the closest match by case-insensitive prefix or
short Levenshtein distance and appends up to three suggestions.
Typos like `Display.PICKER_TYP_DATE` surface as `... (did you mean:
PICKER_TYPE_DATE, PICKER_TYPE_DATE_AND_TIME?)`, and
`myThing.sayz()` surfaces as `No instance method Thing.sayz/0. Did
you mean: say?`.

Interface-method enforcement fires at class-declaration time, so
`class X implements ActionListener {}` fails immediately with
`Missing: actionPerformed.` rather than deferring to the first
invocation site.

### Cold-start Performance

`PlaygroundColdStartHarness` in the test sources prints baseline
timings for the cold-start phases (registry first use, first
package-helper load, first FIELD_INDEX lookup, CN1 `Display.init`,
first full `PlaygroundRunner.run`). Run it against a fresh JVM via
`java -cp ...` to catch regressions. Typical median on a dev
laptop: first registry hit ~27 ms, first `PlaygroundRunner.run`
~60 ms, CN1's own `Display.init` ~800 ms. Only the
playground-controlled phases are actionable; the rest is CN1
runtime wiring.

## JavaScript Port Considerations

Expand Down Expand Up @@ -347,9 +424,37 @@ mvn clean install

```bash
cd scripts/cn1playground
./scripts/run-tests.sh
bash tools/run-playground-smoke-tests.sh
```

This smoke command currently runs:

1. CN1 access registry generation (`tools/generate-cn1-access-registry.sh`).
2. Registry sanity checks (expected/forbidden class entries).
3. `PlaygroundSmokeHarness` end-to-end behavior checks.
4. `PlaygroundSyntaxMatrixHarness` syntax regression checks.

## Language Feature Rollout Process

Use this process when adding or fixing Java syntax support in Playground:

1. **Add/adjust matrix coverage first**
Update `common/src/test/java/com/codenameone/playground/PlaygroundSyntaxMatrixHarness.java` with a focused snippet for the target syntax.
- For currently unsupported syntax, add as `ExpectedOutcome.FAILURE`.
- When support lands, flip that case to `ExpectedOutcome.SUCCESS`.

2. **Implement parser/runtime change in small steps**
Prefer one syntax feature per PR (e.g. method references only) to keep regressions easy to isolate.

3. **Run smoke + syntax matrix locally**
Run `bash tools/run-playground-smoke-tests.sh` from `scripts/cn1playground`.

4. **Require CI green before merge**
The `CN1 Playground Language Tests` workflow runs the same smoke command under CI (`xvfb-run`) and should pass before merging syntax updates.

5. **Document behavior changes**
Update this README's known issues/limitations when syntax support changes so users know what is now supported.

## Known Issues

1. **Parse errors with complex expressions**: BeanShell's parser may fail on some Java syntax. Simplify complex expressions or break them into multiple statements.
Expand All @@ -360,4 +465,4 @@ cd scripts/cn1playground

## Contributing

See the main Codename One repository for contribution guidelines.
See the main Codename One repository for contribution guidelines.
Loading
Loading