eclipse-langium / langium

Next-gen language engineering / DSL framework
https://langium.org/
MIT License
725 stars 65 forks source link

Add another CompositeGeneratorNode#indent overload #1295

Open tomsontom opened 10 months ago

tomsontom commented 10 months ago

Proposal

I'd like to propse to add another overload method

indent<T>(children: ((indented: IndentNode, value: T) => void), value: T | T[]): this;

allowing me to directly pass a function instead of writing a closure.

Reason

While writing my code generator I found that I could have written more consise code if could directly pass a function to indent just to pass on a value/list of values to operate on.

Original:

function generateType(node: IndentNode, type: Type) {
    node.append(`class ${type.name} {`, NL)
    node.indent(content => {
        type.methods.forEach( m => generateMethod(content, m) )
    } )
    node.append('}')
}

function generateMethod(node: IndentNode, method: Method) {
    node.append(`public ${method.name}(): ${method.returnType} {`, NL)
    node.indent(content => generateMethodBody(content, method))
    node.append('}')
}

function generateMethodBody(node: IndentNode, method: Method) {
    // ...
}

With API addition:

function generateType(node: IndentNode, type: Type) {
    node.append(`class ${type.name} {`, NL)
    node.indent(generateMethod, type.methods)
    node.append('}')
}

function generateMethod(node: IndentNode, method: Method) {
    node.append(`public ${method.name}(): ${method.returnType} {`, NL)
    node.indent(generateMethodBody, method)
    node.append('}')
}

function generateMethodBody(node: IndentNode, method: Method) {
    // ...
}

If you think this API makes sense then I would implement and provide a PR.

sailingKieler commented 10 months ago

Hi Tom, thanks for this idea.

Instead of sticking to the classic append-based API: Did you give the expandToNode-based approach a try? That way you can write

function generateMethod(node: IndentNode, method: Method) {
    expandToNode`
        public ${method.name}(): ${method.returnType} {
            ${generateMethodBody(method)}
        }
    `;
}

provided

function generateMethodBody(method: Method): Generated {
    return new ComponentGeneratorNode()....
}