-
Tag: @msujew Example Project: Entities DSL Repo I'm attempting to implement a custom formatter by extending the AbstractFormatter as shown in the Domain example. The formatter should insert two newlines after each Example Text: entity MyFirstEntity {
string s;
int[10] a;
}
entity MySecondEntity extends MyFirstEntity {
MyFirstEntity e;
} import { AbstractFormatter, Formatting } from 'langium';
import * as ast from './generated/ast';
export class EntitiesFormatter extends AbstractFormatter {
protected format(model: ast.Model): void {
const lastEntity = model.entities[model.entities.length - 1];
model.entities.forEach(entity => {
const formatter = this.getNodeFormatter(entity);
const node = formatter.node(entity);
if (entity === lastEntity) {
node.append(Formatting.newLine());
} else {
node.append(Formatting.newLines(2));
}
});
}
} Invoking the format command in VSCode using
While intuitively I assume it's complaining about trying to read the array length, I'm not sure how I would implement it differently. |
Beta Was this translation helpful? Give feedback.
Replies: 3 comments 8 replies
-
Tag: @msujew Disregard - I'll leave this here in case anyone else is curious. I'm assuming that since we don't have dynamic dispatch (Xtend) that means that we have to call protected format(node: AstNode): void {
if (ast.isModel(node)) {
const lastEntity = node.entities[node.entities.length - 1];
node.entities.forEach(entity => {
const formatter = this.getNodeFormatter(entity);
const node = formatter.node(entity);
if (entity === lastEntity) {
node.append(Formatting.newLine());
} else {
node.append(Formatting.newLines(5));
}
});
}
} |
Beta Was this translation helpful? Give feedback.
-
This seems to be mostly working. For some add'l context - this is what I'm trying to "port" for lack of better words: class EntitiesFormatter extends AbstractFormatter2 {
@Inject extension EntitiesGrammarAccess
def dispatch void format(Model model, extension IFormattableDocument document) {
val lastEntity = model.entities.last
for (entity : model.entities) {
entity.format
if (entity === lastEntity)
entity.append[setNewLines(1)]
else
entity.append[setNewLines(2)]
}
}
def dispatch void format(Entity entity, extension IFormattableDocument document) {
entity.regionFor.keyword("extends").surround[oneSpace]
entity.regionFor.feature(ENTITY__NAME).surround[oneSpace]
entity.regionFor.feature(ENTITY__SUPER_TYPE).surround[oneSpace]
val open = entity.regionFor.keyword(entityAccess.leftCurlyBracketKeyword_3)
val close = entity.regionFor.keyword("}")
open.append[newLine]
interior(open, close)[indent]
for (attribute : entity.attributes) {
attribute.type.format(document)
attribute.regionFor.keyword(";").surround[noSpace]
attribute.append[setNewLines(1, 1, 2)]
}
}
def dispatch void format(AttributeType attributeType, extension IFormattableDocument document) {
if (!attributeType.array) {
attributeType.elementType.append[oneSpace]
} else {
attributeType.regionFor.keyword("[").surround[noSpace]
attributeType.regionFor.keyword("]").prepend[noSpace].append[oneSpace]
}
}
} export class EntitiesFormatter extends AbstractFormatter {
protected format(node: AstNode): void {
if (ast.isModel(node)) {
const lastEntity = node.entities[node.entities.length - 1];
node.entities.forEach(entity => {
const formatter = this.getNodeFormatter(entity);
const node = formatter.node(entity);
if (entity === lastEntity) {
node.append(Formatting.newLine());
} else {
node.append(Formatting.newLines(2));
}
});
} else if (ast.isEntity(node)) {
const formatter = this.getNodeFormatter(node);
formatter.keyword("extends").surround(Formatting.oneSpace());
// entity name
// entity superType
const bracesOpen = formatter.keyword("{");
const bracesClose = formatter.keyword("}");
bracesOpen.append(Formatting.newLine());
formatter.interior(bracesOpen, bracesClose).prepend(Formatting.indent());
node.attributes.forEach(attribute => {
const formatter = this.getNodeFormatter(attribute.type);
const node = formatter.node(attribute);
formatter.keyword(";").surround(Formatting.noSpace());
node.append(Formatting.newLine());
});
} else if (ast.isAttributeType(node)) {
const formatter = this.getNodeFormatter(node);
if (!node.array) {
const elem = formatter.node(node.entity);
elem.append(Formatting.oneSpace());
} else {
formatter.keyword("[").surround(Formatting.noSpace());
formatter.keyword("]").prepend(Formatting.noSpace()).append(Formatting.oneSpace());
}
}
}
} |
Beta Was this translation helpful? Give feedback.
-
Tag: @msujew I'll just tag this here ... working through some example parser unit tests and what seems like a straightforward object equality check results in a heap error. It's not completely obvious to me why this explodes ... Grammar:
Unit Test ( ... this goes boom ... ):test('Parse: VariableReference', async () => {
const text=`
var i = 10
eval i`;
const parse = await helper(text);
const elements = parse.parseResult.value.elements;
expect((elements[elements.length - 1].expression as VariableRef).variable).toEqual(elements[0]);
}); Note: As a work around (which I think accomplishes the intent of testing the reference), I used the following, which seemed to work. expect((elements[elements.length - 1].expression as VariableRef).variable.ref?.name).toBe('i') |
Beta Was this translation helpful? Give feedback.
Tag: @msujew
Disregard - I'll leave this here in case anyone else is curious. I'm assuming that since we don't have dynamic dispatch (Xtend) that means that we have to call
format()
on all of the nodes of the AST and select which nodes to apply formatting to using the utilityisSomeType()
function. Please feel free to clarify if I'm off the mark.