Skip to content

Commit

Permalink
Make Parser.String() return the EBNF.
Browse files Browse the repository at this point in the history
This is more useful than the arbitrary internal format.
  • Loading branch information
alecthomas committed Sep 13, 2020
1 parent 4bad22e commit 2403858
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 25 deletions.
54 changes: 38 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,22 @@
[![Godoc](https://godoc.org/github.com/alecthomas/participle?status.svg)](http://godoc.org/github.com/alecthomas/participle) [![CircleCI](https://img.shields.io/circleci/project/github/alecthomas/participle.svg)](https://circleci.com/gh/alecthomas/participle)
[![Go Report Card](https://goreportcard.com/badge/github.com/alecthomas/participle)](https://goreportcard.com/report/github.com/alecthomas/participle) [![Slack chat](https://img.shields.io/static/v1?logo=slack&style=flat&label=slack&color=green&message=gophers)](https://gophers.slack.com/messages/CN9DS8YF3)

<!-- TOC -->

1. [Introduction](#introduction)
2. [Limitations](#limitations)
3. [Tutorial](#tutorial)
4. [Overview](#overview)
5. [Annotation syntax](#annotation-syntax)
6. [Capturing](#capturing)
7. [Streaming](#streaming)
8. [Lexing](#lexing)
9. [Options](#options)
10. [Examples](#examples)
11. [Performance](#performance)
12. [Concurrency](#concurrency)
13. [Error reporting](#error-reporting)
<!-- TOC depthFrom:2 insertAnchor:true updateOnSave:true -->

- [Introduction](#introduction)
- [Limitations](#limitations)
- [Tutorial](#tutorial)
- [Overview](#overview)
- [Annotation syntax](#annotation-syntax)
- [Capturing](#capturing)
- [Streaming](#streaming)
- [Lexing](#lexing)
- [Options](#options)
- [Examples](#examples)
- [Performance](#performance)
- [Concurrency](#concurrency)
- [Error reporting](#error-reporting)
- [EBNF](#ebnf)

<!-- /TOC -->

Expand All @@ -35,7 +36,7 @@ encoders, but is unusual for a parser.
<a id="markdown-limitations" name="limitations"></a>
## Limitations

Participle parsers are LL(k). Among other things, this means that they do not support left recursion.
Participle grammars are LL(k). Among other things, this means that they do not support left recursion.

The default value of K is 1 but this can be controlled with `participle.UseLookahead(k)`.

Expand Down Expand Up @@ -377,3 +378,24 @@ There are a few areas where Participle can provide useful feedback to users of y
automatically populated with the token at the end of the node.

These related pieces of information can be combined to provide fairly comprehensive error reporting.

<a id="markdown-ebnf" name="ebnf"></a>
## EBNF

Participle supports outputting an EBNF grammar from a Participle parser. Once
the parser is constructed simply call `String()`.

eg. The [GraphQL example](https://github.com/alecthomas/participle/blob/cbe0cc62a3ad95955311002abd642f11543cb8ed/_examples/graphql/main.go#L14-L61)
gives in the following EBNF:

```ebnf
File = Entry* .
Entry = Type | Schema | Enum | "scalar" ident .
Type = "type" ident ("implements" ident)? "{" Field* "}" .
Field = ident ("(" (Argument ("," Argument)*)? ")")? ":" TypeRef ("@" ident)? .
Argument = ident ":" TypeRef ("=" Value)? .
TypeRef = "[" TypeRef "]" | ident "!"? .
Value = ident .
Schema = "schema" "{" Field* "}" .
Enum = "enum" ident "{" ident* "}" .
```
2 changes: 1 addition & 1 deletion _examples/graphql/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ var cli struct {
func main() {
ctx := kong.Parse(&cli)
if cli.EBNF {
fmt.Println(parser.EBNF())
fmt.Println(parser.String())
ctx.Exit(0)
}
for _, file := range cli.Files {
Expand Down
4 changes: 2 additions & 2 deletions ebnf.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ import (
"strings"
)

// EBNF for the grammar.
// String returns the EBNF for the grammar.
//
// Productions are always upper case. Lexer tokens are always lower case.
func (p *Parser) EBNF() string {
func (p *Parser) String() string {
seen := map[node]bool{}
outp := []*ebnfp{}
ebnf(p.root, seen, nil, &outp)
Expand Down
2 changes: 1 addition & 1 deletion ebnf_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,5 @@ Group = "(" Expression ")" .
EBNFOption = "[" Expression "]" .
Repetition = "{" Expression "}" .
`
require.Equal(t, strings.TrimSpace(expected), parser.EBNF())
require.Equal(t, strings.TrimSpace(expected), parser.String())
}
5 changes: 0 additions & 5 deletions parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -251,8 +251,3 @@ func (p *Parser) ParseString(s string, v interface{}, options ...ParseOption) er
func (p *Parser) ParseBytes(b []byte, v interface{}, options ...ParseOption) error {
return p.Parse(bytes.NewReader(b), v, options...)
}

// String representation of the grammar.
func (p *Parser) String() string {
return stringern(p.root, 128)
}

0 comments on commit 2403858

Please sign in to comment.