Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Criando sua DSL com jparsec

Criando sua DSL com jparsec

Como criar uma DSL simples com a lib jparsec.

Felipe Mamud

October 19, 2017
Tweet

More Decks by Felipe Mamud

Other Decks in Programming

Transcript

  1. AGENDA • O que é? • Vantagens e Desvantagens •

    Motivação • Exemplo simples • Caso de uso em produção
  2. Biblioteca inspirada no parsec, da linguagem Haskell, onde é possível

    a criação de parsers de gramáticas preditivas ou sensíveis a contextos. • Desde 2013 • Latest version: 3.0 (requires Java 8+) • compile 'org.jparsec:jparsec:3.0' O QUE É?
  3. VANTAGENS E DESVANTAGENS • Combinação entre parsers • Alguns scanners

    prontos • Performance • Estável • Documentação pobre • Ordem de declaração
  4. MOTIVAÇÃO • Abstrair as queries para nosso backend; • Permitir

    aos clientes da SearchAPI v2: ◦ Autonomia; ◦ Facilidade; ◦ Flexibilidade. • Validar a estrutura de uma query válida; • DSL do Elasticsearch incompleta.
  5. EXEMPLO SIMPLES EM 3 PASSOS Criar um parser de strings

    separadas por espaço e aninhadas por parênteses. • "tincas" • "tincas trolha dumbs" • "tincas (dunhas)" • "(tincas (dunhas))" • "(tincas (dunhas (socks (xpto cool))))"
  6. Parser<Strings> STRING = Scanners.IDENTIFIER .sepBy(Scanners.WHITESPACES).map(Strings::new); public static Parser<Strings> getRecursive() {

    Parser.Reference<Strings> ref = Parser.newReference(); Parser<Strings> parser = ref.lazy() .between(isChar('('),isChar(')')).or(STRING) .sepBy(Scanners.WHITESPACES) .many() .map(Strings::new); ref.set(parser); return parser; } // ["tincas","dunhas","socks","xpto","cool"] getRecursive() .parse("(tincas (dunhas (socks (xpto cool))))"); PASSO #3
  7. FIELD PARSER Parsers.IDENTIFIER .sepBy1(isChar('.')) .label("field") .map(Field::new); Parser de identificadores que

    podem ser separados por um ponto. • "_tincas" • "BonaFont10" • "address.street"
  8. FIELD PARSER Parsers.IDENTIFIER .sepBy1(isChar('.')) .label("field") .map(Field::new); public class Field {

    private final List<String> names; public Field(final List<String> names) { this.names = names; } ... } Parser de identificadores que podem ser separados por um ponto. • "_tincas" • "BonaFont10" • "address.street"
  9. • DIFFERENT("NE", "<>") • EQUAL("EQ", ":", "=") • GREATER("GT", ">")

    • GREATER_EQUAL("GTE", ">=") • IN("INTO") • LESS("LT", "<") • LESS_EQUAL("LTE", "<=") • VIEWPORT("@") • LIKE("LK") • RANGE("RG") • POLYGON("PG") RELATIONAL OPERATORS
  10. VALUE PARSER • BOOLEAN → a = true • NULL

    → b:null • STRING → c EQ "tincas" • NUMBER → d > 42 • IN → v IN [1,"abc",true,NULL] • LIKE → x LIKE "tinc%" • RANGE → y RANGE [1, 3] • GEOPOINT → z VIEWPORT [[-23.1234,-46.4534],[-23.0987,-46.9087]]
  11. QUERY PARSER "(rooms EQUAL 3 AND NOT pimba EQUAL 2

    AND (suites EQUAL 1 OR (parkingLots GT 1 AND xpto DIFFERENT 3)))"
  12. QUERY PARSER "(rooms EQUAL 3 AND NOT pimba EQUAL 2

    AND (suites EQUAL 1 OR (parkingLots GT 1 AND xpto DIFFERENT 3)))" QUERY_PARSER = Parsers.sequence( LOGICAL_OPERATOR_PARSER.asOptional(), FILTER_PARSER, QueryFragmentItem::new); Parsers.between(isChar('('), isChar(')')) .or(QUERY_PARSER, LOGICAL_OPERATOR_PARSER, NOT_PARSER)
  13. LINKS • SearchAPI v2 Wiki https://github.com/VivaReal/search-api/wiki • Parsec https://wiki.haskell.org/Parsec •

    jparsec https://github.com/jparsec/jparsec • parsertest https://github.com/fmamud/parsertest