Skip to content

Commit 5c58819

Browse files
committed
Fix: ignore non-Node containments in Lionweb trees (e.g. Position)
1 parent 7f8208d commit 5c58819

File tree

3 files changed

+46
-24
lines changed

3 files changed

+46
-24
lines changed

src/interop/ecore.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import {
99
Node,
1010
NODE_TYPES, NodeDefinition,
1111
PackageDescription,
12-
PropertyDefinition,
12+
Feature,
1313
registerNodeDefinition,
1414
registerNodeAttribute
1515
} from "../model/model";
@@ -946,8 +946,8 @@ export class ECoreNode extends NodeAdapter implements PossiblyNamed {
946946
return this.eo.eContainingFeature?.get("name");
947947
}
948948

949-
getFeatures(): { [name: string | symbol]: PropertyDefinition } {
950-
const result: { [name: string | symbol]: PropertyDefinition } = {};
949+
getFeatures(): { [name: string | symbol]: Feature } {
950+
const result: { [name: string | symbol]: Feature } = {};
951951
const eClass = this.eo.eClass;
952952
const features = eClass.get("eAllStructuralFeatures");
953953
for (const ft of features) {

src/interop/lionweb.ts

+32-15
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,24 @@ import {
66
Classifier,
77
Concept,
88
Containment,
9-
Feature,
9+
Feature as LWFeature,
1010
Id,
1111
InstantiationFacade,
1212
Interface,
1313
Language,
14-
Node as LionwebNodeInterface
14+
Node as LWNodeInterface
1515
} from "@lionweb/core";
16-
import {NodeAdapter, Issue, Node, NodeDefinition, Position, PropertyDefinition} from "..";
16+
import {NodeAdapter, Issue, Node, NodeDefinition, Position, Feature} from "..";
1717
import {STARLASU_LANGUAGE} from "./lionweb-starlasu-language";
1818
export {STARLASU_LANGUAGE} from "./lionweb-starlasu-language";
1919

20-
export class TylasuNodeWrapper implements LionwebNodeInterface {
20+
export const ASTNode = STARLASU_LANGUAGE.entities.find(e => e.name == "ASTNode")!;
21+
22+
export class TylasuNodeWrapper implements LWNodeInterface {
2123
id: Id;
2224
node: Node;
23-
parent?: LionwebNodeInterface;
24-
annotations: LionwebNodeInterface[];
25+
parent?: LWNodeInterface;
26+
annotations: LWNodeInterface[];
2527
}
2628

2729
export class LanguageMapping {
@@ -43,11 +45,23 @@ export class LanguageMapping {
4345
}
4446
}
4547

46-
function featureToProperty(feature: Feature): PropertyDefinition {
47-
const def: PropertyDefinition = { name: feature.name };
48+
function isASTNode(classifier: Classifier) {
49+
return (classifier instanceof Concept) &&
50+
(classifier.key == ASTNode.key || (classifier.extends && isASTNode(classifier.extends)));
51+
}
52+
53+
function importFeature(feature: LWFeature): Feature | undefined {
54+
const def: Feature = { name: feature.name };
4855
if (feature instanceof Containment) {
49-
def.child = true;
50-
def.multiple = feature.multiple;
56+
if (isASTNode(feature.classifier)) {
57+
def.child = true;
58+
def.multiple = feature.multiple;
59+
} else {
60+
// TODO we assume that:
61+
// 1) we're importing a StarLasu AST
62+
// 2) containments in a StarLasu AST are either AST nodes or internal StarLasu objects like the position
63+
return undefined;
64+
}
5165
}
5266
return def
5367
}
@@ -81,7 +95,7 @@ export class TylasuInstantiationFacade implements InstantiationFacade<TylasuNode
8195
annotations: []
8296
};
8397
}
84-
setFeatureValue(node: TylasuNodeWrapper, feature: Feature, value: unknown): void {
98+
setFeatureValue(node: TylasuNodeWrapper, feature: LWFeature, value: unknown): void {
8599
if (feature instanceof Containment) {
86100
if (feature.multiple) {
87101
node.node.addChild(feature.name, (value as TylasuNodeWrapper)?.node);
@@ -132,16 +146,19 @@ export class LionwebNode extends NodeAdapter {
132146

133147
constructor(
134148
public readonly classifier: Classifier,
135-
protected lwnode: LionwebNodeInterface
149+
protected lwnode: LWNodeInterface
136150
) {
137151
super();
138-
const properties = {};
152+
const features = {};
139153
allFeatures(classifier).forEach(f => {
140-
properties[f.name] = featureToProperty(f);
154+
const feature = importFeature(f);
155+
if (feature) {
156+
features[f.name] = feature;
157+
}
141158
});
142159
this._nodeDefinition = {
143160
name: classifier.name,
144-
features: properties,
161+
features,
145162
resolved: true
146163
};
147164
}

src/model/model.ts

+11-6
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,11 @@ export const NODE_TYPES: { [name: string]: PackageDescription } = {
1515
export type NodeDefinition = {
1616
package?: string,
1717
name?: string,
18-
features: { [name: string | symbol]: PropertyDefinition },
18+
features: { [name: string | symbol]: Feature },
1919
resolved?: boolean;
2020
};
2121

22-
export type PropertyDefinition = {
22+
export type Feature = {
2323
name: string | symbol,
2424
child?: boolean,
2525
multiple?: boolean,
@@ -29,6 +29,11 @@ export type PropertyDefinition = {
2929
arrayType?: any
3030
}
3131

32+
/**
33+
* @deprecated replaced by Feature
34+
*/
35+
export type PropertyDefinition = Feature;
36+
3237
export function getNodeDefinition(node: Node | (abstract new (...args: any[]) => Node)): NodeDefinition {
3338
const target = typeof node === "function" ? node : node.constructor;
3439
let definition: NodeDefinition;
@@ -174,7 +179,7 @@ export abstract class Node extends Origin implements Destination {
174179
});
175180
}
176181

177-
containment(name: string | symbol): PropertyDefinition | undefined {
182+
containment(name: string | symbol): Feature | undefined {
178183
const props = this.nodeDefinition?.features || {};
179184
return props[name]?.child ? props[name] : undefined;
180185
}
@@ -457,7 +462,7 @@ export function ensureNodeDefinition(node: Node | { new (...args: any[]): Node }
457462

458463
export function registerNodeAttribute<T extends Node>(
459464
type: { new(...args: any[]): T }, methodName: string | symbol
460-
): PropertyDefinition {
465+
): Feature {
461466
if (methodName == "parent" || methodName == "children" || methodName == "origin") {
462467
methodName = Symbol(methodName);
463468
}
@@ -471,15 +476,15 @@ export function registerNodeAttribute<T extends Node>(
471476
}
472477

473478
export function registerNodeChild<T extends Node>(
474-
type: new (...args: any[]) => T, methodName: string, multiple: boolean = false): PropertyDefinition {
479+
type: new (...args: any[]) => T, methodName: string, multiple: boolean = false): Feature {
475480
const propInfo = registerNodeAttribute(type, methodName);
476481
propInfo.child = true;
477482
propInfo.multiple = multiple;
478483
return propInfo;
479484
}
480485

481486
export function registerNodeReference<T extends Node & PossiblyNamed>(
482-
type: new (...args: any[]) => T, methodName: string): PropertyDefinition {
487+
type: new (...args: any[]) => T, methodName: string): Feature {
483488
const propInfo = registerNodeAttribute(type, methodName);
484489
propInfo.reference = true;
485490
return propInfo;

0 commit comments

Comments
 (0)