com.github.leeonky.dal.compiler.Compiler Maven / Gradle / Ivy
package com.github.leeonky.dal.compiler;
import com.github.leeonky.dal.ast.node.*;
import com.github.leeonky.dal.ast.node.table.*;
import com.github.leeonky.dal.ast.node.text.*;
import com.github.leeonky.dal.ast.opt.DALOperator;
import com.github.leeonky.dal.runtime.RuntimeContextBuilder.DALRuntimeContext;
import com.github.leeonky.interpreter.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;
import static com.github.leeonky.dal.ast.node.InputNode.INPUT_NODE;
import static com.github.leeonky.dal.compiler.Constants.PROPERTY_DELIMITER_STRING;
import static com.github.leeonky.dal.compiler.DALProcedure.*;
import static com.github.leeonky.interpreter.ClauseParser.Mandatory.clause;
import static com.github.leeonky.interpreter.ClauseParser.positionClause;
import static com.github.leeonky.interpreter.NodeParser.positionNode;
import static com.github.leeonky.interpreter.Parser.*;
import static com.github.leeonky.interpreter.Rules.*;
import static com.github.leeonky.interpreter.Syntax.many;
import static com.github.leeonky.interpreter.Syntax.single;
import static com.github.leeonky.util.function.When.when;
import static java.util.Optional.empty;
//TODO splite to sub classes
public class Compiler {
private static final EscapeChars SINGLE_QUOTED_ESCAPES = new EscapeChars()
.escape("\\\\", '\\')
.escape("\\'", '\'');
private static final EscapeChars DOUBLE_QUOTED_ESCAPES = new EscapeChars()
.escape("\\\\", '\\')
.escape("\\n", '\n')
.escape("\\r", '\r')
.escape("\\t", '\t')
.escape("\\\"", '"');
private static final EscapeChars REGEX_ESCAPES = new EscapeChars()
.escape("\\/", '/');
// TODO private
NodeParser
PROPERTY, OBJECT, SORTED_LIST, LIST, PARENTHESES, VERIFICATION_SPECIAL_OPERAND, VERIFICATION_VALUE_OPERAND,
TABLE, SHORT_VERIFICATION_OPERAND, CELL_VERIFICATION_OPERAND, GROUP_PROPERTY, OPTIONAL_PROPERTY_CHAIN,
INPUT = procedure -> when(procedure.isCodeBeginning()).optional(() -> INPUT_NODE),
NUMBER = Tokens.NUMBER.nodeParser(NodeFactory::constNumber),
INTEGER = Tokens.INTEGER.nodeParser(NodeFactory::constInteger),
SINGLE_QUOTED_STRING = Notations.SINGLE_QUOTED.with(many(charNode(SINGLE_QUOTED_ESCAPES))
.and(endWith(Notations.SINGLE_QUOTED.getLabel())).as(NodeFactory::constString)),
DOUBLE_QUOTED_STRING = Notations.DOUBLE_QUOTED.with(many(charNode(DOUBLE_QUOTED_ESCAPES))
.and(endWith(Notations.DOUBLE_QUOTED.getLabel())).as(NodeFactory::constString)),
TEXT_BLOCK = positionNode(many(Notations.TEXT_BLOCK).and(atLeast(3)).as(TextBlockNotationNode::new))
.concat(clause(this::textAttribute)).concat(clause(node -> many(charNode(new EscapeChars()))
.and(endWithPosition(((NotationAttributeNode) node).endNotation()))
.as(ls -> new TextBlockNode((NotationAttributeNode) node, ls)))),
STRING = oneOf(TEXT_BLOCK, SINGLE_QUOTED_STRING, DOUBLE_QUOTED_STRING),
CONST_TRUE = Notations.Keywords.TRUE.wordNode(NodeFactory::constTrue, PROPERTY_DELIMITER_STRING),
CONST_FALSE = Notations.Keywords.FALSE.wordNode(NodeFactory::constFalse, PROPERTY_DELIMITER_STRING),
CONST_NULL = Notations.Keywords.NULL.wordNode(NodeFactory::constNull, PROPERTY_DELIMITER_STRING),
REGEX = Notations.OPEN_REGEX.with(many(charNode(REGEX_ESCAPES))
.and(endWith(Notations.CLOSE_REGEX.getLabel())).as(NodeFactory::regex)),
WILDCARD = Notations.Operators.WILDCARD.node(WildcardNode::new),
ROW_WILDCARD = Notations.Operators.ROW_WILDCARD.node(WildcardNode::new),
CONST = oneOf(STRING, CONST_TRUE, CONST_FALSE, CONST_NULL, this::compileUserDefinedLiteral, NUMBER),
ELEMENT_ELLIPSIS = Notations.Operators.ELEMENT_ELLIPSIS.node(token -> new ListEllipsisNode()),
SCHEMA = Tokens.SCHEMA.nodeParser(NodeFactory::schema),
INTEGER_OR_STRING = oneOf(INTEGER, STRING),
STRING_PROPERTY = procedure -> procedure.isEnableRelaxProperty() ? single(STRING)
.as(NodeFactory::stringSymbol).parse(procedure) : empty(),
NUMBER_PROPERTY = procedure -> procedure.isEnableNumberProperty() ? single(NUMBER)
.as(NodeFactory::numberSymbol).parse(procedure) : empty(),
SYMBOL = procedure -> (procedure.isEnableRelaxProperty() ? Tokens.RELAX_SYMBOL : Tokens.SYMBOL)
.nodeParser(NodeFactory::symbolNode).parse(procedure),
TEXT_ATTRIBUTE = Tokens.RELAX_SYMBOL.nodeParser(t -> new TextBlockAttributeNode(t.getContent())),
DOT_SYMBOL = procedure -> (procedure.isEnableRelaxProperty() ? Tokens.RELAX_DOT_SYMBOL : Tokens.DOT_SYMBOL)
.nodeParser(NodeFactory::symbolNode).parse(procedure),
META_SYMBOL = Tokens.DOT_SYMBOL.nodeParser(NodeFactory::metaSymbolNode),
PROPERTY_PATTERN = this::propertyPattern,
OPTIONAL_VERIFICATION_PROPERTY = lazyNode(() -> enableSlashProperty(enableRelaxProperty(OPTIONAL_PROPERTY_CHAIN)));
private NodeParser.Mandatory textAttribute(DALNode notationNode) {
return many(TEXT_ATTRIBUTE).and(endWithLine()).as(attributes ->
new NotationAttributeNode(notationNode, new TextBlockAttributeListNode(attributes)));
}
private Optional propertyPattern(DALProcedure dalProcedure) {
ClauseParser patternClause =
Notations.THIS.clause((token, symbol) -> new PropertyPattern(symbol));
return oneOf(Notations.THIS.node(n -> new PropertyThis()), SYMBOL.with(patternClause)).parse(dalProcedure);
}
public NodeParser.Mandatory
PROPERTY_CHAIN, OPERAND, EXPRESSION, VERIFICATION_PROPERTY, OBJECT_VERIFICATION_PROPERTY,
DEFAULT_INPUT = procedure -> INPUT_NODE,
SCHEMA_COMPOSE = Notations.OPENING_BRACKET.with(single(many(SCHEMA.mandatory("Expect a schema"))
.and(splitBy(Notations.SCHEMA_AND)).as(NodeFactory::elementSchemas))
.and(endWith(Notations.CLOSING_BRACKET)).as()).or(many(SCHEMA.mandatory("Expect a schema"))
.and(splitBy(Notations.SCHEMA_AND)).as(NodeFactory::schemas)),
EXPRESSION_RELAX_STRING = Tokens.EXPRESSION_RELAX_STRING.nodeParser(NodeFactory::relaxString),
OBJECT_SCOPE_RELAX_STRING = Tokens.OBJECT_SCOPE_RELAX_STRING.nodeParser(NodeFactory::relaxString),
LIST_SCOPE_RELAX_STRING = Tokens.LIST_SCOPE_RELAX_STRING.nodeParser(NodeFactory::relaxString),
TABLE_CELL_RELAX_STRING = Tokens.TABLE_CELL_RELAX_STRING.nodeParser(NodeFactory::relaxString),
DEFAULT_INDEX_HEADER = procedure -> new TableDefaultIndexHeadRow();
public ClauseParser
ARITHMETIC_CLAUSE, VERIFICATION_CLAUSE,
SCHEMA_CLAUSE = Operators.IS.clause(SCHEMA_COMPOSE),
WHICH_CLAUSE = lazyClause(() -> Operators.WHICH.clause(EXPRESSION)),
ELEMENT_ELLIPSIS_CLAUSE = Notations.Operators.ELEMENT_ELLIPSIS.clause((token, input) -> new ListEllipsisNode()),
ROW_WILDCARD_CLAUSE = Notations.Operators.ROW_WILDCARD.clause((token, input) -> new WildcardNode(token.getContent())),
LIST_MAPPING_CLAUSE = Notations.LIST_MAPPING.clause((token, symbolNode) -> new ListMappingNode(symbolNode)),
META_LIST_MAPPING_CLAUSE = Notations.LIST_MAPPING.clause((token, symbolNode) -> new ListMappingNodeMeta(symbolNode)),
IMPLICIT_PROPERTY_CLAUSE = Operators.PROPERTY_IMPLICIT.clause(oneOf(PROPERTY_PATTERN,
oneOf(STRING_PROPERTY, NUMBER_PROPERTY, SYMBOL).concat(LIST_MAPPING_CLAUSE))),
EXPLICIT_PROPERTY_CLAUSE = oneOf(Operators.PROPERTY_DOT.clause(PROPERTY_PATTERN.or(propertyChainNode())),
Operators.PROPERTY_SLASH.clause(propertyChainNode()),
Operators.PROPERTY_META.clause(symbolClause(META_SYMBOL.concat(META_LIST_MAPPING_CLAUSE))),
Operators.PROPERTY_IMPLICIT.clause(Notations.OPENING_BRACKET.with(single(INTEGER_OR_STRING.mandatory(
"Should given one property or array index in `[]`")).and(endWith(Notations.CLOSING_BRACKET))
.as(NodeFactory::bracketSymbolNode).concat(LIST_MAPPING_CLAUSE)))
);
private NodeParser.Mandatory propertyChainNode() {
return symbolClause(oneOf(STRING_PROPERTY, DOT_SYMBOL, NUMBER_PROPERTY,
lazyNode(() -> GROUP_PROPERTY)).concat(LIST_MAPPING_CLAUSE));
}
private NodeParser.Mandatory symbolClause(
NodeParser nodeParser) {
return nodeParser.mandatory("Expect a symbol");
}
private ClauseParser.Mandatory shortVerificationClause(
OperatorParser.Mandatory operatorMandatory,
NodeParser.Mandatory operand) {
return SCHEMA_CLAUSE.concat(Operators.VERIFICATION_OPERATORS.clause(operand)).or(operatorMandatory.clause(operand));
}
private ClauseParser ARITHMETIC_CLAUSE_CHAIN, VERIFICATION_CLAUSE_CHAIN,
EXPLICIT_PROPERTY_CHAIN, WHICH_CLAUSE_CHAIN, SCHEMA_CLAUSE_CHAIN, EXPRESSION_CLAUSE;
public Compiler() {
PARENTHESES = lazyNode(() -> enableCommaAnd(Notations.OPENING_PARENTHESES.with(single(EXPRESSION).and(endWith(Notations.CLOSING_PARENTHESES))
.as(NodeFactory::parenthesesNode))));
PROPERTY = lazyNode(() -> oneOf(GROUP_PROPERTY, DEFAULT_INPUT.with(oneOf(EXPLICIT_PROPERTY_CLAUSE, IMPLICIT_PROPERTY_CLAUSE))));
OPTIONAL_PROPERTY_CHAIN = PROPERTY.concatAll(EXPLICIT_PROPERTY_CLAUSE);
PROPERTY_CHAIN = OPTIONAL_PROPERTY_CHAIN.mandatory("Expect a object property");
VERIFICATION_PROPERTY = enableNumberProperty(enableRelaxProperty(enableSlashProperty(PROPERTY_CHAIN)));
OBJECT_VERIFICATION_PROPERTY = many(VERIFICATION_PROPERTY).and(splitBy(Notations.COMMA))
// TODO miss test for error message
.and(endWith(this::verificationNotations, () -> "Expect a verification operator")).as(NodeFactory::createVerificationGroup);
OBJECT = lazyNode(() -> disableCommaAnd(Notations.OPENING_BRACES.with(single(ELEMENT_ELLIPSIS).and(endWith(Notations.CLOSING_BRACES))
.as(ObjectScopeNode::new).or(many(OBJECT_VERIFICATION_PROPERTY.concat(shortVerificationClause(Operators.VERIFICATION_OPERATORS
.mandatory("Expect operator `:` or `=`"), SHORT_VERIFICATION_OPERAND.or(OBJECT_SCOPE_RELAX_STRING))))
.and(optionalSplitBy(Notations.COMMA)).and(endWith(Notations.CLOSING_BRACES)).as(ObjectScopeNode::new)))));
SORTED_LIST = oneOf(Notations.Operators.PLUS.before(pureList(ListScopeNode.NatureOrder::new)),
Notations.Operators.SUBTRACTION.before(pureList(ListScopeNode.ReverseOrder::new)));
LIST = oneOf(pureList(ListScopeNode::new), SORTED_LIST);
TABLE = oneOf(Notations.TRANSPOSE_MARK.with(EMPTY_TRANSPOSED_HEAD.with(transposeTable())),
positionNode(Notations.COLUMN_SPLITTER.before(Notations.TRANSPOSE_MARK.before(Notations.COLUMN_SPLITTER.before(tableLine(ROW_PREFIX)
.as(TransposedTableHead::new))))).concat(transposeTable()),
positionNode(Notations.COLUMN_SPLITTER.before(tableLine(TABLE_HEADER).as(TableHeadRow::new))).concat(TABLE_BODY_CLAUSE),
positionNode(Notations.MATRIX_COLUMN_SPLITTER.before(DEFAULT_INDEX_HEADER).concat(TABLE_BODY_CLAUSE)));
VERIFICATION_SPECIAL_OPERAND = oneOf(REGEX, OBJECT, LIST, WILDCARD, TABLE);
OPERAND = lazyNode(() -> oneOf(Operators.UNARY_OPERATORS.unary(OPERAND), CONST, PROPERTY, PARENTHESES, INPUT))
.mandatory("Expect a value or expression");
VERIFICATION_VALUE_OPERAND = oneOf(Operators.UNARY_OPERATORS.unary(OPERAND), CONST, DEFAULT_INPUT.with(EXPLICIT_PROPERTY_CLAUSE), PARENTHESES);
ARITHMETIC_CLAUSE = Operators.BINARY_ARITHMETIC_OPERATORS.clause(OPERAND);
VERIFICATION_CLAUSE = Operators.VERIFICATION_OPERATORS.clause(oneOf(VERIFICATION_SPECIAL_OPERAND,
VERIFICATION_VALUE_OPERAND).or(EXPRESSION_RELAX_STRING));
ARITHMETIC_CLAUSE_CHAIN = lazyClause(() -> ARITHMETIC_CLAUSE.concat(EXPRESSION_CLAUSE));
VERIFICATION_CLAUSE_CHAIN = lazyClause(() -> VERIFICATION_CLAUSE.concat(EXPRESSION_CLAUSE));
EXPLICIT_PROPERTY_CHAIN = lazyClause(() -> EXPLICIT_PROPERTY_CLAUSE.concat(EXPRESSION_CLAUSE));
WHICH_CLAUSE_CHAIN = lazyClause(() -> WHICH_CLAUSE.concat(EXPRESSION_CLAUSE));
SCHEMA_CLAUSE_CHAIN = lazyClause(() -> SCHEMA_CLAUSE.concat(oneOf(VERIFICATION_CLAUSE_CHAIN,
WHICH_CLAUSE_CHAIN, SCHEMA_CLAUSE_CHAIN)));
EXPRESSION_CLAUSE = oneOf(ARITHMETIC_CLAUSE_CHAIN, VERIFICATION_CLAUSE_CHAIN, EXPLICIT_PROPERTY_CHAIN,
WHICH_CLAUSE_CHAIN, SCHEMA_CLAUSE_CHAIN);
EXPRESSION = OPERAND.concat(EXPRESSION_CLAUSE);
SHORT_VERIFICATION_OPERAND = oneOf(VERIFICATION_SPECIAL_OPERAND, VERIFICATION_VALUE_OPERAND
.concatAll(oneOf(ARITHMETIC_CLAUSE, EXPLICIT_PROPERTY_CLAUSE)));
CELL_VERIFICATION_OPERAND = single(oneOf(oneOf(REGEX, OBJECT, LIST, WILDCARD), VERIFICATION_VALUE_OPERAND
.concatAll(oneOf(ARITHMETIC_CLAUSE, EXPLICIT_PROPERTY_CLAUSE)))).and(enabledBefore(Notations.COLUMN_SPLITTER)).as();
GROUP_PROPERTY = disableCommaAnd(Notations.OPENING_GROUP.with(many(VERIFICATION_PROPERTY)
.and(optionalSplitBy(Notations.COMMA)).and(endWith(Notations.CLOSING_GROUP)).as(GroupExpression::new)));
}
private boolean verificationNotations(DALProcedure procedure) {
SourceCode sourceCode = procedure.getSourceCode();
return sourceCode.startsWith(Notations.Operators.EQUAL)
|| sourceCode.startsWith(Notations.Operators.MATCHER, Notations.Operators.META.getLabel())
|| Notations.Operators.IS.postfix(Constants.PROPERTY_DELIMITER).stream().anyMatch(sourceCode::startsWith);
}
private NodeParser pureList(Function>, DALNode> factory) {
return lazyNode(() -> disableCommaAnd(Notations.OPENING_BRACKET.with(many(ELEMENT_ELLIPSIS_CLAUSE.or(
shortVerificationClause(Operators.VERIFICATION_OPERATORS.or(Operators.DEFAULT_VERIFICATION_OPERATOR),
SHORT_VERIFICATION_OPERAND.or(LIST_SCOPE_RELAX_STRING)))).and(optionalSplitBy(Notations.COMMA))
.and(endWith(Notations.CLOSING_BRACKET)).as(factory))));
}
public List compile(SourceCode sourceCode, DALRuntimeContext DALRuntimeContext) {
return new ArrayList() {{
DALProcedure dalParser = new DALProcedure(sourceCode, DALRuntimeContext, DALExpression::new);
add(EXPRESSION.parse(dalParser));
if (sourceCode.isBeginning() && sourceCode.hasCode())
throw sourceCode.syntaxError("Unexpected token", 0);
while (sourceCode.hasCode())
add(EXPRESSION.parse(dalParser));
}};
}
public List
© 2015 - 2025 Weber Informatics LLC | Privacy Policy