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

org.infinispan.ppg.generator.package-info Maven / Gradle / Ivy

There is a newer version: 10.0.0.Beta3
Show newest version
/**
 * This package contains tooling for automatic generation of binary protocol parsers
 * implementing Netty's ByteToMessageDecoder. These parsers are expected to operate
 * without allocations (aside from allocations from the code specified in grammar).
 *
 * As the processing is quite general, ideally this code will end up in Netty project
 * itself. To demo its capabilities it is now used for decoding the Hot Rod protocol
 * and could be used for Memcached. Netty provides another means for HTTP parsing,
 * therefore REST is not a target.
 *
 * The syntax of grammar is intentionally close to ANTLRv4 syntax despite it's neither
 * a subset nor limited to that.
 *
 * 

Top-level statements

* * * namespace /identifier/;
* Defines an unique namespace for the elements. * This may be useful when the grammar includes another grammar (e.g. older version of protocol). *

* class /fully qualified class name/ [extends /base class name/];
* Defines the package and name of the decoder class, possibly with a base class. * If the base class name is not set it defaults to {@link io.netty.handler.codec.ByteToMessageDecoder}. *

* constants /class name/;
* Static final fields from this class can be referenced (without class name) in the grammar. *

* intrinsics /class name/;
* This class is expected to contain static methods that will parse basic elements from the stream. * Each such method must have {@link io.netty.buffer.ByteBuf} as the first parameter * and any number (or none) of extra parameters. * Underscores on the end of method name are ignored; this allows the intrinsics to clash * with Java keywords, e.g. byte. * These intrinsics are referenced in the grammar using the method name (e.g. string), * if the method requires additional parameters these are passed in brackets (e.g. array[16]). * If the method advances buffer's {@link io.netty.buffer.ByteBuf#readerIndex() reader index} it's considered successful; * when it does not advance the reader index the parsing stops and the method will be invoked again when * more data arrives. Note that this limits non-reading intrinsics (e.g. arrays of length 0): these need * to be handled directly in the grammar using sentinels (see below). *

* Intrinsic methods should not have any side-effect. *

* import /class name/;
* Adds this import to the generated parser. *

* init { /custom code/ }
* This code will be added to the generated parser. This is the place to add constructor and extra fields * and methods. *

* exceptionally { /custom code /}
* This code will be placed into a method called when an exception occurs during decoding process. * The exception is be provided as Throwable t. *

* deadend() { /custom code/ }
* This code will be invoked when the parsing cannot continue, e.g. because there is no matching branch. *

* [root] /rule name/ [returns /type/] [switch /reference/]: /branch1/ [| /branch 2/ | ...| /branch N/];
* Rules are the core part of parsing. There must be exactly one rule in each file with * the root modifier; this is where the parsing starts. *

* Each rule may return a type; in such case the parser contains a field that will hold the result. * The type can be either stated explicitly using returns or is inferred automatically. * Automatic inference requires all of the branches to be of the same type. Type for branch can be inferred when: *

  • there is only single reference to another rule in the branch *
  • the last statement in branch is an action (see below) that starts with new /type/ *
  • the last statement in branch is an action that contains a number (possibly suffixed with L) *
  • the last statement in branch is an action that starts with throw *

    * All but the last branch must start with a sentinel predicate:

    
     * myRule
     *    : { /predicate1/ }? /branch 1 elements/
     *    | { /predicate2/ }? /branch 2 elements/
     *    | /branch 3 elements/
     *    ;
     * 
    * The first matching predicate triggers evaluation of the branch. Each predicate is a Java expression * that returns boolean. The predicates may (and should) reference already matched rules. *

    * In order to generate a switch statement for a rule with many branches, the switch modifier * can be set on the rule. In that case the sentinels should not contain boolean predicates but values * that can be used as the switch cases. *

    * The branch elements is a space-separated list of: *

  • references to another rules *
  • byte values provided as decimal (e.g. 42) or hexadecimal (e.g 0xFF). *
  • constants with value 0..255 *
  • actions: { /custom code/ } *
  • loops: #/reference/ ( /elements/ ) *

    * Loops require some more explanation here: the reference after # is not matched, * it is expected to be already matched before. At this point its value is evaluated and if it's not equal to zero * the referenced field is decremented and the following sequence of elements is matched. Here is an example: *

    
     * map returns Map<String, String>
     *    : numEntries { map = new HashMap<>(numEntries); } #numEntries ( key value { map.put(key, value); } )
     *    ;
     * 
    * The loop can be used for unknown number of elements, too: *
    
     * list returns List<String>
     *    : { list = new ArrayList<>() } hasNext #hasNext ( value { list.add(value); } hasNext )
     *    ;
     * 
    *

    * The grammar must be non-recursive; rules can reference each other as long as this does not cause a cycle. *

    * Once the root rule is fully matched, all fields are zeroed and the parsing starts with root rule anew. * The root rule is not expected to return anything the rightmost element in the parsing tree should be an action * that will fire a callback (defined in base class or in the init code). */ package org.infinispan.ppg.generator;





  • © 2015 - 2025 Weber Informatics LLC | Privacy Policy