Skip to content

fix: faithful ==/nested-arithmetic codegen in scope/export expression translation (follow-up to #1405)#1436

Draft
joaodinissf wants to merge 2 commits into
dsldevkit:masterfrom
joaodinissf:followup/scope-expression-codegen-test
Draft

fix: faithful ==/nested-arithmetic codegen in scope/export expression translation (follow-up to #1405)#1436
joaodinissf wants to merge 2 commits into
dsldevkit:masterfrom
joaodinissf:followup/scope-expression-codegen-test

Conversation

@joaodinissf

Copy link
Copy Markdown
Collaborator

⚠️ Stacked on #1405 (does not touch its commits). Until #1405 merges, this PR's diff also shows #1405's commits; the net change here is the single follow-up commit 8e6fff410. Will rebase to a clean diff once #1405 lands.

What

Restores two behaviours the Xbase migration (#1405) silently changed in the scope/export expression code generators. Both are latent (no in-repo .scope/.export instance hits them; the only generated providers in the repo are expression-free), which is precisely why CI didn't catch them — #1405 also deleted CodeGenerationXTest, the test that pinned this.

  1. ==/!= reference equality. The translator linked ==/!= to ObjectExtensions.operator_equals/notEquals → Xbase inlines to Objects.equals(a, b) (null-safe value equality). The legacy generator — and this PR's own string fallback compiler — emit Java reference equality a == b. The inferrer prefers the translated XExpression, so value-equality won, silently changing cross-reference-resolution semantics for EObject operands. Fix: leave ==/!= untranslated so they fall to the faithful string compiler (raw a == b). The relational operators < > <= >= were already left untranslated, so this also makes the operator family consistent.

  2. Nested arithmetic. isNumber() delegated to resolveType(), which returns null for an OperationCall operand, so a nested arithmetic operand (the (a + b) in (a + b) * c) wasn't "numeric"; the outer operator missed the arithmetic branch and emitted operator-as-method — *(a + b, c), non-compilable. Fix: isNumber() now recognises an arithmetic OperationCall as numeric, restoring (a + b) * c.

Applied symmetrically to scope and export; removes the now-unused ObjectExtensions import.

Evidence

A standalone replica of the compiler's classification/emission confirms the change red→green: (4 + 2) * 3 goes from *(4 + 2, 3) (malformed) → (4 + 2) * 3, and 1 == 2 emits raw 1 == 2. Next commit: a new scope.test module with a CodeGenerationXTest-style regression test (re-introducing the coverage #1405 dropped) so this is guarded in CI.

🤖 Generated with Claude Code

rubenporras and others added 2 commits June 18, 2026 14:03
The com.avaloq.tools.ddk.xtext.scope plugin compiled the embedded
Expression DSL to Java through expression.generator.CodeGenerationX /
CompilationContext, whose type system is the legacy classic Xtend
runtime (org.eclipse.xtend.expression.*,
org.eclipse.xtend.typesystem.emf.*). That was the only reason the plugin
required those bundles.

This PR replaces the IGenerator2-based ScopeGenerator with an Xbase
JvmModelInferrer, introduces a self-contained (Xtend-free)
expression-translation layer, deletes the classic-Xtend execution
context, and removes org.eclipse.xtend and
org.eclipse.xtend.typesystem.emf from the scope plugin.

Key decisions

Scope generation moves to a JvmModelInferrer + Xbase
JvmModelGenerator	Same pattern as Format/Check; lets the standard
XbaseCompiler emit the provider classes. The
*ScopeProvider/*ScopeNameProvider are now inferred JVM types rather than
hand-templated .java.

Hybrid expression backend: an Xbase translator + a string compiler
fallback	String + concatenation (very common in .scope) has no
operator_plus in xbase.lib — Xbase special-cases it in its compiler — so
it can't be pre-linked as an XExpression tree. We translate to Xbase
what maps cleanly and fall back to a faithful port of the legacy string
output for +, arithmetic and relational operators.

Model-type names resolve via imported EPackages, not the classpath	In
real sources, (Cast)x / typeSelect(T) / T.isInstance(x) name EMF model
types (FormDef, ILogicalTable, intfdef::AlternatingGroup), not Java
FQNs. javaType resolves them through the model's imported EPackages →
GenModelUtilX.instanceClassName, exactly as the legacy
EmfRegistryMetaModel did. findDeclaredType would fail on these.

.ext (JAVA extension) support dropped	Scope sources no longer reference
Xtend extension files; removed the .ext-reading validation and the
isJavaExtensionCall/isExtension generator branches.

factory becomes a direct Xbase static call	Must be written
Type.method(args); the generator resolves the type to a
JvmDeclaredType.qualifiedName and emits the static call. Bare factory
foo() is no longer supported.

Downstream projects need to adapt their .scope/.ext sources.
…rt expression translation

Follow-up to dsldevkit#1405 (does NOT touch its commits): restores two behaviours the
Xbase migration silently changed in the scope/export expression code generators.

1. ==/!= reference equality. The translator linked == / != to
   ObjectExtensions.operator_equals/notEquals, which Xbase inlines to
   Objects.equals(a, b) (null-safe VALUE equality). The legacy generator - and
   this PR's own string fallback compiler - emit Java reference equality (a == b).
   Since the inferrer prefers the translated XExpression, the value-equality path
   won, silently changing cross-reference resolution semantics for EObject
   operands. Fix: leave == / != untranslated so they fall through to the faithful
   string compiler (raw a == b). The relational operators < > <= >= were already
   left untranslated, so this also makes the operator family consistent.

2. Nested arithmetic. isNumber() delegated to resolveType(), which returns null
   for an OperationCall operand, so a nested arithmetic operand (e.g. the (a + b)
   in (a + b) * c) was not "numeric"; the outer operator then missed the
   arithmetic branch and was emitted as operator-as-method, e.g. *(a + b, c) -
   non-compilable Java. Fix: isNumber() now recognises an arithmetic
   OperationCall as numeric, restoring (a + b) * c.

Applied symmetrically to scope and export; removes the now-unused ObjectExtensions
import. A scope.test module with a CodeGenerationXTest-style regression test
(re-introducing the coverage dsldevkit#1405 dropped) follows in the next commit.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants