Skip to content

Commit 53506f0

Browse files
committed
Handling of references in ECore TraceNodes and Nodes in general #61
1 parent 9377e98 commit 53506f0

11 files changed

+200
-74
lines changed

CHANGELOG.md

+14
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,20 @@
22
All notable changes to this project from version 1.2.0 upwards are documented in this file.
33
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
44

5+
## [1.6.13] – 2024-03-14
6+
7+
### Added
8+
- `Node.getReference` method as in Kolasu
9+
10+
### Changed
11+
- Renamed `Node.getAttribute` to `getAttributeValue` in accordance with Kolasu
12+
13+
### Fixed
14+
- Proper handling of references in ECore
15+
16+
### Removed
17+
- The `ParserNode` class, replaced by its superclass `TraceNode` that's now a concrete class.
18+
519
## [1.6.12] – 2024-03-07
620

721
### Added

package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"description": "AST building blocks for TypeScript/JavaScript, part of the *lasu family, with optional integrations with ANTLR4 and Ecore.",
44
"author": "Strumenta s.r.l.",
55
"publisher": "strumenta",
6-
"version": "1.6.12",
6+
"version": "1.6.13",
77
"license": "Apache-2.0",
88
"keywords": [
99
"antlr",
@@ -82,7 +82,7 @@
8282
"reflect-metadata": "^0.1.13"
8383
},
8484
"peerDependencies": {
85-
"@lionweb/core": "^0.6.1",
85+
"@lionweb/core": "^0.6.2",
8686
"antlr4ng": "^2.0.3",
8787
"cmd-ts": "^0.11.0",
8888
"ecore": "^0.12.0"

src/interop/ecore.ts

+49-14
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ import {KOLASU_URI_V1, THE_NODE_ECLASS as THE_NODE_ECLASS_V1} from "./kolasu-v1-
4242
import {EBigDecimal, EBigInteger} from "./ecore-patching";
4343
import {NodeAdapter} from "../trace/trace-node";
4444
import {EClassifier} from "ecore";
45+
import {PossiblyNamed, ReferenceByName} from "../model/naming";
4546

4647
export * as starlasu_v2 from "./starlasu-v2-metamodel";
4748
export * as kolasu_v1 from "./kolasu-v1-metamodel";
@@ -518,7 +519,7 @@ export function loadEPackages(data: any, resource: ECore.Resource): ECore.EPacka
518519
}
519520

520521
interface PostponedReference {
521-
eObject: ECore.EObject, feature: any, refValue: any
522+
eObject: ECore.EObject, feature: any, refName: string | undefined, refValue: any
522523
}
523524

524525
/**
@@ -530,19 +531,24 @@ class ReferencesTracker {
530531
constructor(public resource: ECore.Resource) {
531532
}
532533

533-
trackReference(eObject: ECore.EObject, feature: any, refValue: any) : void {
534-
this.postponedReferences.push({eObject, feature, refValue});
534+
trackReference(eObject: ECore.EObject, feature: any, refName: string | undefined, refValue: any) : void {
535+
this.postponedReferences.push({eObject, feature, refName: refName, refValue});
535536
}
536537

537538
resolveAllReferences() : void {
538-
this.postponedReferences.forEach((pr)=>{
539+
this.postponedReferences.forEach((pr)=> {
539540
this.resolveReference(pr);
540541
});
541542
this.postponedReferences = [];
542543
}
543544

544545
resolveReference(pr: PostponedReference) {
545-
if (pr.feature.get('upperBound') !== 1) {
546+
if (pr.refName) {
547+
pr.eObject.set(pr.feature, THE_REFERENCE_BY_NAME_ECLASS.create({
548+
name: pr.refName,
549+
referenced: pr.refValue ? this.getReferredObject(pr.refValue["$ref"]) : undefined
550+
}));
551+
} else if (pr.feature.get('upperBound') !== 1) {
546552
const list = pr.eObject.get(pr.feature);
547553
pr.refValue.forEach(ref => {
548554
list.add(this.getReferredObject(ref.$ref));
@@ -770,20 +776,15 @@ function importJsonObject(
770776
if (eGenericType) {
771777
eType = eGenericType.get("eClassifier");
772778
if (eType == THE_REFERENCE_BY_NAME_ECLASS) {
773-
//eType = eGenericType.get("eTypeArguments").at(0).get("eClassifier");
774-
const refValue = obj[key].referenced;
775-
if (refValue) {
776-
referencesTracker.trackReference(eObject, feature, refValue);
777-
}
779+
referencesTracker.trackReference(eObject, feature, obj[key].name, obj[key].referenced);
778780
continue;
779781
}
780782
}
781783
}
782784
if (feature.get("containment") === true) {
783785
setChild(feature, obj, key, eObject, resource, eType, strict, referencesTracker, eClass);
784786
} else if (feature.isKindOf(ECore.EReference)) {
785-
const refValue = obj[key];
786-
referencesTracker.trackReference(eObject, feature, refValue);
787+
referencesTracker.trackReference(eObject, feature, undefined, obj[key]);
787788
} else {
788789
throw featureError("The feature is neither a containment nor a reference", key, eClass, resource);
789790
}
@@ -824,7 +825,7 @@ export interface EcoreMetamodelSupport {
824825
generateMetamodel(resource: ECore.Resource, includingKolasuMetamodel: boolean): void;
825826
}
826827

827-
export class ECoreNode extends NodeAdapter {
828+
export class ECoreNode extends NodeAdapter implements PossiblyNamed {
828829

829830
parent?: ECoreNode;
830831

@@ -838,6 +839,10 @@ export class ECoreNode extends NodeAdapter {
838839
}
839840
}
840841

842+
get name(): string | undefined {
843+
return this.getAttributeValue("name");
844+
}
845+
841846
private _nodeDefinition?: NodeDefinition;
842847

843848
get nodeDefinition() {
@@ -863,7 +868,7 @@ export class ECoreNode extends NodeAdapter {
863868
}
864869
}
865870

866-
getAttribute(name: string): any {
871+
getAttributeValue(name: string): any {
867872
return this.eo.get(name);
868873
}
869874

@@ -885,6 +890,36 @@ export class ECoreNode extends NodeAdapter {
885890
return this._children!.filter(c => !role || c.getRole() == role);
886891
}
887892

893+
protected doGetChildOrChildren(name: string | symbol): ECoreNode | ECoreNode[] | undefined {
894+
const containment = this.containment(name);
895+
const children = this.getChildren(name.toString());
896+
if (!containment?.multiple) {
897+
if (children) {
898+
return children[0];
899+
} else {
900+
return undefined;
901+
}
902+
} else {
903+
return children;
904+
}
905+
}
906+
907+
getReference(name: string | symbol): ReferenceByName<ECoreNode> | undefined {
908+
const ref = this.eo.get(name.toString());
909+
if (ref) {
910+
if (ref.isKindOf(THE_REFERENCE_BY_NAME_ECLASS)) {
911+
const referred = ref.get("referenced");
912+
return new ReferenceByName<any>(ref.get("name"), referred ? new ECoreNode(referred) : undefined);
913+
} else {
914+
const error = new Error(`Not a reference: ${name.toString()}`) as any;
915+
error.object = ref;
916+
throw error;
917+
}
918+
} else {
919+
return undefined;
920+
}
921+
}
922+
888923
getId(): string {
889924
return this.eo.fragment();
890925
}

src/interop/lionweb.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ export class TylasuInstantiationFacade implements InstantiationFacade<TylasuNode
8989
node.node.setChild(feature.name, (value as TylasuNodeWrapper)?.node);
9090
}
9191
} else {
92-
node.node.setAttribute(feature.name, value);
92+
node.node.setAttributeValue(feature.name, value);
9393
}
9494
}
9595
}
@@ -166,7 +166,7 @@ export class LionwebNode extends NodeAdapter {
166166
const attributes = {};
167167
for (const p in this.nodeDefinition.properties) {
168168
if (!this.nodeDefinition.properties[p].child) {
169-
attributes[p] = this.getAttribute(p);
169+
attributes[p] = this.getAttributeValue(p);
170170
}
171171
}
172172
return attributes;

src/interop/strumenta-playground.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ export class ParserTrace {
6868
}
6969

7070
get name(): string | undefined {
71-
return this.node.getAttribute("name");
71+
return this.node.getAttributeValue("name");
7272
}
7373
}
7474

@@ -178,7 +178,7 @@ export class TranspilationTrace extends AbstractTranspilationTrace {
178178
}
179179

180180
get name(): string | undefined {
181-
return this.wrappedNode.getAttribute("name");
181+
return this.wrappedNode.getAttributeValue("name");
182182
}
183183
}
184184

@@ -206,19 +206,19 @@ export class WorkspaceTranspilationTrace extends AbstractTranspilationTrace {
206206
}
207207

208208
get name(): string | undefined {
209-
return this.wrappedNode.getAttribute("name");
209+
return this.wrappedNode.getAttributeValue("name");
210210
}
211211
}
212212

213213
abstract class AbstractWorkspaceFile<N> {
214214
protected constructor(protected wrappedNode: NodeAdapter, protected trace: AbstractTranspilationTrace) {}
215215

216216
get path(): string {
217-
return this.wrappedNode.getAttribute("path");
217+
return this.wrappedNode.getAttributeValue("path");
218218
}
219219

220220
get code(): string {
221-
return this.wrappedNode.getAttribute("code");
221+
return this.wrappedNode.getAttributeValue("code");
222222
}
223223

224224
get issues(): Issue[] {

src/model/model.ts

+12-7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import {Position} from "./position";
22
import "reflect-metadata";
3+
import {ReferenceByName} from "./naming";
34

45
export const NODE_DEFINITION_SYMBOL = Symbol("nodeDefinition");
56

@@ -163,7 +164,7 @@ export abstract class Node extends Origin implements Destination {
163164
return Object.getOwnPropertyNames(props).map(p => {
164165
const value = props[p].child ?
165166
(props[p].multiple ? this.getChildren(p) : this.getChild(p)) :
166-
this.getAttribute(p);
167+
this.getAttributeValue(p);
167168
return { name: p, value };
168169
});
169170
}
@@ -270,42 +271,46 @@ export abstract class Node extends Origin implements Destination {
270271
}
271272
}
272273

273-
getAttribute(name: string | symbol): any {
274+
getAttributeValue(name: string | symbol): any {
274275
const props = this.nodeDefinition?.properties || {};
275276
const prop = props[name];
276277
if(prop) {
277278
if (prop.child) {
278279
throw new Error(name.toString() + " is a containment, please use getChild");
279280
} else {
280-
return this.doGetAttribute(name);
281+
return this.doGetAttributeValue(name);
281282
}
282283
} else {
283284
throw new Error(`${name.toString()} is not a feature of ${this} (${this.nodeDefinition}).`);
284285
}
285286
}
286287

287-
setAttribute(name: string | symbol, value: any) {
288+
setAttributeValue(name: string | symbol, value: any) {
288289
const props = this.nodeDefinition?.properties || {};
289290
const prop = props[name];
290291
if(prop) {
291292
if (prop.child) {
292293
throw new Error(name.toString() + " is a containment, please use setChild/addChild");
293294
} else {
294-
this.doSetAttribute(name, value);
295+
this.doSetAttributeValue(name, value);
295296
}
296297
} else {
297298
throw new Error(`${name.toString()} is not a feature of ${this} (${this.nodeDefinition}).`);
298299
}
299300
}
300301

301-
protected doSetAttribute(name: string | symbol, value: any) {
302+
protected doSetAttributeValue(name: string | symbol, value: any) {
302303
this[name] = value;
303304
}
304305

305-
protected doGetAttribute(name: string | symbol) {
306+
protected doGetAttributeValue(name: string | symbol) {
306307
return this[name];
307308
}
308309

310+
getReference(name: string | symbol): ReferenceByName<any> | undefined {
311+
return this[name] as ReferenceByName<any>;
312+
}
313+
309314
withParent(parent?: Node): this {
310315
this.parent = parent;
311316
return this;

0 commit comments

Comments
 (0)