Skip to content

Commit

Permalink
Modelunit can implement interfaces
Browse files Browse the repository at this point in the history
  • Loading branch information
joswarmer committed Jul 1, 2023
1 parent 9259f79 commit 032c90e
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ export class UnitTemplate {
.concat([Names.FreModelUnit, Names.FreParseLocation])
.concat(hasReferences ? (Names.FreNodeReference) : null);
const metaType = Names.metaType(language);
const intfaces = Array.from(
new Set(
unitDescription.interfaces.map(i => Names.interface(i.referred))
)
);

// Template starts here. Note that the imports are gathered during the generation, and added later.
const result: string = `
Expand All @@ -29,13 +34,13 @@ export class UnitTemplate {
* It uses mobx decorators to enable parts of the language environment, e.g. the editor, to react
* to any changes in the state of its properties.
*/
export class ${myName} extends ${extendsClass} implements ${Names.FreModelUnit} {
export class ${myName} extends ${extendsClass} implements ${Names.FreModelUnit}${intfaces.map(imp => `, ${imp}`).join("")} {
${ConceptUtils.makeStaticCreateMethod(unitDescription, myName)}
fileExtension: string;
${ConceptUtils.makeBasicProperties(metaType, myName, false)}
${unitDescription.primProperties.map(p => ConceptUtils.makePrimitiveProperty(p)).join("\n")}
${unitDescription.implementedPrimProperties().map(p => ConceptUtils.makePrimitiveProperty(p)).join("\n")}
${unitDescription.parts().map(p => ConceptUtils.makePartProperty(p)).join("\n")}
${unitDescription.references().map(p => ConceptUtils.makeReferenceProperty(p)).join("\n")}
Expand All @@ -56,6 +61,7 @@ export class UnitTemplate {
return Array.from(
new Set(
unitDescription.parts().map(part => Names.classifier(part.type))
.concat(unitDescription.interfaces.map(intf => Names.interface((intf.referred))))
.concat(unitDescription.references().map(part => Names.classifier(part.type)))
.concat(Names.metaType(unitDescription.language))
.filter(name => !(name === myName))
Expand Down
33 changes: 33 additions & 0 deletions packages/meta/src/languagedef/metalanguage/FreLanguage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,8 +131,41 @@ export class FreModelDescription extends FreClassifier {
}

export class FreUnitDescription extends FreClassifier {
interfaces: MetaElementReference<FreInterface>[] = []; // the interfaces that this concept implements

fileExtension: string = "";
isPublic: boolean = true;

/**
* Returns a list of properties that are either (1) defined in this concept or (2) in one of the interfaces
* that is implemented by this concept. Excluded are properties that are defined in an interface but are already
* included in one of the base concepts.
*/
implementedPrimProperties(): FrePrimitiveProperty[] {
let result: FrePrimitiveProperty[] = []; // return a new array!
result.push(...this.primProperties);
for (const intf of this.interfaces) {
for (const intfProp of intf.referred.allPrimProperties()) {
let allreadyIncluded = false;
// if the prop from the interface is present in this concept, do not include
allreadyIncluded = this.primProperties.some(p => p.name === intfProp.name );
// TODO The next lines are only needed if units can have other units as base classes
// if the prop from the interface is present in the base of this concept (resursive), do not include
// if (!allreadyIncluded && !!this.base && !!this.base.referred) {
// allreadyIncluded = this.base.referred.allPrimProperties().some(p => p.name === intfProp.name);
// }
// if the prop from the interface is present in another implemented interface, do not include
if (!allreadyIncluded) {
allreadyIncluded = result.some(p => p.name === intfProp.name );
}
if (!allreadyIncluded) {
result = result.concat(intfProp);
}
}
}
return result;
}

}

export class FreInterface extends FreClassifier {
Expand Down
6 changes: 6 additions & 0 deletions packages/meta/src/languagedef/parser/LanguageCreators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,12 @@ export function createUnit(data: Partial<FreUnitDescription>): FreUnitDescriptio
prop.owningClassifier = result;
}
}
if (!!data.interfaces) {
result.interfaces = data.interfaces;
for (const intf of result.interfaces) {
intf.owner = result;
}
}
if (!!data.fileExtension) {
result.fileExtension = data.fileExtension;
}
Expand Down
20 changes: 15 additions & 5 deletions packages/meta/src/languagedef/parser/LanguageGrammar.part.pegjs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Language_Definition
"concepts": langparts,
"location": location()
});
}
}

abstractKey = "abstract" rws { return true; }
modelKey = "model" rws { return true; }
Expand Down Expand Up @@ -39,17 +39,24 @@ model = isModel:modelKey name:var
});
}
unit = isUnit:unitKey name:var
curly_begin props:property* fileExtension:(fileExtensionKey equals_separator "\"" fileExt:var "\"" semicolon_separator {return fileExt;})? curly_end {
unit = isUnit:unitKey name:var ws implementedInterfaces:implementedInterfaces?
curly_begin
props:property*
fileExtension:(fileExtensionKey equals_separator "\"" fileExt:var "\"" semicolon_separator {return fileExt;})?
curly_end {
return create.createUnit({
"name": name,
"properties": props,
"interfaces": implementedInterfaces,
"fileExtension": (!!fileExtension ? fileExtension : ""),
"location": location()
});
}
concept = abs:abstractKey? conceptKey name:var rws base:conceptbase? ws implementedInterfaces:implementedInterfaces? curly_begin props:property* curly_end
concept = abs:abstractKey? conceptKey name:var rws base:conceptbase? ws implementedInterfaces:implementedInterfaces?
curly_begin
props:property*
curly_end
{
return create.createConcept({
"isAbstract": (!!abs),
Expand All @@ -74,7 +81,10 @@ limited = abs:abstractKey? limitedKey ws name:var rws base:conceptbase? ws imple
});
}
interface = interfaceKey ws name:var rws base:interfacebase? curly_begin props:property* curly_end
interface = interfaceKey ws name:var rws base:interfacebase?
curly_begin
props:property*
curly_end
{
return create.createInterface({
"name": name,
Expand Down

0 comments on commit 032c90e

Please sign in to comment.