All Downloads are FREE. Search and download functionalities are using the official Maven repository.

dev.khbd.interp4j.processor.s.expr.SGrammarDefinition Maven / Gradle / Ivy

There is a newer version: 2.0.0_jre21
Show newest version
package dev.khbd.interp4j.processor.s.expr;

import lombok.Value;
import org.petitparser.context.Token;
import org.petitparser.parser.Parser;
import org.petitparser.parser.primitive.CharacterParser;
import org.petitparser.parser.primitive.StringParser;
import org.petitparser.tools.GrammarDefinition;

import java.util.List;

/**
 * 'S' expression grammar.
 *
 * @author Sergei_Khadanovich
 */
class SGrammarDefinition extends GrammarDefinition {

    private static final String TEXT = "text";
    private static final String EXPRESSION = "expression";
    private static final String EXPRESSION_AND_TEXT = "expressionAndText";

    SGrammarDefinition() {
        def("start",
                ref(TEXT)
                        .seq(ref(EXPRESSION_AND_TEXT).star())
                        .end()
        );
        action("start", (List seq) -> {
            SExpression expression = new SExpression();
            addNotEmptyTextPart(expression, (TextPart) seq.get(0));
            if (seq.size() > 1) {
                List other = (List) seq.get(1);
                for (ExpressionAndText exprAndText : other) {
                    expression.addPart(exprAndText.getExpression());
                    addNotEmptyTextPart(expression, exprAndText.getText());
                }
            }
            return expression;
        });

        def(EXPRESSION_AND_TEXT, ref(EXPRESSION).seq(ref(TEXT)));
        action(EXPRESSION_AND_TEXT, (List seq) ->
                new ExpressionAndText((ExpressionPart) seq.get(0), (TextPart) seq.get(1)));

        def(EXPRESSION, expressionParser());
        action(EXPRESSION, (Token token) -> new ExpressionPart(token.getValue(), token.getStart(), token.getStop()));

        def(TEXT, textParser());
        action(TEXT, (Token token) -> new TextPart(token.getValue(), token.getStart(), token.getStop()));
    }

    private void addNotEmptyTextPart(SExpression expression, TextPart text) {
        if (text.getText().isEmpty()) {
            return;
        }
        expression.addPart(text);
    }

    private static Parser expressionParser() {
        Parser openParser = StringParser.of("${");
        Parser expressionBodyParser = CharacterParser.noneOf("}").star().flatten().token();
        Parser closeParser = CharacterParser.of('}');
        return openParser.seq(expressionBodyParser).seq(closeParser)
                .map((List seq) -> seq.get(1));
    }

    private static Parser textParser() {
        return StringParser.of("$$").map(seq -> "$")
                .or(CharacterParser.noneOf("$").flatten())
                .star()
                .map(seq -> String.join("", (List) seq))
                .token();
    }

    @Value
    private static class ExpressionAndText {
        ExpressionPart expression;
        TextPart text;
    }
}