Exemple #1
0
 public function parse(Input $input)
 {
     $aggregatedResult = [];
     $isPositive = false;
     $count = 0;
     $lastOffset = $input->getOffset();
     while ($this->max === null || $count < $this->max) {
         $result = parent::parse($input)->addParser($this);
         if ($result->positiveMatch) {
             $isPositive = true;
         }
         if ($result->errorMessage) {
             if ($count < $this->min) {
                 return $input->errorHere("Expected {$this->min} elements, but found {$count}");
             } elseif ($result->positiveMatch) {
                 // If a branch got far enough to assert itself but still returned an error then we need to propagate
                 return $result;
             }
             // Most errors are normal, they just signal the end of the repetition.
             break;
         }
         if ($input->getOffset() == $lastOffset) {
             throw new GrammarException('At ' . $input->getPositionDescription() . ": parser {$result->getParserStack()} did not consume any input, this is a bug with the grammar. Make sure there are no zero width matches in a Many. The result in  was {$result}");
         }
         if ($result->hasData) {
             $aggregatedResult[] = $result->data;
         }
         $lastOffset++;
         $count++;
     }
     if ($count < $this->min) {
         return $input->errorHere("Expected {$this->min} elements, but found {$count}", $isPositive)->addParser($this);
     }
     return $input->matchHere($aggregatedResult, $isPositive);
 }
 public function __construct()
 {
     $ws = new WhitespaceParser();
     $left_brace = new Ignore('{');
     $right_brace = new Ignore('}');
     $left_bracket = new Ignore('[');
     $right_bracket = new Ignore(']');
     $colon = new Ignore(':');
     $comma = new Ignore(',');
     // Types
     $bool = new Closure(new Choice(['true', 'false']), function ($data) {
         return $data === 'true';
     });
     $null = new Closure('null', function ($data) {
         return null;
     });
     $string = new StringLiteral();
     $int = new IntLiteral();
     $float = new FloatLiteral();
     $value = new Choice($bool, $null, $string, $float, $int);
     $object = new Closure(new Sequence([$ws, $left_brace, $ws, new Many([new Sequence([$string, $ws, $colon, $ws, $value, $ws])], 0, 1), new Many([new Sequence([$comma, $ws, $string, $ws, $colon, $ws, $value])]), $ws, $right_brace, $ws]), function ($data) {
         $result = [];
         foreach ($data as $value) {
             foreach ($value as $value1) {
                 $result[$value1[0]] = $value1[1];
             }
         }
         return $result;
     });
     $value->append($object);
     $array = new Closure(new Sequence($ws, $left_bracket, $ws, new Many([$value], 0, 1), new Many([new Sequence([$ws, $comma, $ws, $value])]), $ws, $right_bracket, $ws), function ($data) {
         $result = [];
         if (is_array($data[0])) {
             $result[] = $data[0][0];
         }
         if (is_array($data[1])) {
             foreach ($data[1] as $value) {
                 $result[] = $value[0];
             }
         }
         return $result;
     });
     $value->append($array);
     $this->rootParser = new Closure(new Sequence($value, new EofParser()), function ($data) {
         return $data[0];
     });
 }
 public function __construct()
 {
     $identifier = '[a-zA-Z_]{1}[a-zA-Z0-9_\\.]*';
     $positive = new PositiveMatch();
     $comment = new Ignore('//.*');
     $ws = new Ignore(new Sequence([new WhitespaceParser(), new Choice([new Many([new Sequence([$comment, new WhitespaceParser()])]), ''])]));
     // Literals
     $bool = new Closure('true|false', function ($data) {
         return $data === 'true';
     });
     $null = new Closure('null', function ($data) {
         return null;
     });
     $int = new IntLiteral();
     $string = new StringLiteral();
     $float = new FloatLiteral(false);
     $literal = new Choice([$float, $int, $bool, $string, $null]);
     $label = new Choice(['required', 'optional', 'repeated']);
     $type = new Choice(['double', 'float', 'int32', 'int64', 'uint32', 'uint64', 'sint32', 'sint64', 'fixed32', 'fixed64', 'sfixed32', 'sfixed64', 'bool', 'string', 'bytes']);
     $var = new Choice([$literal, new Closure($identifier, function ($data) {
         return new Identifier($data);
     })]);
     $default_field_option = new Closure(new Sequence(['default', $positive, $ws, '=', $ws, $var, $ws]), function ($data) {
         return new Option('default', $data[2]);
     });
     $extended_field_option = new Closure(new Sequence(['(', $positive, $ws, $identifier, $ws, ')', $ws, new Choice([new Concatenate(new Sequence(['.', $positive, $identifier])), '']), $ws, '=', $ws, $var, $ws]), function ($data) {
         return new Option($data[1] . $data[3], $data[5]);
     });
     $field_options = new Closure(new Sequence(['[', $positive, $ws, new Choice([$default_field_option, $extended_field_option, '']), new Many([new Sequence([',', $ws, new Choice([$default_field_option, $extended_field_option, '']), $ws])]), ']', $ws]), function ($data) {
         $result = [];
         if ($data[1]) {
             $result[] = $data[1];
         }
         if (isset($data[2]) && is_array($data[2])) {
             foreach ($data[2] as $option) {
                 $result[] = $option[1];
             }
         }
         return $result;
     });
     $field = new Closure(new Sequence([$label, $positive, $ws, new Choice([$type, $identifier]), $ws, $identifier, $ws, new Ignore('='), $ws, $int, $ws, new Choice([$field_options, '']), new Ignore(';'), $ws]), function ($data) {
         $default = null;
         if (isset($data[4])) {
             $default = $data[4];
         }
         return new Field($data[0], $data[1], $data[2], $data[3], $default);
     });
     $extensions = new Closure(new Sequence(['extensions', $positive, $ws, $var, $ws, 'to', $ws, $var, $ws, ';', $ws]), function ($data) {
         return new Extensions($data[1], $data[3]);
     });
     $extend = new Closure(new Sequence(['extend', $positive, $ws, $identifier, $ws, '{', $ws, new Many([$field]), $ws, '}', $ws]), function ($data) {
         return new Extend($data[1], $data[3]);
     });
     $import = new Closure(new Sequence(['import', $positive, $ws, $string, $ws, ';', $ws]), function ($data) {
         return new Import($data[1]);
     });
     $option = new Closure(new Sequence(['option', $positive, $ws, new Concatenate(new Sequence([new Ignore('\\(?'), $ws, '\\.?', $ws, $identifier, $ws, new Ignore('\\)?'), $ws])), $ws, new Choice([new Concatenate(new Sequence(['.', $ws, $identifier, $ws])), '']), '=', $ws, $var, $ws, ';', $ws]), function ($data) {
         return new Option($data[1] . $data[2], $data[4]);
     });
     $rpc = new Closure(new Sequence(['rpc', $positive, $ws, $identifier, $ws, '(', $ws, $identifier, $ws, ')', $ws, 'returns', $ws, '(', $ws, $identifier, $ws, ')', $ws, new Choice([new Sequence(['{', $positive, $ws, new Many([$option]), $ws, '}', $ws]), ';', $ws])]), function ($data) {
         return new Rpc($data[1], $data[3], $data[7]);
     });
     $service = new Closure(new Sequence(['service', $positive, $ws, $identifier, $ws, '{', $ws, new Many([$rpc, $option]), $ws, '}', $ws]), function ($data) {
         return new Service($data[1], $data[3]);
     });
     $enumField = new Closure(new Sequence([$identifier, $ws, '=', $ws, $int, $ws, new Choice([$field_options, '']), ';', $ws]), function ($data) {
         if (is_array($data[3])) {
             return new EnumValue($data[0], $data[2], $data[3]);
         }
         return new EnumValue($data[0], $data[2]);
     });
     $enum = new Closure(new Sequence(['enum', $positive, $ws, $identifier, $ws, '{', $ws, new Many([$option, $enumField]), $ws, '}', $ws]), function ($data) {
         $fields = [];
         $options = [];
         foreach ($data[3] as $datum) {
             if ($datum instanceof Option) {
                 $options[] = $datum;
             } else {
                 $fields[] = $datum;
             }
         }
         return new Enum($data[1], $fields, $options);
     });
     $definition = new Choice([$field, $enum, $extensions, $extend, $option]);
     $message = new Closure(new Sequence(['message', $positive, $ws, $identifier, $ws, '{', $ws, new Many([$definition]), $ws, '}', $ws]), function ($data) {
         $message = new Message($data[1], $data[3]);
         return $message;
     });
     $definition->append($message);
     $package = new Closure(new Sequence(['package', $positive, $ws, $identifier, $ws, ';', $ws, new Many([$option, $enum, $import, $message, $extend, $service])]), function ($data) {
         return new Package($data[1], $data[3]);
     });
     $this->rootParser = new Closure(new Sequence([$ws, new Many([$option, $enum, $package, $import, $message, $extend, $service]), $ws, new EofParser()]), function ($data) {
         return new File($data[0]);
     });
 }
 public function testMultiple()
 {
     $combinator = new Choice(['asdf', 'hjkl']);
     $this->assertEquals('hjkl', $combinator->parse(new Input("hjkl"))->data);
 }