├── .editorconfig ├── .github └── workflows │ └── d.yaml ├── .gitignore ├── .gitmodules ├── .travis.yml ├── README.md ├── appveyor.yml ├── ci.bat ├── ci.sh ├── debian ├── changelog ├── compat ├── control ├── copyright ├── install └── rules ├── dub.json ├── examples ├── DConf2017 │ ├── README.md │ ├── arithmetic.d │ ├── left_recursion_naive.d │ ├── left_recursion_proper.d │ └── recursion.d ├── PEG │ ├── dub.json │ └── src │ │ └── pegged │ │ └── examples │ │ └── PEG.d ├── README.md ├── arithmetic │ ├── dub.json │ └── src │ │ └── pegged │ │ └── examples │ │ └── arithmetic.d ├── c │ ├── dub.json │ └── src │ │ └── pegged │ │ └── examples │ │ └── c.d ├── composition │ ├── dub.json │ └── src │ │ └── pegged │ │ └── examples │ │ └── composition.d ├── csv │ ├── dub.json │ └── src │ │ └── pegged │ │ └── examples │ │ └── csv.d ├── dgrammar │ ├── dub.json │ └── src │ │ └── pegged │ │ └── examples │ │ └── dgrammar.d ├── extended_pascal │ ├── .gitattributes │ ├── .gitignore │ ├── README.md │ ├── dub.json │ ├── example.pas │ ├── output │ │ ├── TraceLog.txt │ │ ├── example.html │ │ └── example.txt │ ├── runtests.d │ └── source │ │ ├── app.d │ │ ├── epgrammar.d │ │ └── make.d ├── json │ ├── dub.json │ └── src │ │ └── pegged │ │ └── examples │ │ └── json.d ├── markdown │ ├── dub.json │ └── src │ │ └── pegged │ │ └── examples │ │ └── markdown.d ├── misc │ ├── dub.json │ └── src │ │ └── pegged │ │ └── examples │ │ ├── constraints.d │ │ ├── pattern.d │ │ └── testergrammar.d ├── numbers │ ├── dub.json │ └── src │ │ └── pegged │ │ └── examples │ │ └── numbers.d ├── oberon2 │ ├── dub.json │ └── src │ │ └── pegged │ │ └── examples │ │ └── oberon2.d ├── parameterized │ ├── dub.json │ └── src │ │ └── pegged │ │ └── examples │ │ └── parameterized.d ├── peggedgrammar │ ├── dub.json │ └── src │ │ └── pegged │ │ └── examples │ │ └── peggedgrammar.d ├── python │ ├── Makefile │ ├── dub.json │ └── src │ │ └── pegged │ │ └── examples │ │ └── python.d ├── simple_arithmetic │ ├── dub.json │ └── src │ │ └── pegged │ │ └── examples │ │ └── simple_arithmetic.d ├── strings │ ├── dub.json │ └── src │ │ └── pegged │ │ └── examples │ │ └── strings.d └── xml │ ├── dub.json │ └── src │ └── pegged │ └── examples │ ├── xml.d │ └── xml2.d ├── makefile ├── pegged.valgrind ├── pegged ├── dev │ ├── README.md │ ├── TODO.md │ ├── regenerate.d │ └── test.d ├── docs │ ├── README.md │ └── cheatsheet │ │ ├── Makefile │ │ └── cheatsheet.tex ├── dynamic │ ├── README.md │ ├── grammar.d │ └── peg.d ├── grammar.d ├── introspection.d ├── parser.d ├── peg.d ├── performancetest │ └── cursive │ │ ├── generator.d │ │ ├── parser.d │ │ ├── reader.d │ │ └── test.crs ├── test │ └── tester.d ├── tester │ ├── README.md │ ├── grammartester.d │ └── testerparser.d └── tohtml.d ├── scripts └── core-dump.sh └── wscript /.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor config ripped from dlang repository : https://github.com/dlang/dlang.org/blob/master/.editorconfig 2 | root = true 3 | 4 | [*.{c,h,d,di,dd,ddoc,json,yml,sh}] 5 | end_of_line = lf 6 | insert_final_newline = true 7 | indent_style = space 8 | indent_size = 4 9 | trim_trailing_whitespace = true 10 | charset = utf-8 11 | 12 | [*.bat] 13 | end_of_line = crlf 14 | 15 | -------------------------------------------------------------------------------- /.github/workflows/d.yaml: -------------------------------------------------------------------------------- 1 | name: Run all D Tests 2 | on: [push, pull_request] 3 | 4 | jobs: 5 | generated: 6 | name: Make sure that the parser is generated from the grammar 7 | strategy: 8 | matrix: 9 | os: [ubuntu-latest] 10 | dc: [dmd-2.101.2] # Avoid https://dlang.org/changelog/2.102.0.html#build-cache 11 | 12 | runs-on: ${{ matrix.os }} 13 | steps: 14 | - uses: actions/checkout@v2 15 | 16 | - name: Install D compiler 17 | uses: dlang-community/setup-dlang@v1 18 | with: 19 | compiler: ${{ matrix.dc }} 20 | 21 | - name: Run test 22 | working-directory: ./pegged/dev 23 | run: rdmd -I../.. -I../../examples/peggedgrammar/src -I../../examples/misc/src regenerate.d --validate 24 | 25 | unittest: 26 | name: Pegged unit tests 27 | strategy: 28 | matrix: 29 | os: [ubuntu-latest, windows-latest, macOS-latest] 30 | dc: [dmd-latest, ldc-latest, dmd-2.087.1, dmd-2.090.1, ldc-1.17.0, ldc-1.20.0] 31 | exclude: 32 | # dyld[2053]: missing symbol called 33 | - { os: macOS-latest, dc: dmd-2.087.1 } 34 | # ld: section __DATA/__thread_bss has type zero-fill but non-zero file offset 35 | - { os: macOS-latest, dc: dmd-2.090.1 } 36 | # needs -lowmem 37 | - { os: windows-latest, dc: dmd-2.090.1 } 38 | 39 | runs-on: ${{ matrix.os }} 40 | steps: 41 | - uses: actions/checkout@v2 42 | 43 | - name: Install D compiler 44 | uses: dlang-community/setup-dlang@v1 45 | with: 46 | compiler: ${{ matrix.dc }} 47 | 48 | - name: Run tests 49 | run: dub -q test 50 | 51 | examples: 52 | name: Examples unit tests 53 | strategy: 54 | matrix: 55 | os: [ubuntu-latest, windows-latest, macOS-latest] 56 | dc: [dmd-2.101.2] # Avoid https://dlang.org/changelog/2.102.0.html#build-cache 57 | example: [arithmetic, c, csv, json, numbers, python, simple_arithmetic, strings, xml] 58 | exclude: 59 | # out of memory 60 | - { example: python } 61 | 62 | runs-on: ${{ matrix.os }} 63 | steps: 64 | - uses: actions/checkout@v2 65 | 66 | - name: Install D compiler 67 | uses: dlang-community/setup-dlang@v1 68 | with: 69 | compiler: ${{ matrix.dc }} 70 | 71 | - name: Test example 72 | run: dub test :${{ matrix.example }} 73 | 74 | runtests: 75 | name: Examples runtests 76 | strategy: 77 | matrix: 78 | os: [ubuntu-latest, windows-latest, macOS-latest] 79 | dc: [dmd-2.101.2] # Avoid https://dlang.org/changelog/2.102.0.html#build-cache 80 | example: [extended_pascal] 81 | 82 | runs-on: ${{ matrix.os }} 83 | steps: 84 | - uses: actions/checkout@v2 85 | 86 | - name: Install D compiler 87 | uses: dlang-community/setup-dlang@v1 88 | with: 89 | compiler: ${{ matrix.dc }} 90 | 91 | - name: Test example 92 | working-directory: examples/${{ matrix.example }} 93 | run: rdmd runtests 94 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by https://www.gitignore.io/api/d 2 | # Edit at https://www.gitignore.io/?templates=d 3 | 4 | ### D ### 5 | # Compiled Object files 6 | *.o 7 | *.obj 8 | 9 | # Compiled Dynamic libraries 10 | *.so 11 | *.dylib 12 | *.dll 13 | 14 | # Compiled Static libraries 15 | *.a 16 | *.lib 17 | 18 | # Executables 19 | *.exe 20 | 21 | # DUB 22 | .dub 23 | docs.json 24 | __dummy.html 25 | docs/ 26 | 27 | # Code coverage 28 | *.lst 29 | 30 | ### D Patch ### 31 | # Test Executables 32 | *-test-* 33 | 34 | # Comment to allow dub lock file to be version controlled as well 35 | dub.selections.json 36 | 37 | # End of https://www.gitignore.io/api/d 38 | 39 | *~ 40 | *.swp 41 | *.deps 42 | .lock-* 43 | build/* 44 | .directory 45 | 46 | .vscode/ 47 | 48 | /.vs 49 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "pegged/docs/wiki"] 2 | path = pegged/docs/wiki 3 | url = https://github.com/PhilippeSigaud/Pegged.wiki.git 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | os: linux 2 | # Latest Ubuntu LTS 3 | dist: bionic 4 | language: d 5 | 6 | addons: 7 | apt: 8 | update: true 9 | packages: 10 | - gdb 11 | 12 | # Enable core dumps 13 | before_script: 14 | - ulimit -c unlimited -S 15 | - sudo mkdir /cores/ && sudo chmod 777 /cores/ 16 | - echo "/cores/%E.%p" | sudo tee /proc/sys/kernel/core_pattern 17 | 18 | after_failure: 19 | - ./scripts/core-dump.sh 20 | 21 | jobs: 22 | include: 23 | - d: dmd-nightly 24 | - d: dmd 25 | - d: ldc 26 | allow_failures: 27 | - d: dmd-nightly 28 | 29 | script: ./ci.sh 30 | 31 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.com/PhilippeSigaud/Pegged.svg?branch=master)](https://travis-ci.com/PhilippeSigaud/Pegged) 2 | [![Build status](https://ci.appveyor.com/api/projects/status/qbd39bvvyrrns2m0?svg=true)](https://ci.appveyor.com/project/PhilippeSigaud/pegged) 3 | 4 | PEGGED 5 | ====== 6 | 7 | **Pegged** is a parsing expression grammar (PEG) generator implemented in the D programming language. 8 | 9 | The idea is to give the generator a [PEG](http://en.wikipedia.org/wiki/Parsing_expression_grammar), with the syntax presented in [the reference article ](http://bford.info/pub/lang/peg). From this grammar definition a set of related parsers will be created, to be used at runtime or compile time. 10 | 11 | Usage 12 | ----- 13 | 14 | To use **Pegged**, just call the `grammar` function with a PEG and mix it in. For example: 15 | 16 | 17 | ```d 18 | import pegged.grammar; 19 | 20 | mixin(grammar(` 21 | Arithmetic: 22 | Term < Factor (Add / Sub)* 23 | Add < "+" Factor 24 | Sub < "-" Factor 25 | Factor < Primary (Mul / Div)* 26 | Mul < "*" Primary 27 | Div < "/" Primary 28 | Primary < Parens / Neg / Pos / Number / Variable 29 | Parens < "(" Term ")" 30 | Neg < "-" Primary 31 | Pos < "+" Primary 32 | Number < ~([0-9]+) 33 | 34 | Variable <- identifier 35 | `)); 36 | ``` 37 | [![Open on run.dlang.io](https://img.shields.io/badge/run.dlang.io-open-blue.svg)](https://run.dlang.io/is/AYKe5x) 38 | 39 | 40 | This creates the `Arithmetic` grammar, with the `Expr`, `Add`, `Factor` (and so on) rules for basic arithmetic expressions with operator precedence ('*' and '/' bind stronger than '+' or '-'). `identifier` is a pre-defined parser recognizing your basic C-style identifier (first a letter or underscore, then digits, letters or underscores). In the rest of this document, I'll call 'rule' a `Parser <- Parsing Expression` expression and I'll use 'grammar' to designate the entire group of rules given to `grammar`. 41 | 42 | To use a grammar, call it with a string. It will return a parse tree containing the calls to the different rules: 43 | 44 | ```d 45 | // Parsing at compile-time: 46 | enum parseTree1 = Arithmetic("1 + 2 - (3*x-5)*6"); 47 | 48 | pragma(msg, parseTree1.matches); 49 | assert(parseTree1.matches == ["1", "+", "2", "-", "(", "3", "*", "x", "-", "5", ")", "*", "6"]); 50 | writeln(parseTree1); 51 | 52 | // And at runtime too: 53 | auto parseTree2 = Arithmetic(" 0 + 123 - 456 "); 54 | assert(parseTree2.matches == ["0", "+", "123", "-", "456"]); 55 | ``` 56 | 57 | Even for such a simple grammar and such a simple expression, the resulting parse tree is a bit long to be shown here. See [the result here](https://github.com/PhilippeSigaud/Pegged/wiki/Parse-Result) 58 | 59 | By default, the grammars do not silently consume spaces, as this is the standard behaviour for PEGs. There is an opt-out though, with the simple `< ` arrow instead of `<-` (you can see it in the previous example). 60 | 61 | How to get Pegged 62 | ----------------- 63 | 64 | Pegged is a github project, hosted at 65 | 66 | To get it: 67 | 68 | ```bash 69 | $ git clone https://github.com/PhilippeSigaud/Pegged 70 | ``` 71 | 72 | The `/docs` directory contains an empty `/wiki` directory, linked to the github wiki as a git submodule. 73 | Here is how to get it: 74 | 75 | ```bash 76 | $ cd 77 | $ git submodule init 78 | $ git submodule update 79 | ``` 80 | 81 | This should give you a `/docs/wiki` directory full of markdown files, right from the online wiki. 82 | 83 | Tutorial and docs 84 | ----------------- 85 | 86 | The **Pegged** wiki is [here](https://github.com/PhilippeSigaud/Pegged/wiki/). It contains a growing [tutorial](https://github.com/PhilippeSigaud/Pegged/wiki/Pegged-Tutorial). All the wiki pages are also present (as Markdown files) in the `docs` directory. 87 | 88 | Features 89 | -------- 90 | 91 | * The complete set of operators described [here](http://en.wikipedia.org/wiki/Parsing_expression_grammar) are implemented, with the 'traditional' PEG syntax. See [Peg Basics](https://github.com/PhilippeSigaud/Pegged/wiki/PEG-Basics). 92 | * **Pegged** can parse its input at compile time and generate a complete parse tree at compile time. In a word: compile-time string (read: D code) transformation and generation. See [Generating Code](https://github.com/PhilippeSigaud/Pegged/wiki/Generating-Code) for example. 93 | * You can parse at runtime also, you lucky you. ([Using the Parse Tree](https://github.com/PhilippeSigaud/Pegged/wiki/Using-the-Parse-Tree)) 94 | * Use a standard and readable PEG syntax as a DSL, not a bunch of templates that hide the parser in noise. 95 | * But you can use expression templates if you want, as parsers are all available as such. **Pegged** is implemented as an expression template, and what's good for the library writer is sure OK for the user too. ([Behind the Curtain: How Pegged Works](https://github.com/PhilippeSigaud/Pegged/wiki/Behind-the-Curtain%3A-How-Pegged-Works) 96 | * Some useful additional operators are there too: a way to discard matches (thus dumping them from the parse tree), to push captures on a stack, to accept matches that are equal to another match: see [PEG Additions](https://github.com/PhilippeSigaud/Pegged/wiki/Extended-PEG-Syntax). 97 | * Adding new parsers is easy. See [User-Defined Parsers](https://github.com/PhilippeSigaud/Pegged/wiki/User-Defined-Parsers) to see how to do that. 98 | * **Pegged** fully supports [left recursive](https://github.com/PhilippeSigaud/Pegged/wiki/Left-Recursion) grammars when parsing at run-time. 99 | * Grammars are composable: you can put different `mixin(grammar(rules));` in a module and then grammars and rules can refer to one another. That way, you can have utility grammars providing their functionalities to other grammars. [Grammar Composition](https://github.com/PhilippeSigaud/Pegged/wiki/Grammar-Composition) 100 | * That's why **Pegged** comes with some pre-defined grammars (JSON, C, XML, CSV, D, the PEG grammar itself, etc). See [Grammar Examples](https://github.com/PhilippeSigaud/Pegged/wiki/Grammar-Examples). 101 | * Grammars can be dumped in a file to create a module. Use the `asModule(string moduleName, string gram)` function in `pegged.grammar` to do that. See [Grammars as Modules](https://github.com/PhilippeSigaud/Pegged/wiki/Grammars-as-D-Modules). 102 | 103 | More advanced features, outside the standard PEG perimeter are there to bring more power in the mix: 104 | 105 | * **Parametrized rules**: `"List(E, Sep) <- E (Sep E)*"` is possible. The previous rule defines a parametrized parser taking two other parsers (namely, `E` and `Sep`) to match a `Sep`-separated list of `E`'s. Entire grammars can be parametrized, too. See [Parametrized Rules](https://github.com/PhilippeSigaud/Pegged/wiki/Parametrized-Rules) to see what's possible. 106 | * **Semantic actions** can be added to any rule in a grammar. Once a rule has matched, its associated action is called on the rule output and passed as final result to other parsers further up the grammar. Do what you want to the parse tree. If the passed actions are delegates, they can access external variables. See [Semantic Actions](https://github.com/PhilippeSigaud/Pegged/wiki/Semantic-Actions). 107 | 108 | References 109 | ---------- 110 | 111 | Articles: 112 | 113 | * [The base PEG article from Bryan Ford](http://bford.info/pub/lang/peg). 114 | * [Packrat parsing](http://pdos.csail.mit.edu/~baford/packrat/icfp02/). 115 | * [OMeta](http://www.vpri.org/pdf/tr2007003_ometa.pdf). 116 | 117 | D Code: 118 | 119 | * Hisayuki Mima's [CTPG](https://github.com/youkei/ctpg), very similar, also done in D. Have a look! 120 | * Nick Sabalausky's [Goldie](http://www.dsource.org/projects/goldie). 121 | * Benjamin Shropshire's [dparser](http://dsource.org/projects/scrapple/browser/trunk/dparser). 122 | * Martin Nowak put these gists on the D newsgroup: 123 | - https://gist.github.com/1255439 - lexer generator 124 | - https://gist.github.com/1262321 - complete and fast D lexer 125 | 126 | Other languages: 127 | 128 | * [pegtl](http://code.google.com/p/pegtl/), the PEG Template Library, in C++. 129 | * [chilon::parser](http://chilon.net/library.html) in C++ also. 130 | * [metaparse](http://abel.web.elte.hu/mpllibs/metaparse/index.html), in C++, is able to parse at compile-time. 131 | * [Parslet](http://kschiess.github.com/parslet/) in Ruby and [Treetop](http://treetop.rubyforge.org/), in Ruby also. 132 | 133 | License 134 | ------- 135 | 136 | **Pegged** is released with the Boost license (like most D projects). See [here](http://www.boost.org/LICENSE_1_0.txt) for more details. 137 | 138 | Contributing 139 | ------------ 140 | 141 | **Pegged** itself is used in its own development. In particular, the file [pegged/parser.d](pegged/parser.d) is generated from [examples/peggedgrammar/src/pegged/examples/peggedgrammar.d](examples/peggedgrammar/src/pegged/examples/peggedgrammar.d). Therefore [pegged/parser.d](pegged/parser.d) should not be edited by hand. However, if anything changes in any of the other files in [pegged/](pegged/), or in [examples/peggedgrammar/src/pegged/examples/peggedgrammar.d](examples/peggedgrammar/src/pegged/examples/peggedgrammar.d), the parser must be regenerated. How to do that is described in [pegged/dev](pegged/dev). 142 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | platform: x64 2 | environment: 3 | matrix: 4 | - DC: dmd 5 | DVersion: stable 6 | arch: x64 7 | - DC: dmd 8 | DVersion: stable 9 | arch: x86 10 | - DC: dmd 11 | DVersion: 2.090.1 12 | arch: x86 13 | - DC: dmd 14 | DVersion: 2.087.1 15 | arch: x86 16 | - DC: ldc 17 | DVersion: stable 18 | arch: x86 19 | - DC: ldc 20 | DVersion: stable 21 | arch: x64 22 | 23 | matrix: 24 | allow_failures: 25 | - DVersion: 2.090.1 26 | 27 | skip_tags: true 28 | 29 | install: 30 | - ps: function ResolveLatestDMD 31 | { 32 | $version = $env:DVersion; 33 | if($version -eq "stable") { 34 | $latest = (Invoke-WebRequest "http://downloads.dlang.org/releases/LATEST").toString(); 35 | $url = "http://downloads.dlang.org/releases/2.x/$($latest)/dmd.$($latest).windows.7z"; 36 | }elseif($version -eq "beta") { 37 | $latest = (Invoke-WebRequest "http://downloads.dlang.org/pre-releases/LATEST").toString(); 38 | $latestVersion = $latest.split("-")[0].split("~")[0]; 39 | $url = "http://downloads.dlang.org/pre-releases/2.x/$($latestVersion)/dmd.$($latest).windows.7z"; 40 | }elseif($version -eq "nightly") { 41 | $url = "http://nightlies.dlang.org/dmd-master-2017-05-20/dmd.master.windows.7z" 42 | }else { 43 | $url = "http://downloads.dlang.org/releases/2.x/$($version)/dmd.$($version).windows.7z"; 44 | } 45 | if($env:arch -eq "x64"){ 46 | $env:PATH += ";C:\dmd2\windows\bin64;"; 47 | } 48 | $env:PATH += ";C:\dmd2\windows\bin;"; 49 | return $url; 50 | } 51 | - ps: function ResolveLatestLDC 52 | { 53 | $version = $env:DVersion; 54 | $arch = $env:arch; 55 | if($version -eq "stable") { 56 | $latest = (Invoke-WebRequest "https://ldc-developers.github.io/LATEST").toString().replace("`n","").replace("`r",""); 57 | $url = "https://github.com/ldc-developers/ldc/releases/download/v$($latest)/ldc2-$($latest)-windows-$($arch).7z"; 58 | }elseif($version -eq "beta") { 59 | $latest = (Invoke-WebRequest "https://ldc-developers.github.io/LATEST_BETA").toString().replace("`n","").replace("`r",""); 60 | $url = "https://github.com/ldc-developers/ldc/releases/download/v$($latest)/ldc2-$($latest)-windows-$($arch).7z"; 61 | } else { 62 | $latest = $version; 63 | $url = "https://github.com/ldc-developers/ldc/releases/download/v$($version)/ldc2-$($version)-windows-$($arch).7z"; 64 | } 65 | $env:PATH += ";C:\ldc2-$($latest)-windows-$($arch)\bin"; 66 | $env:DC = "ldc2"; 67 | return $url; 68 | } 69 | - ps: function SetUpDCompiler 70 | { 71 | $env:toolchain = "msvc"; 72 | if($env:DC -eq "dmd"){ 73 | echo "downloading ..."; 74 | $url = ResolveLatestDMD; 75 | echo $url; 76 | Invoke-WebRequest $url -OutFile "c:\dmd.7z"; 77 | echo "finished."; 78 | pushd c:\\; 79 | 7z x dmd.7z > $null; 80 | popd; 81 | } 82 | elseif($env:DC -eq "ldc"){ 83 | echo "downloading ..."; 84 | $url = ResolveLatestLDC; 85 | echo $url; 86 | Invoke-WebRequest $url -OutFile "c:\ldc.zip"; 87 | echo "finished."; 88 | pushd c:\\; 89 | 7z x ldc.zip > $null; 90 | popd; 91 | } 92 | } 93 | - ps: SetUpDCompiler 94 | 95 | before_build: 96 | - ps: if($env:arch -eq "x86"){ 97 | $env:compilersetupargs = "x86"; 98 | $env:Darch = "x86"; 99 | $env:DConf = "m32"; 100 | }elseif($env:arch -eq "x64"){ 101 | $env:compilersetupargs = "amd64"; 102 | $env:Darch = "x86_64"; 103 | $env:DConf = "m64"; 104 | } 105 | - ps: $env:compilersetup = "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall"; 106 | - '"%compilersetup%" %compilersetupargs%' 107 | - ps: Get-CIMInstance Win32_OperatingSystem | Select FreePhysicalMemory,TotalVisibleMemory 108 | 109 | build_script: 110 | - echo dummy build script - dont remove me 111 | 112 | test_script: 113 | - echo %PLATFORM% 114 | - echo %Darch% 115 | - echo %DC% 116 | - echo %PATH% 117 | - dub --version 118 | - '%DC% --version' 119 | - ci.bat 120 | -------------------------------------------------------------------------------- /ci.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | @setlocal 3 | setlocal EnableDelayedExpansion 4 | 5 | echo Unit Tests 6 | 7 | echo "Test for successful release build" 8 | dub build -b release --compiler=%DC% 9 | dub clean --all-packages -q 10 | 11 | echo "Running tests" 12 | dub test --compiler=%DC% -v 13 | 14 | echo "Running example tests" 15 | 16 | pushd examples\simple_arithmetic 17 | dub test --compiler=%DC% -q 18 | popd 19 | 20 | dub test :numbers --compiler=%DC% -q 21 | dub test :arithmetic --compiler=%DC% -q 22 | dub test :strings --compiler=%DC% -q 23 | dub test :csv --compiler=%DC% -q 24 | dub test :json --compiler=%DC% -q 25 | 26 | pushd examples\composition 27 | dub test --compiler=%DC% -q 28 | popd 29 | 30 | rem TODO Actually doesn't compiles 31 | rem pushd examples\c 32 | rem dub test --compiler=%DC% -q 33 | rem popd 34 | 35 | pushd examples\dgrammar 36 | dub test --compiler=%DC% -q 37 | popd 38 | 39 | pushd examples\markdown 40 | dub test --compiler=%DC% -q 41 | popd 42 | 43 | pushd examples\oberon2 44 | dub test --compiler=%DC% -q 45 | popd 46 | 47 | pushd examples\parameterized 48 | dub test --compiler=%DC% -q 49 | popd 50 | 51 | pushd examples\PEG 52 | dub test --compiler=%DC% -q 53 | popd 54 | 55 | pushd examples\peggedgrammar 56 | dub test --compiler=%DC% -q 57 | popd 58 | 59 | pushd examples\xml 60 | dub test --compiler=%DC% -q 61 | popd 62 | 63 | echo Execute extended_pascal build 64 | pushd examples\extended_pascal 65 | rem Hack to workaround dub bug with preGenerateCommands 66 | dub build -b release --compiler=%DC% || dub build -b release --compiler=%DC% 67 | popd 68 | -------------------------------------------------------------------------------- /ci.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e -x -o pipefail 4 | 5 | DC=${DC:-dmd} 6 | 7 | # test for successful release build 8 | dub build -b release --compiler=$DC 9 | dub clean --all-packages -q 10 | 11 | # test for successful 32-bit build 12 | if [ "$DC" == "dmd" ]; then 13 | dub build -b release --compiler=$DC --arch=x86 14 | dub clean --all-packages -q 15 | fi 16 | 17 | # Run unit tests 18 | dub test --compiler=$DC 19 | 20 | # Run examples tests 21 | pushd examples/simple_arithmetic 22 | dub test --compiler=$DC -q 23 | popd 24 | 25 | dub test :arithmetic --compiler=$DC -q 26 | dub test :numbers --compiler=$DC -q 27 | dub test :strings --compiler=$DC -q 28 | dub test :csv --compiler=$DC -q 29 | dub test :json --compiler=$DC -q 30 | 31 | pushd examples/composition 32 | dub test --compiler=$DC -q 33 | popd 34 | 35 | # TODO Actually doesn't compiles 36 | # pushd examples/c 37 | # dub test --compiler=$DC -q 38 | # popd 39 | 40 | pushd examples/dgrammar 41 | dub test --compiler=$DC -q 42 | popd 43 | 44 | pushd examples/markdown 45 | dub test --compiler=$DC -q 46 | popd 47 | 48 | pushd examples/oberon2 49 | dub test --compiler=$DC -q 50 | popd 51 | 52 | pushd examples/parameterized 53 | dub test --compiler=$DC -q 54 | popd 55 | 56 | pushd examples/PEG 57 | dub test --compiler=$DC -q 58 | popd 59 | 60 | pushd examples/peggedgrammar 61 | dub test --compiler=$DC -q 62 | popd 63 | 64 | pushd examples/xml 65 | dub test --compiler=$DC -q 66 | popd 67 | 68 | # Execute extended_pascal build with time -v 69 | pushd examples/extended_pascal 70 | # Hack to workaround dub bug with preGenerateCommands 71 | dub build -b release --compiler=$DC || true 72 | /usr/bin/time -v dub build -b release --compiler=$DC 73 | popd 74 | 75 | -------------------------------------------------------------------------------- /debian/changelog: -------------------------------------------------------------------------------- 1 | dlang-pegged (0.3.1-1) unstable; urgency=low 2 | 3 | * Initial release 4 | 5 | -- Igor Khasilev Tue, 09 Feb 2016 13:45:01 -0500 6 | -------------------------------------------------------------------------------- /debian/compat: -------------------------------------------------------------------------------- 1 | 7 2 | -------------------------------------------------------------------------------- /debian/control: -------------------------------------------------------------------------------- 1 | Source: dlang-pegged 2 | Section: devel 3 | Priority: optional 4 | Maintainer: Igor Khasilev 5 | Build-Depends: debhelper (>= 7.0.50~), dmd (>=2.069.2-0) | dmd-bin (>=2.069.2-0) | gdc (>=4.9.2-2) 6 | Standards-Version: 3.8.4 7 | Homepage: https://github.com/PhilippeSigaud/Pegged 8 | 9 | Package: dlang-pegged 10 | Architecture: any 11 | Depends: 12 | Description: A Parsing Expression Grammar (PEG) module, using the D programming language. 13 | Pegged is a parsing expression grammar (PEG) generator implemented in the D programming language. 14 | The idea is to give the generator a PEG(http://en.wikipedia.org/wiki/Parsing_expression_grammar), with the syntax presented in the reference article (http://bford.info/pub/lang/peg). From this grammar definition a set of related parsers will be created, to be used at runtime or compile time. 15 | -------------------------------------------------------------------------------- /debian/copyright: -------------------------------------------------------------------------------- 1 | This work was packaged for Debian by: 2 | 3 | Igor Khasilev on Tue, 09 Feb 2016 13:45:01 -0500 4 | 5 | It was downloaded from: 6 | 7 | https://github.com/PhilippeSigaud/Pegged 8 | 9 | Upstream Author(s): 10 | 11 | Philippe Sigaud 12 | 13 | Copyright: 14 | 15 | 16 | 17 | The Debian packaging is: 18 | 19 | Copyright (C) 2016 Igor Khasilev 20 | 21 | and is licensed under the Boost 22 | see http://www.boost.org/LICENSE_1_0.txt 23 | 24 | -------------------------------------------------------------------------------- /debian/install: -------------------------------------------------------------------------------- 1 | pegged/*d usr/include/d/pegged/ 2 | pegged/dynamic usr/include/d/pegged/ 3 | libpegged.a usr/lib/ 4 | -------------------------------------------------------------------------------- /debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | # -*- makefile -*- 3 | # Sample debian/rules that uses debhelper. 4 | # This file was originally written by Joey Hess and Craig Small. 5 | # As a special exception, when this file is copied by dh-make into a 6 | # dh-make output file, you may use that output file without restriction. 7 | # This special exception was added by Craig Small in version 0.37 of dh-make. 8 | 9 | # Uncomment this to turn on verbose mode. 10 | #export DH_VERBOSE=1 11 | 12 | %: 13 | dh $@ 14 | -------------------------------------------------------------------------------- /dub.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pegged", 3 | "description": "Parsing Expression Grammar (PEG) generator", 4 | "copyright": "Copyright © 2012-2016, Philippe Sigaud", 5 | "license": "Boost", 6 | "authors": [ "Philippe Sigaud" ], 7 | "sourceFiles": [ 8 | "pegged/peg.d", 9 | "pegged/grammar.d", 10 | "pegged/parser.d", 11 | "pegged/introspection.d", 12 | "pegged/tohtml.d", 13 | "pegged/dynamic/grammar.d", 14 | "pegged/dynamic/peg.d", 15 | "pegged/tester/grammartester.d", 16 | "pegged/tester/testerparser.d" 17 | ], 18 | "importPaths": ["."], 19 | "dflags": ["-ignore"], 20 | "dflags-gdc": ["-ggdb"], 21 | "configurations": [ 22 | { 23 | "name": "default" 24 | }, 25 | { 26 | "name": "tracer", 27 | "versions": ["tracer"] 28 | } 29 | ], 30 | "subPackages": [ 31 | "examples/arithmetic", 32 | "examples/c", 33 | "examples/composition", 34 | "examples/csv", 35 | "examples/json", 36 | "examples/numbers", 37 | "examples/python", 38 | "examples/simple_arithmetic", 39 | "examples/strings", 40 | "examples/xml" 41 | ] 42 | } 43 | -------------------------------------------------------------------------------- /examples/DConf2017/README.md: -------------------------------------------------------------------------------- 1 | # Folder `pegged/examples/DConf2017` 2 | 3 | Examples as presented at [DConf 2017, Berlin](http://dconf.org/2017/talks/veelo.html). 4 | -------------------------------------------------------------------------------- /examples/DConf2017/arithmetic.d: -------------------------------------------------------------------------------- 1 | import pegged.grammar; 2 | 3 | mixin(grammar(` 4 | Arithmetic: 5 | Term < Factor (Add / Sub)* 6 | Add < "+" Factor 7 | Sub < "-" Factor 8 | Factor < Primary (Mul / Div)* 9 | Mul < "*" Primary 10 | Div < "/" Primary 11 | Primary < Parens / Neg / Number / Variable 12 | Parens < :"(" Term :")" 13 | Neg < "-" Primary 14 | Number < ~([0-9]+) 15 | Variable <- identifier 16 | `)); 17 | 18 | void main() 19 | { 20 | enum parseTree = Arithmetic("1 + 2 - (3 * 2 - 5) * 6"); 21 | 22 | float value(ParseTree p) 23 | { 24 | switch (p.name) 25 | { 26 | case "Arithmetic", "Arithmetic.Primary", "Arithmetic.Parens", "Arithmetic.Add", "Arithmetic.Mul": 27 | return value(p.children[0]); 28 | case "Arithmetic.Sub", "Arithmetic.Neg": 29 | return -value(p.children[0]); 30 | case "Arithmetic.Term": 31 | float v = 0.0; 32 | foreach(child; p.children) v += value(child); 33 | return v; 34 | case "Arithmetic.Factor": 35 | float v = 1.0; 36 | foreach(child; p.children) v *= value(child); 37 | return v; 38 | case "Arithmetic.Div": 39 | return 1.0/value(p.children[0]); 40 | case "Arithmetic.Number": 41 | import std.conv: to; 42 | return to!float(p.matches[0]); 43 | default: 44 | return float.nan; 45 | } 46 | } 47 | 48 | import std.stdio; 49 | enum answer = value(parseTree); 50 | writeln(answer); 51 | } 52 | 53 | // rdmd -I../../.. arithmetic.d -------------------------------------------------------------------------------- /examples/DConf2017/left_recursion_naive.d: -------------------------------------------------------------------------------- 1 | /* This causes infinite recursion and terminates due to stack space exhaustion. */ 2 | 3 | import pegged.peg; // Predefined parser combinators (and, or, literal). 4 | 5 | // Left-recursion: 6 | // R <- R '+n' / 'n' 7 | ParseTree R(ParseTree p) 8 | { 9 | return or!(and!(R, literal!("+n")), literal!("n"))(p); 10 | } 11 | 12 | void main() 13 | { 14 | ParseTree p = { input : "n+n" }; 15 | auto result = R(p); 16 | import std.stdio; 17 | writeln(result); 18 | } 19 | 20 | // rdmd -I../../.. ../../../libpegged.a left_recursion_naive.d 21 | -------------------------------------------------------------------------------- /examples/DConf2017/left_recursion_proper.d: -------------------------------------------------------------------------------- 1 | import pegged.peg; // Predefined parser combinators (and, or, literal). 2 | 3 | // Left-recursion: 4 | // R <- R '+n' / 'n' 5 | ParseTree R(ParseTree p) 6 | { 7 | static ParseTree[size_t /*position*/] prev; 8 | if (auto s = p.end in prev) // We are recursing. Don't evaluate R anew 9 | return *s; // return the memoized result instead. 10 | ParseTree current = fail(p); // R_{-1}. 11 | prev[p.end] = current; // Stop on next recursive call. 12 | while (true) // Controlled loop, try R with increased 13 | { // recursion bound. 14 | ParseTree result = or!(and!(R, literal!("+n")), literal!("n"))(p); 15 | if (result.end > current.end) // The match length is growing, continue. 16 | { 17 | prev[p.end] = result; // Memoize R_{n-1} for when we recurse. 18 | current = result; 19 | } 20 | else // Optimum bound exceeded, current is 21 | { // the best match. 22 | prev.remove(p.end); // Clean up. 23 | return current; // Done. 24 | } 25 | } 26 | } 27 | 28 | void main() 29 | { 30 | ParseTree p = { input : "n+n" }; 31 | auto result = R(p); 32 | import std.stdio; 33 | writeln(result); 34 | } 35 | 36 | // rdmd -I../../.. ../../../libpegged.a left_recursion_proper.d 37 | -------------------------------------------------------------------------------- /examples/DConf2017/recursion.d: -------------------------------------------------------------------------------- 1 | import pegged.peg; // Predefined parser combinators (and, or, literal). 2 | 3 | // Right-recursion: 4 | // R <- 'n+' R / 'n' 5 | ParseTree R(ParseTree p) 6 | { 7 | return 8 | or!(and!(literal!("n+"), R), literal!("n"))(p); 9 | } 10 | 11 | void main() 12 | { 13 | ParseTree p = { input : "n+n" }; 14 | auto result = R(p); 15 | import std.stdio; 16 | writeln(result); 17 | } 18 | 19 | // rdmd -I../../.. ../../../libpegged.a recursion.d 20 | -------------------------------------------------------------------------------- /examples/PEG/dub.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "PEG", 3 | "description": "The basic PEG grammar, as described by Ford.", 4 | "license": "Boost", 5 | "targetType": "library", 6 | "dependencies": { 7 | "pegged": { 8 | "version": "*", 9 | "path": "../.." 10 | } 11 | }, 12 | "dflags": [ "-preview=dip1000" ] 13 | } 14 | -------------------------------------------------------------------------------- /examples/PEG/src/pegged/examples/PEG.d: -------------------------------------------------------------------------------- 1 | module pegged.examples.PEG; 2 | 3 | import pegged.grammar; 4 | 5 | enum string PEGGgrammar =` 6 | 7 | Grammar <- S Definition+ EOI 8 | Definition <- Name Arrow Expression S 9 | Expression <- Sequence (OR Sequence)* 10 | Sequence <- Prefix+ 11 | Prefix <- (LOOKAHEAD / NOT)? Suffix 12 | Suffix <- Primary ( OPTION 13 | / ONEORMORE 14 | / ZEROORMORE )? S 15 | Primary <- Name !Arrow 16 | / GroupExpr 17 | / Literal 18 | / Class 19 | / ANY 20 | Name <- Identifier S 21 | GroupExpr <- OPEN Expression :CLOSE S 22 | Literal <- Quote (!Quote Char)* Quote S 23 | / DoubleQuote (!DoubleQuote Char)* DoubleQuote S 24 | Class <- '[' (!']' CharRange)* ']' S 25 | CharRange <- Char '-' Char / Char 26 | Char <- BackSlash ( Quote 27 | / DoubleQuote 28 | / BackQuote 29 | / BackSlash 30 | / [nrt] 31 | / [0-2][0-7][0-7] 32 | / [0-7][0-7]?) 33 | / !BackSlash . 34 | # Terminals 35 | Arrow <- "<-" S 36 | OR <- '/' S 37 | LOOKAHEAD <- '&' S 38 | NOT <- '!' S 39 | OPTION <- '?' S 40 | ZEROORMORE <- '*' S 41 | ONEORMORE <- '+' S 42 | OPEN <- '(' S 43 | CLOSE <- ')' S 44 | ANY <- '.' S 45 | # Blanks 46 | EOL <- '\r\n' / '\n' / '\r' 47 | Comment <- "#" (!EOL .)* (EOL/EOI) 48 | S <- (' ' / '\t' / EOL / Comment)* 49 | EOI <- !. 50 | `; 51 | 52 | // TODO: add unit tests on simple grammars 53 | -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | # Folder `pegged/examples` 2 | 3 | These are some grammars (and semantic actions) to show what can be done with Pegged. 4 | 5 | -------------------------------------------------------------------------------- /examples/arithmetic/dub.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "arithmetic", 3 | "description": "Example arithmetic PEG grammar. Parses arithmetic expression, like 1*(2+ x/3) - ( x * y * y -4).", 4 | "license": "Boost", 5 | "targetType": "library", 6 | "dependencies": { 7 | "pegged": { 8 | "version": "*", 9 | "path": "../.." 10 | } 11 | }, 12 | "dflags": [ "-preview=dip1000" ] 13 | } 14 | -------------------------------------------------------------------------------- /examples/arithmetic/src/pegged/examples/arithmetic.d: -------------------------------------------------------------------------------- 1 | /** 2 | This module contains a example of a reusable arithmetic expression grammar and 3 | a recursive ParseTree parser that returns the evaluation of the arithmetic expression 4 | */ 5 | module pegged.examples.arithmetic; 6 | 7 | import std.conv: to; 8 | 9 | import pegged.grammar; 10 | 11 | @safe: 12 | 13 | mixin(grammar(` 14 | # Arithmetic grammar with variable terminal 15 | Arithmetic: 16 | Term < Factor (Add / Sub)* 17 | Add < "+" Factor 18 | Sub < "-" Factor 19 | Factor < Primary (Mul / Div)* 20 | Mul < "*" Primary 21 | Div < "/" Primary 22 | Primary < Parens / Neg / Number / Variable 23 | Parens < :"(" Term :")" 24 | Neg < "-" Primary 25 | Number < ~([0-9]+) 26 | Variable <- identifier 27 | `)); 28 | 29 | mixin(grammar(` 30 | # Arithmetic grammar without variable terminal 31 | ArithmeticNoVar: 32 | Term < Factor (Add / Sub)* 33 | Add < "+" Factor 34 | Sub < "-" Factor 35 | Factor < Primary (Mul / Div)* 36 | Mul < "*" Primary 37 | Div < "/" Primary 38 | Primary < Parens / Neg / Number 39 | Parens < :"(" Term :")" 40 | Neg < "-" Primary 41 | Number < ~([0-9]+) 42 | `)); 43 | 44 | /** 45 | * Parses a ParseTree as a arithmetic expression 46 | * @param T arithmetic type. By default is float. 47 | * @param grammarName Name of the arithmetic grammar. Must be "ArithmeticNoVar" or "Arithmetic". By default is "ArithmeticNoVar" 48 | * @param ParseTree p ParseTree generated by ArithmeticNoVar 49 | * @param variable Associative array with variable values 50 | * @return The result of the arithmetic expresion. If the ParseTree is invalid 51 | * or contains unexpected nodes, then will return NaN if T is a float or 0 52 | * if T is a integral 53 | */ 54 | T parseArithmetic(T = float, string grammarName = "ArithmeticNoVar")(const ParseTree p, 55 | const T[string] variables = null) 56 | if (__traits(isArithmetic, T) && (grammarName == "ArithmeticNoVar" || grammarName == "Arithmetic")) 57 | { 58 | switch (p.name) 59 | { 60 | case grammarName: 61 | return parseArithmetic!(T, grammarName)(p.children[0], variables); 62 | case grammarName ~ ".Term": 63 | T val; 64 | static if (__traits(isFloating, T)) { 65 | val = 0.0; // float init is NaN 66 | } 67 | foreach(child; p.children) { 68 | val += parseArithmetic!(T, grammarName)(child, variables); 69 | } 70 | return val; 71 | case grammarName ~ ".Add": 72 | return parseArithmetic!(T, grammarName)(p.children[0], variables); 73 | case grammarName ~ ".Sub": 74 | return -parseArithmetic!(T, grammarName)(p.children[0], variables); 75 | case grammarName ~ ".Factor": 76 | import std.string : lastIndexOf; 77 | T val = to!T(1.0); 78 | foreach(child; p.children) { 79 | const childName = child.name[lastIndexOf(child.name, '.') + 1..$]; 80 | if (childName == "Div") { 81 | val /= parseArithmetic!(T, grammarName)(child, variables); 82 | } else { // Process Primary and Mul nodes 83 | val *= parseArithmetic!(T, grammarName)(child, variables); 84 | } 85 | } 86 | return val; 87 | case grammarName ~ ".Mul": 88 | return parseArithmetic!(T, grammarName)(p.children[0], variables); 89 | case grammarName ~ ".Div": 90 | return parseArithmetic!(T, grammarName)(p.children[0], variables); 91 | case grammarName ~ ".Primary": 92 | return parseArithmetic!(T, grammarName)(p.children[0], variables); 93 | case grammarName ~ ".Parens": 94 | return parseArithmetic!(T, grammarName)(p.children[0], variables); 95 | case grammarName ~ ".Neg": 96 | return -parseArithmetic!(T, grammarName)(p.children[0], variables); 97 | case grammarName ~ ".Number": 98 | return to!T(p.matches[0]); 99 | case grammarName ~ ".Variable": 100 | return variables[p.matches[0]]; 101 | default: 102 | return T.init; 103 | } 104 | } 105 | 106 | unittest 107 | { // Testing parsing arithmetic expression without variables 108 | string testExpression = "1 + 2 * (3 + 10 / 4)"; 109 | const pNoVar = ArithmeticNoVar(testExpression); 110 | 111 | assert(pNoVar.successful); 112 | assert(pNoVar.toString == q"EOS 113 | ArithmeticNoVar[0, 20]["1", "+", "2", "*", "3", "+", "10", "/", "4"] 114 | +-ArithmeticNoVar.Term[0, 20]["1", "+", "2", "*", "3", "+", "10", "/", "4"] 115 | +-ArithmeticNoVar.Factor[0, 2]["1"] 116 | | +-ArithmeticNoVar.Primary[0, 2]["1"] 117 | | +-ArithmeticNoVar.Number[0, 2]["1"] 118 | +-ArithmeticNoVar.Add[2, 20]["+", "2", "*", "3", "+", "10", "/", "4"] 119 | +-ArithmeticNoVar.Factor[4, 20]["2", "*", "3", "+", "10", "/", "4"] 120 | +-ArithmeticNoVar.Primary[4, 6]["2"] 121 | | +-ArithmeticNoVar.Number[4, 6]["2"] 122 | +-ArithmeticNoVar.Mul[6, 20]["*", "3", "+", "10", "/", "4"] 123 | +-ArithmeticNoVar.Primary[8, 20]["3", "+", "10", "/", "4"] 124 | +-ArithmeticNoVar.Parens[8, 20]["3", "+", "10", "/", "4"] 125 | +-ArithmeticNoVar.Term[9, 19]["3", "+", "10", "/", "4"] 126 | +-ArithmeticNoVar.Factor[9, 11]["3"] 127 | | +-ArithmeticNoVar.Primary[9, 11]["3"] 128 | | +-ArithmeticNoVar.Number[9, 11]["3"] 129 | +-ArithmeticNoVar.Add[11, 19]["+", "10", "/", "4"] 130 | +-ArithmeticNoVar.Factor[13, 19]["10", "/", "4"] 131 | +-ArithmeticNoVar.Primary[13, 16]["10"] 132 | | +-ArithmeticNoVar.Number[13, 16]["10"] 133 | +-ArithmeticNoVar.Div[16, 19]["/", "4"] 134 | +-ArithmeticNoVar.Primary[18, 19]["4"] 135 | +-ArithmeticNoVar.Number[18, 19]["4"] 136 | EOS"); 137 | 138 | // Parsing as a float 139 | const f = parseArithmetic(pNoVar); 140 | assert(f == 12.0f); 141 | 142 | // Parsing as integer 143 | const i = parseArithmetic!int(pNoVar); 144 | assert(i == 11); 145 | } 146 | 147 | unittest 148 | { 149 | // Testing parsing arithmetic expression witht variables 150 | 151 | string testExpressionWithVar = "1 + 2 * (3 + 10 / 4) + fooBar"; 152 | const p = Arithmetic(testExpressionWithVar); 153 | 154 | assert(p.successful); 155 | assert(p.toString == q"EOS 156 | Arithmetic[0, 29]["1", "+", "2", "*", "3", "+", "10", "/", "4", "+", "fooBar"] 157 | +-Arithmetic.Term[0, 29]["1", "+", "2", "*", "3", "+", "10", "/", "4", "+", "fooBar"] 158 | +-Arithmetic.Factor[0, 2]["1"] 159 | | +-Arithmetic.Primary[0, 2]["1"] 160 | | +-Arithmetic.Number[0, 2]["1"] 161 | +-Arithmetic.Add[2, 21]["+", "2", "*", "3", "+", "10", "/", "4"] 162 | | +-Arithmetic.Factor[4, 21]["2", "*", "3", "+", "10", "/", "4"] 163 | | +-Arithmetic.Primary[4, 6]["2"] 164 | | | +-Arithmetic.Number[4, 6]["2"] 165 | | +-Arithmetic.Mul[6, 21]["*", "3", "+", "10", "/", "4"] 166 | | +-Arithmetic.Primary[8, 21]["3", "+", "10", "/", "4"] 167 | | +-Arithmetic.Parens[8, 21]["3", "+", "10", "/", "4"] 168 | | +-Arithmetic.Term[9, 19]["3", "+", "10", "/", "4"] 169 | | +-Arithmetic.Factor[9, 11]["3"] 170 | | | +-Arithmetic.Primary[9, 11]["3"] 171 | | | +-Arithmetic.Number[9, 11]["3"] 172 | | +-Arithmetic.Add[11, 19]["+", "10", "/", "4"] 173 | | +-Arithmetic.Factor[13, 19]["10", "/", "4"] 174 | | +-Arithmetic.Primary[13, 16]["10"] 175 | | | +-Arithmetic.Number[13, 16]["10"] 176 | | +-Arithmetic.Div[16, 19]["/", "4"] 177 | | +-Arithmetic.Primary[18, 19]["4"] 178 | | +-Arithmetic.Number[18, 19]["4"] 179 | +-Arithmetic.Add[21, 29]["+", "fooBar"] 180 | +-Arithmetic.Factor[23, 29]["fooBar"] 181 | +-Arithmetic.Primary[23, 29]["fooBar"] 182 | +-Arithmetic.Variable[23, 29]["fooBar"] 183 | EOS"); 184 | 185 | // Parsing as a float 186 | const float[string] fVars = ["fooBar": 10.25f]; 187 | const fWithVar = parseArithmetic!(float, "Arithmetic")(p, fVars ); 188 | 189 | assert(fWithVar == 22.25f); 190 | 191 | // Parsing as integer 192 | const iVars = ["fooBar": 10]; 193 | const iWithVar = parseArithmetic!(int, "Arithmetic")(p, iVars); 194 | 195 | assert(iWithVar == 21); 196 | } 197 | 198 | 199 | unittest 200 | { 201 | // Some additional test borrowed from simple_arithmetic 202 | float interpreter(string expr) => ArithmeticNoVar(expr).parseArithmetic; 203 | 204 | assert(interpreter("1") == 1.0); 205 | assert(interpreter("-1") == -1.0); 206 | assert(interpreter("1+1") == 2.0); 207 | assert(interpreter("1-1") == 0.0); 208 | 209 | assert(interpreter("1+1+1") == 3.0); 210 | assert(interpreter("1-1-1") == -1.0); 211 | assert(interpreter("1+1-1") == 1.0); 212 | assert(interpreter("1-1+1") == 1.0); 213 | assert(interpreter("-1+1+1") == 1.0); 214 | 215 | assert(interpreter("(-1+1)+1") == 1.0); 216 | assert(interpreter("-1+(1+1)") == 1.0); 217 | assert(interpreter("(-1+1+1)") == 1.0); 218 | assert(interpreter("1-(1-1)") == 1.0); 219 | 220 | assert(interpreter("1*1") == 1.0); 221 | assert(interpreter("1/1") == 1.0); 222 | assert(interpreter("-1*1") == -1.0); 223 | assert(interpreter("-1/1") == -1.0); 224 | 225 | assert(interpreter("1+2*3") == 7.0); 226 | assert(interpreter("1-2*3") == -5.0); 227 | assert(interpreter("-1-2*-3") == 5.0); 228 | assert(interpreter("-1+2*-3") == -7.0); 229 | 230 | assert(interpreter("1/2/(1/2)") == 1.0); 231 | assert(interpreter("1/2/1/2") == .25); 232 | assert(interpreter("1 - 2*3 - 2*3") == -11.0); 233 | 234 | assert(interpreter("2*3*3 - 3*3 + 3*4") == 21.0); 235 | assert(interpreter("2 * 3 * 3 - 3 * (3 + 3 * 4)") == -27.0); 236 | } 237 | -------------------------------------------------------------------------------- /examples/c/dub.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "c", 3 | "description": " A simple C grammar, most probably full of bugs.", 4 | "license": "Boost", 5 | "targetType": "library", 6 | "dependencies": { 7 | "pegged": { 8 | "version": "*", 9 | "path": "../.." 10 | } 11 | }, 12 | "dflags": [ "-preview=dip1000" ] 13 | } 14 | -------------------------------------------------------------------------------- /examples/c/src/pegged/examples/c.d: -------------------------------------------------------------------------------- 1 | module pegged.examples.c; 2 | 3 | import pegged.grammar; 4 | 5 | enum Cgrammar = ` 6 | C: 7 | 8 | TranslationUnit <- ExternalDeclaration (:Spacing ExternalDeclaration)* 9 | 10 | ExternalDeclaration < FunctionDefinition / Declaration 11 | 12 | FunctionDefinition < DeclarationSpecifiers? Declarator DeclarationList? CompoundStatement 13 | 14 | PrimaryExpression < Identifier 15 | / CharLiteral 16 | / StringLiteral 17 | / FloatLiteral 18 | / IntegerLiteral 19 | / '(' Expression ')' 20 | 21 | PostfixExpression < PrimaryExpression ( '[' Expression ']' 22 | / '(' ')' 23 | / '(' ArgumentExpressionList ')' 24 | / '.' Identifier 25 | / "->" Identifier 26 | / "++" 27 | / "--" 28 | )* 29 | 30 | ArgumentExpressionList < AssignmentExpression (',' AssignmentExpression)* 31 | 32 | UnaryExpression < PostfixExpression 33 | / IncrementExpression 34 | / DecrementExpression 35 | / UnaryOperator CastExpression 36 | / "sizeof" UnaryExpression 37 | / "sizeof" '(' TypeName ')' 38 | 39 | IncrementExpression < PlusPlus UnaryExpression 40 | PlusPlus <- "++" 41 | DecrementExpression < "--" UnaryExpression 42 | 43 | UnaryOperator <- [-&*+~!] 44 | 45 | CastExpression < UnaryExpression 46 | / '(' TypeName ')' CastExpression 47 | 48 | MultiplicativeExpression < CastExpression ([*%/] MultiplicativeExpression)* 49 | 50 | AdditiveExpression < MultiplicativeExpression ([-+] AdditiveExpression)* 51 | 52 | ShiftExpression < AdditiveExpression (("<<" / ">>") ShiftExpression)* 53 | 54 | RelationalExpression < ShiftExpression (("<=" / ">=" / "<" / ">") RelationalExpression)* 55 | 56 | EqualityExpression < RelationalExpression (("==" / "!=") EqualityExpression)* 57 | 58 | ANDExpression < EqualityExpression ('&' ANDExpression)* 59 | 60 | ExclusiveORExpression < ANDExpression ('^' ExclusiveORExpression)* 61 | 62 | InclusiveORExpression < ExclusiveORExpression ('|' InclusiveORExpression)* 63 | 64 | LogicalANDExpression < InclusiveORExpression ("&&" LogicalANDExpression)* 65 | 66 | LogicalORExpression < LogicalANDExpression ("||" LogicalORExpression)* 67 | 68 | ConditionalExpression < LogicalORExpression ('?' Expression ':' ConditionalExpression)? 69 | 70 | AssignmentExpression < UnaryExpression AssignmentOperator AssignmentExpression 71 | / ConditionalExpression 72 | 73 | AssignmentOperator <- "=" / "*=" / "/=" / "%=" / "+=" / "-=" / "<<=" / ">>=" / "&=" / "^=" / "|=" 74 | 75 | Expression < AssignmentExpression (',' AssignmentExpression)* 76 | 77 | ConstantExpression <- ConditionalExpression 78 | 79 | # 80 | # C declaration rules 81 | # 82 | 83 | Declaration < DeclarationSpecifiers InitDeclaratorList? ';' 84 | 85 | DeclarationSpecifiers < ( StorageClassSpecifier 86 | / TypeSpecifier 87 | / TypeQualifier 88 | ) DeclarationSpecifiers? 89 | 90 | InitDeclaratorList < InitDeclarator (',' InitDeclarator)* 91 | 92 | InitDeclarator < Declarator ('=' Initializer)? 93 | 94 | StorageClassSpecifier <- "typedef" / "extern" / "static" / "auto" / "register" 95 | 96 | TypeSpecifier <- "void" 97 | / "char" / "short" / "int" / "long" 98 | / "float" / "double" 99 | / "signed" / "unsigned" 100 | / StructOrUnionSpecifier 101 | / EnumSpecifier 102 | #/ TypedefName # To reactivate with an associated semantic action: 103 | # - keep a list of typedef'd names 104 | # - and verify that the read identifier is already defined 105 | 106 | StructOrUnionSpecifier < ("struct" / "union") ( Identifier ('{' StructDeclarationList '}')? 107 | / '{' StructDeclarationList '}') 108 | 109 | StructDeclarationList <- StructDeclaration (:Spacing StructDeclaration)* 110 | 111 | StructDeclaration < SpecifierQualifierList StructDeclaratorList ';' 112 | 113 | SpecifierQualifierList <- (TypeQualifier / TypeSpecifier) (:Spacing (TypeQualifier / TypeSpecifier))* 114 | 115 | StructDeclaratorList < StructDeclarator (',' StructDeclarator)* 116 | 117 | StructDeclarator < ( Declarator ConstantExpression? 118 | / ConstantExpression) 119 | 120 | EnumSpecifier < "enum" ( Identifier ('{' EnumeratorList '}')? 121 | / '{' EnumeratorList '}') 122 | 123 | EnumeratorList < Enumerator (',' Enumerator)* 124 | 125 | Enumerator < EnumerationConstant ('=' ConstantExpression)? 126 | 127 | EnumerationConstant <- Identifier 128 | 129 | TypeQualifier <- "const" / "volatile" 130 | 131 | Declarator < Pointer? DirectDeclarator 132 | 133 | DirectDeclarator < (Identifier / '(' Declarator ')') ( '[' ']' 134 | / '[' ConstantExpression ']' 135 | / '(' ')' 136 | / '(' ParameterTypeList ')' 137 | / '(' IdentifierList ')' 138 | )* 139 | 140 | Pointer < ('*' TypeQualifier*)* 141 | 142 | TypeQualifierList <- TypeQualifier (:Spacing TypeQualifier)* 143 | 144 | ParameterTypeList < ParameterList (',' "...")? 145 | 146 | ParameterList < ParameterDeclaration (',' ParameterDeclaration)* 147 | 148 | ParameterDeclaration < DeclarationSpecifiers (Declarator / AbstractDeclarator)? 149 | 150 | IdentifierList < Identifier (',' Identifier)* 151 | 152 | TypeName < SpecifierQualifierList AbstractDeclarator? 153 | 154 | AbstractDeclarator < Pointer DirectAbstractDeclarator 155 | / DirectAbstractDeclarator 156 | / Pointer 157 | 158 | DirectAbstractDeclarator < ('(' AbstractDeclarator ')' 159 | / '[' ']' 160 | / '[' ConstantExpression ']' 161 | / '(' ')' 162 | / '(' ParameterTypeList ')' 163 | ) 164 | ( '[' ']' 165 | / '[' ConstantExpression ']' 166 | / '(' ')' 167 | / '(' ParameterTypeList ')' 168 | )* 169 | 170 | TypedefName <- Identifier 171 | 172 | Initializer < AssignmentExpression 173 | / '{' InitializerList ','? '}' 174 | 175 | InitializerList < Initializer (',' Initializer)* 176 | 177 | # 178 | # C statement rules 179 | # 180 | 181 | Statement < LabeledStatement 182 | / CompoundStatement 183 | / ExpressionStatement 184 | / IfStatement 185 | / SwitchStatement 186 | / IterationStatement 187 | / GotoStatement 188 | / ContinueStatement 189 | / BreakStatement 190 | / ReturnStatement 191 | 192 | LabeledStatement < Identifier ':' Statement 193 | / 'case' ConstantExpression ':' Statement 194 | / 'default' ':' Statement 195 | 196 | CompoundStatement < '{' '}' 197 | / '{' DeclarationList '}' 198 | / '{' StatementList '}' 199 | / '{' DeclarationList StatementList '}' 200 | 201 | DeclarationList <- Declaration (:Spacing Declaration)* 202 | 203 | StatementList <- Statement (:Spacing Statement)* 204 | 205 | ExpressionStatement < Expression? ';' 206 | 207 | IfStatement < "if" '(' Expression ')' Statement ('else' Statement)? 208 | 209 | SwitchStatement < "switch" '(' Expression ')' Statement 210 | 211 | IterationStatement < WhileStatement / DoStatement / ForStatement 212 | 213 | WhileStatement < "while" '(' Expression ')' Statement 214 | 215 | DoStatement < "do" Statement "while" '(' Expression ')' ';' 216 | 217 | ForStatement < "for" '(' Expression? ';' Expression? ';' Expression? ')' Statement 218 | 219 | GotoStatement < "goto" Identifier ';' 220 | 221 | ContinueStatement < "continue" ';' 222 | 223 | BreakStatement < "break" ';' 224 | 225 | ReturnStatement < Return Expression? :';' 226 | 227 | Return <- "return" 228 | 229 | # The following comes from me, not an official C grammar 230 | 231 | IdentifierStart <~ [a-zA-Z_] 232 | IdentifierCont <~ [a-zA-Z0-9_]+ 233 | Identifier <~ !(Keyword !IdentifierCont) IdentifierStart IdentifierCont? 234 | 235 | Keyword <- "auto" / "break" / "case" / "char" / "const" / "continue" 236 | / "default" / "double" / "do" / "else" / "enum" / "extern" 237 | / "float" / "for" / "goto" / "if" / "inline" / "int" / "long" 238 | / "register" / "restrict" / "return" / "short" / "signed" 239 | / "sizeof" / "static" / "struct" / "switch" / "typedef" / "union" 240 | / "unsigned" / "void" / "volatile" / "while" 241 | / "_Bool" / "_Complex" / "_Imaginary" 242 | 243 | Spacing <~ (space / endOfLine / Comment)* 244 | 245 | Comment <~ "//" (!endOfLine .)* endOfLine 246 | 247 | StringLiteral <~ doublequote (DQChar)* doublequote 248 | 249 | DQChar <- EscapeSequence 250 | / !doublequote . 251 | 252 | EscapeSequence <~ backslash ( quote 253 | / doublequote 254 | / backslash 255 | / [abfnrtv] 256 | ) 257 | 258 | CharLiteral <~ quote (!quote (EscapeSequence / .)) quote 259 | 260 | IntegerLiteral <~ Sign? Integer IntegerSuffix? 261 | 262 | Integer <~ digit+ 263 | 264 | IntegerSuffix <- "Lu" / "LU" / "uL" / "UL" 265 | / "L" / "u" / "U" 266 | 267 | FloatLiteral <~ Sign? Integer "." Integer? (("e" / "E") Sign? Integer)? 268 | 269 | Sign <- "-" / "+" 270 | `; 271 | 272 | unittest 273 | { 274 | import pegged.tester.grammartester: GrammarTester; 275 | 276 | mixin(grammar(Cgrammar)); 277 | 278 | auto tester = new GrammarTester!(C, "FunctionDefinition"); 279 | 280 | const code = ` 281 | static int * f() { 282 | int a; 283 | a = 2 + 2; 284 | return &a; 285 | } 286 | `; 287 | 288 | tester.assertSimilar(code, ` 289 | FunctionDefinition-> 290 | { 291 | DeclarationSpecifiers->{ 292 | StorageClassSpecifier // static 293 | DeclarationSpecifiers->TypeSpecifier // int 294 | } 295 | Declarator->{Pointer DirectDeclarator->{..}} // *f() 296 | CompoundStatement->{ // f body 297 | DeclarationList->{..} // int a; 298 | StatementList->{ 299 | Statement->{..} // a = 2 + 2; 300 | Statement->ReturnStatement->{ // return &a; 301 | Return 302 | Expression->{..} 303 | } 304 | } 305 | } 306 | } 307 | `); 308 | } 309 | -------------------------------------------------------------------------------- /examples/composition/dub.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "composition", 3 | "description": "Example of grammar composition on Pegged", 4 | "license": "Boost", 5 | "targetType": "library", 6 | "dependencies": { 7 | "pegged": { 8 | "version": "*", 9 | "path": "../.." 10 | }, 11 | "pegged:strings": { 12 | "version": "*", 13 | "path": "../.." 14 | }, 15 | "pegged:numbers": { 16 | "version": "*", 17 | "path": "../.." 18 | } 19 | }, 20 | "dflags": [ "-preview=dip1000" ] 21 | } 22 | -------------------------------------------------------------------------------- /examples/composition/src/pegged/examples/composition.d: -------------------------------------------------------------------------------- 1 | /** 2 | * Example of grammar composition in Pegged 3 | */ 4 | module pegged.examples.composition; 5 | 6 | import pegged.grammar; 7 | import pegged.examples.strings, pegged.examples.numbers; 8 | 9 | @safe: 10 | 11 | mixin(grammar(` 12 | LOG: 13 | LogFile <- LogLine+ eoi 14 | LogLine < String ':' Numbers (',' Numbers)* eol? 15 | `)); 16 | 17 | unittest 18 | { 19 | auto log =` 20 | "File1": 0.00, 0.01, 0.00, 0.00 21 | "File2": 1.0, 2.0, 3.14 22 | "File3": 0.00, 10 23 | `; 24 | assert(LOG(log).successful); 25 | } 26 | 27 | enum g = grammar(` 28 | LOG2: 29 | LogFile <- LogLine+ eoi 30 | LogLine < String Numbers.Hexa ':' Numbers (',' Numbers)* 31 | `); 32 | mixin(g); 33 | 34 | unittest 35 | { 36 | enum log =` 37 | "File1" 123AC7AF : 123, 78.265, 0.00 38 | "File2" 31F039DC9BE : 49.45, 42.220, 0.02, -22.3 39 | "File3" D0043869930 : 0 40 | `; 41 | assert(LOG2(log).successful); 42 | } 43 | 44 | -------------------------------------------------------------------------------- /examples/csv/dub.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "csv", 3 | "description": "Example CSV PEG grammar.", 4 | "license": "Boost", 5 | "targetType": "library", 6 | "dependencies": { 7 | "pegged": { 8 | "version": "*", 9 | "path": "../.." 10 | } 11 | }, 12 | "dflags": [ "-preview=dip1000" ] 13 | } 14 | -------------------------------------------------------------------------------- /examples/csv/src/pegged/examples/csv.d: -------------------------------------------------------------------------------- 1 | module pegged.examples.csv; 2 | 3 | import pegged.grammar; 4 | 5 | @safe: 6 | 7 | mixin(grammar(` 8 | CSV: 9 | 10 | CsvFile <- Line* LastLine 11 | Line <- :S* Item (:Sep Item)* :endOfLine 12 | LastLine <- :S* Item (:Sep Item)* eoi 13 | Item <- SimpleField 14 | / QuotedField 15 | / EmptyField 16 | SimpleField <~ (!eoi !endOfLine !S !',' !doublequote .)+ :S* 17 | QuotedField <~ doublequote EscapedField doublequote :S* 18 | EscapedField <~ SubField (doublequote doublequote SubField)* 19 | SubField <~ (!doublequote !eoi .)+ 20 | EmptyField <- eps :S* 21 | 22 | Sep <- ',' :S* 23 | S <- (' ' / '\t') 24 | `)); 25 | 26 | unittest 27 | { 28 | const csv1 = CSV("a,b,c"); 29 | assert(csv1.successful); 30 | assert(csv1.toString == q"EOS 31 | CSV[0, 5]["a", "b", "c"] 32 | +-CSV.CsvFile[0, 5]["a", "b", "c"] 33 | +-CSV.LastLine[0, 5]["a", "b", "c"] 34 | +-CSV.Item[0, 1]["a"] 35 | | +-CSV.SimpleField[0, 1]["a"] 36 | +-CSV.Item[2, 3]["b"] 37 | | +-CSV.SimpleField[2, 3]["b"] 38 | +-CSV.Item[4, 5]["c"] 39 | +-CSV.SimpleField[4, 5]["c"] 40 | EOS"); 41 | 42 | const csv2 = CSV("a1,b2,c3, 3.14159"); 43 | assert(csv2.successful); 44 | assert(csv2.toString == q"EOS 45 | CSV[0, 17]["a1", "b2", "c3", "3.14159"] 46 | +-CSV.CsvFile[0, 17]["a1", "b2", "c3", "3.14159"] 47 | +-CSV.LastLine[0, 17]["a1", "b2", "c3", "3.14159"] 48 | +-CSV.Item[0, 2]["a1"] 49 | | +-CSV.SimpleField[0, 2]["a1"] 50 | +-CSV.Item[3, 5]["b2"] 51 | | +-CSV.SimpleField[3, 5]["b2"] 52 | +-CSV.Item[6, 8]["c3"] 53 | | +-CSV.SimpleField[6, 8]["c3"] 54 | +-CSV.Item[10, 17]["3.14159"] 55 | +-CSV.SimpleField[10, 17]["3.14159"] 56 | EOS"); 57 | 58 | const csv3 = CSV(`a1,,,b2,c3, 3.14159, άλφα, "abc", "abc""def"`); 59 | assert(csv3.successful); 60 | assert(csv3.toString == q"EOS 61 | CSV[0, 48]["a1", "", "", "b2", "c3", "3.14159", "άλφα", "\"abc\"", "\"abc\"\"def\""] 62 | +-CSV.CsvFile[0, 48]["a1", "", "", "b2", "c3", "3.14159", "άλφα", "\"abc\"", "\"abc\"\"def\""] 63 | +-CSV.LastLine[0, 48]["a1", "", "", "b2", "c3", "3.14159", "άλφα", "\"abc\"", "\"abc\"\"def\""] 64 | +-CSV.Item[0, 2]["a1"] 65 | | +-CSV.SimpleField[0, 2]["a1"] 66 | +-CSV.Item[3, 3][""] 67 | | +-CSV.EmptyField[3, 3][""] 68 | +-CSV.Item[4, 4][""] 69 | | +-CSV.EmptyField[4, 4][""] 70 | +-CSV.Item[5, 7]["b2"] 71 | | +-CSV.SimpleField[5, 7]["b2"] 72 | +-CSV.Item[8, 10]["c3"] 73 | | +-CSV.SimpleField[8, 10]["c3"] 74 | +-CSV.Item[12, 19]["3.14159"] 75 | | +-CSV.SimpleField[12, 19]["3.14159"] 76 | +-CSV.Item[21, 29]["άλφα"] 77 | | +-CSV.SimpleField[21, 29]["άλφα"] 78 | +-CSV.Item[31, 36]["\"abc\""] 79 | | +-CSV.QuotedField[31, 36]["\"abc\""] 80 | +-CSV.Item[38, 48]["\"abc\"\"def\""] 81 | +-CSV.QuotedField[38, 48]["\"abc\"\"def\""] 82 | EOS"); 83 | 84 | const csv4 = CSV("1,2,3,"); 85 | assert(csv4.successful); 86 | assert(csv4.toString == q"EOS 87 | CSV[0, 6]["1", "2", "3", ""] 88 | +-CSV.CsvFile[0, 6]["1", "2", "3", ""] 89 | +-CSV.LastLine[0, 6]["1", "2", "3", ""] 90 | +-CSV.Item[0, 1]["1"] 91 | | +-CSV.SimpleField[0, 1]["1"] 92 | +-CSV.Item[2, 3]["2"] 93 | | +-CSV.SimpleField[2, 3]["2"] 94 | +-CSV.Item[4, 5]["3"] 95 | | +-CSV.SimpleField[4, 5]["3"] 96 | +-CSV.Item[6, 6][""] 97 | +-CSV.EmptyField[6, 6][""] 98 | EOS"); 99 | 100 | const csv5 = CSV("1,2,,3"); 101 | assert(csv5.successful); 102 | assert(csv5.toString == q"EOS 103 | CSV[0, 6]["1", "2", "", "3"] 104 | +-CSV.CsvFile[0, 6]["1", "2", "", "3"] 105 | +-CSV.LastLine[0, 6]["1", "2", "", "3"] 106 | +-CSV.Item[0, 1]["1"] 107 | | +-CSV.SimpleField[0, 1]["1"] 108 | +-CSV.Item[2, 3]["2"] 109 | | +-CSV.SimpleField[2, 3]["2"] 110 | +-CSV.Item[4, 4][""] 111 | | +-CSV.EmptyField[4, 4][""] 112 | +-CSV.Item[5, 6]["3"] 113 | +-CSV.SimpleField[5, 6]["3"] 114 | EOS"); 115 | 116 | const csv6 = CSV("1,,,,,"); 117 | assert(csv6.successful); 118 | assert(csv6.toString == q"EOS 119 | CSV[0, 6]["1", "", "", "", "", ""] 120 | +-CSV.CsvFile[0, 6]["1", "", "", "", "", ""] 121 | +-CSV.LastLine[0, 6]["1", "", "", "", "", ""] 122 | +-CSV.Item[0, 1]["1"] 123 | | +-CSV.SimpleField[0, 1]["1"] 124 | +-CSV.Item[2, 2][""] 125 | | +-CSV.EmptyField[2, 2][""] 126 | +-CSV.Item[3, 3][""] 127 | | +-CSV.EmptyField[3, 3][""] 128 | +-CSV.Item[4, 4][""] 129 | | +-CSV.EmptyField[4, 4][""] 130 | +-CSV.Item[5, 5][""] 131 | | +-CSV.EmptyField[5, 5][""] 132 | +-CSV.Item[6, 6][""] 133 | +-CSV.EmptyField[6, 6][""] 134 | EOS"); 135 | 136 | const csv7 = CSV(",1"); 137 | assert(csv7.successful); 138 | assert(csv7.toString == q"EOS 139 | CSV[0, 2]["", "1"] 140 | +-CSV.CsvFile[0, 2]["", "1"] 141 | +-CSV.LastLine[0, 2]["", "1"] 142 | +-CSV.Item[0, 0][""] 143 | | +-CSV.EmptyField[0, 0][""] 144 | +-CSV.Item[1, 2]["1"] 145 | +-CSV.SimpleField[1, 2]["1"] 146 | EOS"); 147 | 148 | const csv8 = CSV(""); 149 | assert(csv8.successful); 150 | assert(csv8.toString == q"EOS 151 | CSV[0, 0][""] 152 | +-CSV.CsvFile[0, 0][""] 153 | +-CSV.LastLine[0, 0][""] 154 | +-CSV.Item[0, 0][""] 155 | +-CSV.EmptyField[0, 0][""] 156 | EOS"); 157 | 158 | auto p1 = CSV( 159 | "1, 2 , 3 160 | 4, 5, 6,, 161 | 7"); 162 | 163 | assert(p1[0].children.length == 3); // 3 lines 164 | assert(p1[0][0].matches == ["1", "2", "3"]); 165 | assert(p1[0][1].matches == ["4","5","6","",""]); 166 | assert(p1[0][2].matches == ["7"]); 167 | assert(p1.toString == q"EOS 168 | CSV[0, 23]["1", "2", "3", "4", "5", "6", "", "", "7"] 169 | +-CSV.CsvFile[0, 23]["1", "2", "3", "4", "5", "6", "", "", "7"] 170 | +-CSV.Line[0, 9]["1", "2", "3"] 171 | | +-CSV.Item[0, 1]["1"] 172 | | | +-CSV.SimpleField[0, 1]["1"] 173 | | +-CSV.Item[3, 5]["2"] 174 | | | +-CSV.SimpleField[3, 5]["2"] 175 | | +-CSV.Item[7, 8]["3"] 176 | | +-CSV.SimpleField[7, 8]["3"] 177 | +-CSV.Line[9, 21]["4", "5", "6", "", ""] 178 | | +-CSV.Item[10, 11]["4"] 179 | | | +-CSV.SimpleField[10, 11]["4"] 180 | | +-CSV.Item[13, 14]["5"] 181 | | | +-CSV.SimpleField[13, 14]["5"] 182 | | +-CSV.Item[17, 18]["6"] 183 | | | +-CSV.SimpleField[17, 18]["6"] 184 | | +-CSV.Item[19, 19][""] 185 | | | +-CSV.EmptyField[19, 19][""] 186 | | +-CSV.Item[20, 20][""] 187 | | +-CSV.EmptyField[20, 20][""] 188 | +-CSV.LastLine[21, 23]["7"] 189 | +-CSV.Item[22, 23]["7"] 190 | +-CSV.SimpleField[22, 23]["7"] 191 | EOS"); 192 | 193 | const csv9 = CSV("1, 194 | 2, 195 | 3, 196 | 4, 197 | "); 198 | assert(csv9.successful); 199 | assert((csv9.toString == q"EOS 200 | CSV[0, 100]["1", "", "2", "", "3", "", "4", "", ""] 201 | +-CSV.CsvFile[0, 100]["1", "", "2", "", "3", "", "4", "", ""] 202 | +-CSV.Line[0, 3]["1", ""] 203 | | +-CSV.Item[0, 1]["1"] 204 | | | +-CSV.SimpleField[0, 1]["1"] 205 | | +-CSV.Item[2, 2][""] 206 | | +-CSV.EmptyField[2, 2][""] 207 | +-CSV.Line[3, 28]["2", ""] 208 | | +-CSV.Item[25, 26]["2"] 209 | | | +-CSV.SimpleField[25, 26]["2"] 210 | | +-CSV.Item[27, 27][""] 211 | | +-CSV.EmptyField[27, 27][""] 212 | +-CSV.Line[28, 53]["3", ""] 213 | | +-CSV.Item[50, 51]["3"] 214 | | | +-CSV.SimpleField[50, 51]["3"] 215 | | +-CSV.Item[52, 52][""] 216 | | +-CSV.EmptyField[52, 52][""] 217 | +-CSV.Line[53, 78]["4", ""] 218 | | +-CSV.Item[75, 76]["4"] 219 | | | +-CSV.SimpleField[75, 76]["4"] 220 | | +-CSV.Item[77, 77][""] 221 | | +-CSV.EmptyField[77, 77][""] 222 | +-CSV.LastLine[78, 100][""] 223 | +-CSV.Item[100, 100][""] 224 | +-CSV.EmptyField[100, 100][""] 225 | EOS")); 226 | 227 | const csv10 = CSV("1 2 3"); 228 | assert(!csv10.successful); 229 | assert(csv10.toString == q"EOS 230 | CSV (failure) 231 | +-CSV.CsvFile (failure) 232 | +-zeroOrMore!(CSV.Line)[0, 0][] 233 | +-CSV.LastLine (failure) 234 | +-CSV.Item[0, 2]["1"] 235 | | +-CSV.SimpleField[0, 2]["1"] 236 | +-eoi Failure at line 0, col 2, after "1 " expected "end of input", but got "2 3" 237 | EOS"); 238 | } 239 | -------------------------------------------------------------------------------- /examples/dgrammar/dub.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dgrammar", 3 | "description": "It's a first pass through the http://dlang.org online spec. It's about 500 rules long! And hasn't been update. ", 4 | "license": "Boost", 5 | "targetType": "library", 6 | "dependencies": { 7 | "pegged": { 8 | "version": "*", 9 | "path": "../.." 10 | } 11 | }, 12 | "dflags": [ "-preview=dip1000" ] 13 | } 14 | -------------------------------------------------------------------------------- /examples/extended_pascal/.gitattributes: -------------------------------------------------------------------------------- 1 | example.pas text eol=lf 2 | -------------------------------------------------------------------------------- /examples/extended_pascal/.gitignore: -------------------------------------------------------------------------------- 1 | .dub 2 | docs.json 3 | __dummy.html 4 | *.o 5 | *.obj 6 | *.pdb 7 | __test__*__ 8 | parse_ep 9 | source/epparser.d 10 | /example.txt 11 | /example.html 12 | /TraceLog.txt 13 | -------------------------------------------------------------------------------- /examples/extended_pascal/README.md: -------------------------------------------------------------------------------- 1 | # Folder `pegged/examples/extended_pascal` 2 | 3 | ## An example parser for ISO 10206:1990 Extended Pascal. 4 | 5 | This grammar features several cases of (indirect) left-recursion. It is also 6 | ambiguous. Normally, this ambiguity would be resolved by using a symbol table 7 | and possibly semantic analysis, which is omitted in this example. So the syntax 8 | table generated by this parser is not necessarily identical to the one 9 | constructed by an Extended Pascal compiler. 10 | 11 | The command `dub build` initiates a two-step build process: 12 | 13 | 1. The file `source/make.d` is compiled and executed. This produces the parser 14 | module `epparser.d` from the grammar file `epgrammar.d`. 15 | 2. The `parse_ep` parser application is built from `app.d` and `epparser.d`. 16 | 17 | The parser is able to produce the AST in two different formats: 18 | 19 | > `parse_ep --text example.pas` 20 | 21 | produces a text file `example.txt` (this is the default, `--text` is optional) 22 | and 23 | 24 | > `parse_ep --html example.pas` 25 | 26 | produces an expandable tree using HTML5 in [`example.html`](https://cdn.rawgit.com/PhilippeSigaud/Pegged/ade2aa5d/pegged/examples/extended_pascal/example.html). 27 | Please browse with a 28 | browser that supports the 29 | [<details>](https://www.w3schools.com/tags/tag_details.asp) tag. 30 | -------------------------------------------------------------------------------- /examples/extended_pascal/dub.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "parse_ep", 3 | "authors": [ 4 | "Bastiaan Veelo" 5 | ], 6 | "dependencies": { 7 | "pegged": { 8 | "version": "*", 9 | "path": "../.." 10 | } 11 | }, 12 | "dflags": [ "-preview=dip1000" ], 13 | "preGenerateCommands": [ 14 | "rdmd -I$PEGGED_PACKAGE_DIR source/make.d" 15 | ], 16 | "excludedSourceFiles": [ 17 | "source/make.d", 18 | "source/epgrammar.d" 19 | ], 20 | "description": "Example parser for Extended Pascal.", 21 | "copyright": "Copyright © 2017, Bastiaan Veelo", 22 | "license": "Boost License 1.0", 23 | "targetType": "executable", 24 | "configurations": [ 25 | { 26 | "name": "default" 27 | }, 28 | { 29 | "name": "tracer", 30 | "versions": ["tracer"], 31 | "subConfigurations": { 32 | "pegged": "tracer" 33 | } 34 | } 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /examples/extended_pascal/example.pas: -------------------------------------------------------------------------------- 1 | PROGRAM arrayc (output); 2 | 3 | { Extended Pascal examples http://ideone.com/YXpi4n } 4 | { Array constant & constant access } 5 | 6 | TYPE days = (sun,mon {First work day},tues,weds,thurs,fri, {Party!} sat); 7 | dname = string(8); 8 | 9 | VAR d: days; 10 | 11 | FUNCTION DayName (fd: days): dname; 12 | { Elements of the array constant DayNames can be 13 | selected with a variable index } 14 | TYPE abbrevs = ARRAY [days] OF 15 | PACKED ARRAY [1..5] OF char; 16 | CONST DayNames = abbrevs 17 | [ sun: 'Sun'; mon: 'Mon'; tues: 'Tues'; 18 | weds: 'Weds'; thurs: 'Thurs'; fri: 'Fri'; 19 | sat: 'Satur' ]; 20 | BEGIN 21 | DayName := trim(DayNames[fd]) + 'day'; 22 | END {DayName}; 23 | 24 | BEGIN {program} 25 | FOR d := fri DOWNTO mon DO writeln(DayName(d)); 26 | END. 27 | 28 | { Generated output is: 29 | Friday 30 | Thursday 31 | Wedsday 32 | Tuesday 33 | Monday 34 | } 35 | -------------------------------------------------------------------------------- /examples/extended_pascal/runtests.d: -------------------------------------------------------------------------------- 1 | // rdmd runtests 2 | 3 | void main() 4 | { 5 | import std.process: execute; 6 | 7 | const txt = execute(["dub", "run", "--", "example.pas"]); 8 | assert (txt.status == 0, txt.output); 9 | compareFiles("example.txt", "output/example.txt"); 10 | 11 | const html = execute(["dub", "run", "--", "--html", "example.pas"]); 12 | assert (html.status == 0, html.output); 13 | compareFiles("example.html", "output/example.html"); 14 | } 15 | 16 | void compareFiles(string a, string b) 17 | { 18 | import std.exception: enforce; 19 | import std.stdio: File; 20 | import std.algorithm: equal; 21 | 22 | const chunk = 1024; 23 | enforce(equal(File(a).byChunk(chunk), File(b).byChunk(chunk)), 24 | `"` ~ a ~ `" differs from "` ~ b ~ `"`); 25 | } 26 | -------------------------------------------------------------------------------- /examples/extended_pascal/source/app.d: -------------------------------------------------------------------------------- 1 | import std.stdio; 2 | import std.file; 3 | import std.getopt; 4 | import std.path; 5 | import epparser; 6 | 7 | bool html, text; 8 | 9 | int main(string[] args) 10 | { 11 | auto helpInformation = getopt( 12 | args, 13 | "text", "Generate text output (default)", &text, 14 | "html", "Generate HTML5 output", &html); // enum 15 | 16 | if (helpInformation.helpWanted || args.length < 2) 17 | { 18 | defaultGetoptPrinter("An Extended Pascal parser.\n" ~ 19 | "Usage: " ~ args[0] ~ " [options] \n" ~ 20 | "Options:", 21 | helpInformation.options); 22 | return 1; 23 | } 24 | 25 | 26 | version (tracer) 27 | { 28 | import std.logger; 29 | import std.algorithm : startsWith; 30 | sharedLog = cast(shared) new TraceLogger("TraceLog.txt"); 31 | bool cond (string ruleName, const ref ParseTree p) 32 | { 33 | static startTrace = false; 34 | //if (ruleName.startsWith("EP.FunctionDeclaration")) 35 | if (p.begin > 4000) 36 | startTrace = true; 37 | return startTrace && ruleName.startsWith("EP"); 38 | } 39 | // Various ways of turning logging on and of: 40 | //setTraceConditionFunction(&cond); 41 | //setTraceConditionFunction(function(string ruleName, const ref ParseTree p) {return ruleName.startsWith("EP");}); 42 | traceAll; 43 | } 44 | 45 | 46 | auto parseTree = EP(readText(args[1])); 47 | 48 | if (html) { 49 | import pegged.tohtml; 50 | toHTML(parseTree, stripExtension(args[1])); 51 | } 52 | if (text || !html) { 53 | File(stripExtension(args[1]) ~ ".txt", "w").write(parseTree.toString); 54 | } 55 | 56 | return parseTree.successful ? 0 : 1; 57 | } 58 | -------------------------------------------------------------------------------- /examples/extended_pascal/source/make.d: -------------------------------------------------------------------------------- 1 | /** 2 | * Recreate the EP parser from the grammar. 3 | */ 4 | 5 | import pegged.grammar; 6 | import epgrammar; 7 | 8 | void main() 9 | { 10 | auto header = ` 11 | PT failOnWordSymbol(PT)(PT p) 12 | { 13 | import std.uni: sicmp; 14 | // 6.1.2 15 | if (sicmp(p.matches[0], "AND") == 0 || 16 | sicmp(p.matches[0], "AND_THEN") == 0 || 17 | sicmp(p.matches[0], "ARRAY") == 0 || 18 | sicmp(p.matches[0], "BEGIN") == 0 || 19 | sicmp(p.matches[0], "BINDABLE") == 0 || 20 | sicmp(p.matches[0], "CASE") == 0 || 21 | sicmp(p.matches[0], "CONST") == 0 || 22 | sicmp(p.matches[0], "DIV") == 0 || 23 | sicmp(p.matches[0], "DO") == 0 || 24 | sicmp(p.matches[0], "DOWNTO") == 0 || 25 | sicmp(p.matches[0], "ELSE") == 0 || 26 | sicmp(p.matches[0], "END") == 0 || 27 | sicmp(p.matches[0], "EXPORT") == 0 || 28 | sicmp(p.matches[0], "FILE") == 0 || 29 | sicmp(p.matches[0], "FOR") == 0 || 30 | sicmp(p.matches[0], "FUNCTION") == 0 || 31 | sicmp(p.matches[0], "GOTO") == 0 || 32 | sicmp(p.matches[0], "IF") == 0 || 33 | sicmp(p.matches[0], "IMPORT") == 0 || 34 | sicmp(p.matches[0], "IN") == 0 || 35 | sicmp(p.matches[0], "LABEL") == 0 || 36 | sicmp(p.matches[0], "MOD") == 0 || 37 | sicmp(p.matches[0], "MODULE") == 0 || 38 | sicmp(p.matches[0], "NIL") == 0 || 39 | sicmp(p.matches[0], "NOT") == 0 || 40 | sicmp(p.matches[0], "OF") == 0 || 41 | sicmp(p.matches[0], "ONLY") == 0 || 42 | sicmp(p.matches[0], "OR") == 0 || 43 | sicmp(p.matches[0], "OR_ELSE") == 0 || 44 | sicmp(p.matches[0], "OTHERWISE") == 0 || 45 | sicmp(p.matches[0], "PACKED") == 0 || 46 | sicmp(p.matches[0], "POW") == 0 || 47 | sicmp(p.matches[0], "PROCEDURE") == 0 || 48 | sicmp(p.matches[0], "PROGRAM") == 0 || 49 | sicmp(p.matches[0], "PROTECTED") == 0 || 50 | sicmp(p.matches[0], "QUALIFIED") == 0 || 51 | sicmp(p.matches[0], "RECORD") == 0 || 52 | sicmp(p.matches[0], "REPEAT") == 0 || 53 | sicmp(p.matches[0], "RESTRICTED") == 0 || 54 | sicmp(p.matches[0], "SET") == 0 || 55 | sicmp(p.matches[0], "THEN") == 0 || 56 | sicmp(p.matches[0], "TO") == 0 || 57 | sicmp(p.matches[0], "TYPE") == 0 || 58 | sicmp(p.matches[0], "UNTIL") == 0 || 59 | sicmp(p.matches[0], "VALUE") == 0 || 60 | sicmp(p.matches[0], "VAR") == 0 || 61 | sicmp(p.matches[0], "WHILE") == 0 || 62 | sicmp(p.matches[0], "WITH") == 0 || 63 | // Prospero extensions: 64 | sicmp(p.matches[0], "ABSTRACT") == 0 || 65 | sicmp(p.matches[0], "CLASS") == 0 || 66 | sicmp(p.matches[0], "CONSTRUCTOR") == 0 || 67 | sicmp(p.matches[0], "DESTRUCTOR") == 0 || 68 | sicmp(p.matches[0], "EXCEPT") == 0 || 69 | sicmp(p.matches[0], "IS") == 0 || 70 | sicmp(p.matches[0], "PROPERTY") == 0 || 71 | sicmp(p.matches[0], "REM") == 0 || 72 | sicmp(p.matches[0], "SHL") == 0 || 73 | sicmp(p.matches[0], "SHR") == 0 || 74 | sicmp(p.matches[0], "TRY") == 0 || 75 | sicmp(p.matches[0], "VIEW") == 0 || 76 | sicmp(p.matches[0], "XOR") == 0) 77 | { 78 | p.successful = false; 79 | } 80 | return p; 81 | } 82 | `; 83 | asModule!()("epparser", "source/epparser", EPgrammar, header); 84 | } 85 | -------------------------------------------------------------------------------- /examples/json/dub.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "json", 3 | "description": "Example JSON PEG grammar. The standard JSON grammar, taken from json.org. Only 12 rules!", 4 | "license": "Boost", 5 | "targetType": "library", 6 | "dependencies": { 7 | "pegged": { 8 | "version": "*", 9 | "path": "../.." 10 | } 11 | }, 12 | "dflags": [ "-preview=dip1000" ] 13 | } 14 | -------------------------------------------------------------------------------- /examples/markdown/dub.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "markdown", 3 | "description": "The Markdown language grammar. The PEG file comes from this Github project. You can find the official description of Markdown syntax here.", 4 | "license": "Boost", 5 | "targetType": "library", 6 | "dependencies": { 7 | "pegged": { 8 | "version": "*", 9 | "path": "../.." 10 | } 11 | }, 12 | "dflags": [ "-preview=dip1000" ] 13 | } 14 | -------------------------------------------------------------------------------- /examples/misc/dub.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "constrants", 3 | "description": "Parse template constraints", 4 | "license": "Boost", 5 | "targetType": "library", 6 | "dependencies": { 7 | "pegged": { 8 | "version": "*", 9 | "path": "../.." 10 | } 11 | }, 12 | "dflags": [ "-preview=dip1000" ] 13 | } 14 | -------------------------------------------------------------------------------- /examples/misc/src/pegged/examples/constraints.d: -------------------------------------------------------------------------------- 1 | /** 2 | * This module was used to parse template constraints 3 | * and instantiate the various constituent, 4 | * to find which one is blocking a template to be instantiated. 5 | * 6 | * I have to code this again, using the D parser. 7 | */ 8 | module pegged.examples.constraints; 9 | 10 | import std.conv; 11 | import std.stdio; 12 | import std.traits; 13 | 14 | import pegged.grammar; 15 | 16 | 17 | 18 | string constraintToCode(ParseResult p) 19 | { 20 | string result; 21 | switch (p.name) 22 | { 23 | case "ConstraintExp": 24 | result = constraintToCode(p.children[0]); 25 | foreach(child; p.children[1..$]) 26 | result ~= " || " ~ constraintToCode(child); 27 | return result; 28 | case "AndExp": 29 | result = constraintToCode(p.children[0]); 30 | foreach(child; p.children[1..$]) 31 | result ~= " && " ~ constraintToCode(child); 32 | return result; 33 | case "Primary": 34 | return constraintToCode(p.children[0]); 35 | case "NotExp": 36 | return "!" ~ p.matches[0]; 37 | case "Parens": 38 | return "("~constraintToCode(p.children[0])~")"; 39 | case "Ident": 40 | return p.matches[0]; 41 | case "IsExpr": 42 | return p.matches[0]; 43 | default: 44 | break; 45 | } 46 | return result; 47 | } 48 | 49 | string[] generateAllConstraints(ParseResult p) 50 | { 51 | string[] result; 52 | result ~= constraintToCode(p); 53 | foreach(child; p.children) 54 | { 55 | auto temp = generateAllConstraints(child); 56 | if (temp[0] != result[$-1]) 57 | result ~= temp; 58 | else 59 | result ~= temp[1..$]; 60 | } 61 | return result; 62 | } 63 | 64 | string testAllConstraints(string input)() @property 65 | { 66 | string result = "string[] testResult;\n"; 67 | string[] constraints = generateAllConstraints(Constraint(input)); 68 | foreach(i, c; constraints) 69 | { 70 | auto mock = "mock"~to!string(i); 71 | result ~= "void "~mock~"(Args args) if (" ~ c ~ ") {};\n"; 72 | result ~= "static if (!__traits(compiles, "~mock~"(args)))\n"; 73 | result ~= " testResult ~= \""~c~"\";\n"; 74 | } 75 | return result; 76 | } 77 | 78 | string argListAlias(ParseResult p) 79 | { 80 | string aliases; 81 | string associations = "enum assoc = `( ` ~ "; 82 | foreach(i,arg; p.children) 83 | if (arg.children[0].name != "TupleParameter") 84 | { 85 | aliases ~= "alias Args["~to!string(i)~"] " ~ arg.matches[0] ~ ";\n"; 86 | associations ~= "`" ~ arg.matches[0] ~ ": ` ~ Args["~to!string(i)~"].stringof ~ `, ` ~ "; 87 | } 88 | else 89 | { 90 | aliases ~= "alias Args["~to!string(i)~"..$] " ~ arg.matches[0] ~ ";\n"; 91 | associations ~= "`" ~ arg.matches[0] ~ ": ` ~ Args["~to!string(i)~"..$].stringof ~ `, `"; 92 | } 93 | return aliases ~ associations[0..$-6]~" ~ `)`;\n"; 94 | } 95 | 96 | string generateAllMockUps(string argList, string[] constraints) 97 | { 98 | string result; 99 | foreach(i,constraint; constraints) 100 | { 101 | result ~= "struct Mock"~to!string(i)~argList~" if ("~constraint~") {}\n"; 102 | } 103 | return result; 104 | } 105 | 106 | string generateAllTests(string assoc, string[] constraints) 107 | { 108 | string result; 109 | foreach(i,constr; constraints) // to iterate at CT on the right number of mockups 110 | { 111 | string si = to!string(i); 112 | result ~= 113 | "static if (__traits(compiles, Mock"~si~"!(Args))) 114 | pragma(msg, constraints["~si~"], ` with " ~ assoc ~ ": true`); 115 | else 116 | pragma(msg, constraints["~si~"], ` with " ~ assoc ~ ": false`);\n"; 117 | } 118 | return result; 119 | } 120 | 121 | auto testInstantiation(alias name, Args...)() @property 122 | { 123 | enum constraint = getConstraint!name; 124 | enum argList0 = "("~ExtractTemplateArgumentList(name.stringof).matches[0] ~")"; 125 | enum argList = Type.TemplateParametersList(argList0); 126 | enum aliases = argListAlias(argList); 127 | mixin(aliases); 128 | enum constraints = generateAllConstraints(ConstraintExp.parse(constraint)); 129 | enum mockups = generateAllMockUps(argList0, constraints); 130 | mixin(mockups); 131 | enum test = generateAllTests(assoc, constraints); 132 | mixin(test); 133 | return argList; 134 | } 135 | -------------------------------------------------------------------------------- /examples/misc/src/pegged/examples/pattern.d: -------------------------------------------------------------------------------- 1 | /** 2 | This module is an attempt at introducing pattern-matching in D. 3 | 4 | Pattern matching is a type- or value-matching present in functional languages like ML or Haskell. 5 | 6 | The goal here is to obtain code like: 7 | 8 | ---- 9 | Pattern!"[ a, b, ... ]" p1; // match any range with at least two elements 10 | // the rest being discarded. 11 | 12 | auto m1 = p1([0,1,2,3,4]); // match and associate 'a' and 'b' with O and 1. 13 | assert(m1.a == 0 && m1.b == 1); 14 | auto m2 = p1("abc"); 15 | assert(m2.a = 'a' && m2.b == 'b'); 16 | auto m3 = p1(tuple("abc",0)); // not a range, the pattern fails 17 | assert(m3 == matchFailure; // predefined constant 18 | 19 | Pattern!"Tuple!(.,.) t" p2; // match any std.typecons.Tuple with two elements, of any type 20 | auto m4 = p2(tuple("abc",0)); 21 | assert(m4.t = tuple("abc",0); // only the global pattern is named, and hence captured 22 | assert(p2(tuple("abc")) == matchFailure); // only one member -> failure 23 | assert(p2(tuple("abc",0,1)) == matchFailure); // three members -> failure (the pattern has no trailing ... 24 | 25 | Pattern!" . { int, double, double }" p3; // match any aggregate (struct, class) 26 | // with three members being int,double and double, in that order. 27 | ---- 28 | 29 | Don't salivate, it's not implemented yet. 30 | */ 31 | module pegged.examples.pattern; 32 | 33 | import std.range; 34 | import std.traits; 35 | import std.typecons; 36 | import std.typetuple; 37 | 38 | import pegged.grammar; 39 | 40 | mixin(grammar(` 41 | Pattern: 42 | Global < Choice :eoi 43 | Choice < Sequence (:'/' Sequence)* 44 | Sequence < Primary (:',' Primary)* 45 | Primary < (Aggregate / Range / Identifier / Literal / REST / ANY) Name? 46 | 47 | Name < identifier 48 | Aggregate < (Identifier / ANY) (Tuple / Record) 49 | Tuple < '{' (Choice (:',' Choice)*)? '}' 50 | Record < '{' Field (','Field)* '}' 51 | Field < Identifier :'=' Choice 52 | Range < '[' (Choice (:',' Choice)*)? ']' 53 | Identifier < identifier 54 | Literal < Number / Char / String/ Bool 55 | Number <~ Digit+ ('.' Digit*)? 56 | Digit < [0-9] 57 | Char <~ quote . quote # TODO: adding escape chars and Unicode chars 58 | String <~ doublequote (!doublequote .)* doublequote 59 | Bool < "true" / "false" 60 | 61 | REST < "..." 62 | ANY < "." 63 | Spacing <: spacing 64 | `)); 65 | 66 | template TypeFailure(T...) 67 | { 68 | enum successful = false; 69 | alias TypeTuple!() Types; 70 | enum begin = 0; 71 | enum end = 0; 72 | alias T Rest; 73 | } 74 | 75 | struct TypeAny 76 | { 77 | template Match(T...) 78 | { 79 | static if (T.length == 0) 80 | mixin TypeFailure!(T); 81 | else 82 | { 83 | enum successful = true; 84 | alias T[0..1] Types; 85 | enum begin = 0; 86 | enum end = 1; 87 | alias T[1..$] Rest; 88 | } 89 | } 90 | } 91 | 92 | struct TypeEnd 93 | { 94 | template Match(T...) 95 | { 96 | static if (T.length == 0) 97 | { 98 | enum successful = true; 99 | alias TypeTuple!() Types; 100 | enum begin = 0; 101 | enum end = 0; 102 | alias T Rest; 103 | } 104 | else 105 | mixin TypeFailure!(T); 106 | } 107 | } 108 | 109 | struct TypeEps 110 | { 111 | template Match(T...) 112 | { 113 | enum successful = true; 114 | alias TypeTuple!() Types; 115 | enum begin = 0; 116 | enum end = 0; 117 | alias T Rest; 118 | } 119 | } 120 | 121 | struct TypeLiteral(U...) 122 | { 123 | template Match(T...) 124 | { 125 | static if (T.length < U.length || !is(T[0..U.length] == U)) 126 | mixin TypeFailure!(T); 127 | else 128 | { 129 | enum successful = true; 130 | alias T[0..U.length] Types; 131 | enum begin = 0; 132 | enum end = U.length; 133 | alias T[U.length..$] Rest; 134 | } 135 | } 136 | } 137 | 138 | template isSubtype(T...) 139 | { 140 | static if (T.length == 0) 141 | enum isSubtype = true; 142 | else static if (is(T[0] : T[$/2])) 143 | enum isSubtype = isSubtype!(T[1..$/2],T[$/2+1..$]); 144 | else 145 | enum isSubtype = false; 146 | } 147 | 148 | struct TypeSubType(U...) 149 | { 150 | template Match(T...) 151 | { 152 | static if (T.length < U.length || !isSubtype!(T[0..U.length],U)) 153 | mixin TypeFailure!(T); 154 | else 155 | { 156 | enum successful = true; 157 | alias T[0..U.length] Types; 158 | enum begin = 0; 159 | enum end = U.length; 160 | alias T[U.length..$] Rest; 161 | } 162 | } 163 | } 164 | 165 | struct TypeOr(alias Pattern1, alias Pattern2) 166 | { 167 | template Match(T...) 168 | { 169 | alias Pattern1.Match!(T) P1; 170 | static if (P1.successful) 171 | alias P1 Match; 172 | else 173 | alias Pattern2.Match!(T) Match; 174 | } 175 | } 176 | 177 | template TypeOr(Patterns...) if (Patterns.length > 2) 178 | { 179 | alias TypeOr!(Patterns[0], TypeOr!(Patterns[1..$])) TypeOr; 180 | } 181 | 182 | template TypeOr(Patterns...) if (Patterns.length == 1) 183 | { 184 | alias Patterns[0] TypeOr; 185 | } 186 | 187 | struct TypeAnd(alias Pattern1, alias Pattern2) 188 | { 189 | template Match(T...) 190 | { 191 | alias Pattern1.Match!(T) P1; 192 | alias Pattern2.Match!(Pattern1.Match!(T).Rest) P2; 193 | static if (P1.successful && P2.successful) 194 | { 195 | enum successful = true; 196 | alias TypeTuple!(P1.Types, P2.Types) Types; 197 | enum begin = P1.begin; 198 | enum end = P2.end; 199 | alias P2.Rest Rest; 200 | } 201 | else 202 | mixin TypeFailure!(T); 203 | } 204 | } 205 | 206 | template TypeAnd(Patterns...) if (Patterns.length > 2) 207 | { 208 | alias TypeAnd!(Patterns[0], TypeAnd!(Patterns[1..$])) And; 209 | } 210 | 211 | template TypeAnd(Patterns...) if (Patterns.length == 1) 212 | { 213 | alias Patterns[0] TypeAnd; 214 | } 215 | 216 | struct TypeOption(alias Pattern) 217 | { 218 | template Match(T...) 219 | { 220 | alias Pattern.Match!(T) P; 221 | static if (P.successful) 222 | alias P Match; 223 | else 224 | { 225 | enum successful = true; 226 | alias TypeTuple!() Types; 227 | enum begin = 0; 228 | enum end = 0; 229 | alias T Rest; 230 | } 231 | } 232 | } 233 | 234 | struct TypeZeroOrMore(alias Pattern) 235 | { 236 | template Match(T...) 237 | { 238 | alias Pattern.Match!(T) P; 239 | static if (P.successful) 240 | { 241 | enum successful = true; 242 | alias TypeTuple!(P.Types, TypeZeroOrMore!(Pattern).Match!(P.Rest).Types) Types; 243 | enum begin = P.begin; 244 | alias TypeZeroOrMore!(Pattern).Match!(P.Rest) More; 245 | enum end = P.end + More.end; 246 | alias TypeZeroOrMore!(Pattern).Match!(P.Rest).Rest Rest; 247 | } 248 | else 249 | { 250 | enum successful = true; 251 | alias TypeTuple!() Types; 252 | enum begin = 0; 253 | enum end = 0; 254 | alias T Rest; 255 | } 256 | } 257 | } 258 | 259 | struct TypeOneOrMore(alias Pattern) 260 | { 261 | template Match(T...) 262 | { 263 | alias Pattern.Match!(T) P; 264 | static if (P.successful) 265 | { 266 | enum successful = true; 267 | alias TypeTuple!(P.Types, TypeZeroOrMore!(Pattern).Match!(P.Rest).Types) Types; 268 | enum begin = P.begin; 269 | alias TypeZeroOrMore!(Pattern).Match!(P.Rest) More; 270 | enum end = P.end + More.end; 271 | alias TypeZeroOrMore!(Pattern).Match!(P.Rest).Rest Rest; 272 | } 273 | else 274 | mixin TypeFailure!(T); 275 | } 276 | } 277 | 278 | /** 279 | Discards the matched types, but propagate the indices. 280 | */ 281 | struct TypeDiscardMatch(alias Pattern) 282 | { 283 | template Match(T...) 284 | { 285 | alias Pattern.Match!(T) P; 286 | static if (P.successful) 287 | { 288 | enum successful = true; 289 | alias TypeTuple!() Types; // Forget the match, 290 | enum begin = P.begin; // but propagate indices 291 | enum end = P.end; // 292 | alias P.Rest Rest; // and the input 293 | } 294 | else 295 | mixin TypeFailure!(T); 296 | } 297 | } 298 | 299 | struct TypePosLookAhead(alias Pattern) 300 | { 301 | template Match(T...) 302 | { 303 | alias Pattern.Match!(T) P; 304 | static if (P.successful) 305 | { 306 | enum successful = true; 307 | alias TypeTuple!() Types; 308 | enum begin = 0; 309 | enum end = 0; 310 | alias T Rest; 311 | } 312 | else 313 | mixin TypeFailure!(T); 314 | } 315 | } 316 | 317 | struct TypeNegLookAhead(alias Pattern) 318 | { 319 | template Match(T...) 320 | { 321 | alias Pattern.Match!(T) P; 322 | static if (P.successful) 323 | mixin TypeFailure!(T); 324 | else 325 | { 326 | enum successful = true; 327 | alias TypeTuple!() Types; 328 | enum begin = 0; 329 | enum end = 0; 330 | alias T Rest; 331 | } 332 | } 333 | } 334 | 335 | struct isRange 336 | { 337 | template Match(T...) 338 | { 339 | static if (isInputRange!(T[0])) 340 | { 341 | enum successful = true; 342 | alias T[0] Types; 343 | enum begin = 0; 344 | enum end = 1; 345 | alias T[1..$] Rest; 346 | } 347 | else 348 | mixin TypeFailure!(T); 349 | } 350 | } 351 | 352 | struct TypeSatisfy(alias test) 353 | { 354 | template Match(T...) 355 | { 356 | static if (test!(T[0])) 357 | { 358 | enum successful = true; 359 | alias T[0] Types; 360 | enum begin = 0; 361 | enum end = 1; 362 | alias T[1..$] Rest; 363 | } 364 | else 365 | mixin TypeFailure!(T); 366 | } 367 | } 368 | 369 | struct MatchResult(size_t junction, T...) 370 | { 371 | bool successful; 372 | T[0..junction] match; 373 | size_t begin; 374 | size_t end; 375 | T[junction..$] rest; 376 | } 377 | 378 | struct Success(M...) 379 | { 380 | M match; 381 | size_t begin; 382 | size_t end; 383 | 384 | auto rest(R...)(R rest) 385 | { 386 | return MatchResult!(M.length, M, R)(true, match, begin, end, rest); 387 | } 388 | } 389 | 390 | Success!(M) success(M...)(M match, size_t begin, size_t end) 391 | { 392 | return Success!(M)(match, begin, end); 393 | } 394 | 395 | auto failure(R...)(R rest) 396 | { 397 | return MatchResult!(0,R)(false, 0,0, rest); 398 | } 399 | 400 | auto anyValue(Args...)(Args args) 401 | { 402 | static if (Args.length > 0) 403 | return success(args[0],0,1).rest(args[1..$]); 404 | else 405 | return failure(args); 406 | } 407 | 408 | auto endValue(Args...)(Args args) 409 | { 410 | static if (Args.length == 0) 411 | return success(0,0).rest(args); 412 | else 413 | return failure(args); 414 | } 415 | 416 | /+ 417 | template literalValue(values...) 418 | { 419 | auto literalValue(Args...)(Args args) 420 | { 421 | if ( 422 | return success(0,values.length).rest(args[values.length..$]); 423 | else 424 | return failure(args); 425 | } 426 | } 427 | +/ 428 | 429 | Tuple!(ElementType!R, R) rangeAny(R)(R r) if (isInputRange!R) 430 | { 431 | if (r.empty) 432 | throw new Exception("Empty range, could not pattern-match"); 433 | else 434 | { 435 | auto head = r.front(); 436 | r.popFront(); 437 | return tuple(head, r); 438 | } 439 | } 440 | 441 | Tuple!(R,R) rangeRest(R)(R r) if (isInputRange!R) 442 | { 443 | if (r.empty) 444 | throw new Exception("Empty range, could not pattern-match"); 445 | else 446 | return tuple(r, r); // second r will not be used, but is needed to be compatible with other range patterns: Tuple!(result,rest) 447 | } 448 | 449 | template RangePatternResult(R) if (isInputRange!R) 450 | { 451 | template RangePatternResult(alias T) 452 | { 453 | alias ReturnType!(T!R) RangePatternResult; 454 | } 455 | } 456 | 457 | template onRange(RangePatterns...) 458 | { 459 | auto onRange(R)(R r) if (isInputRange!(R)) 460 | { 461 | alias RangePatternResult!R GetType; 462 | 463 | staticMap!(GetType, RangePatterns) _temp; 464 | 465 | static if (RangePatterns.length > 0) 466 | { 467 | _temp[0] = RangePatterns[0](r); 468 | foreach(i,pat; RangePatterns[1..$]) 469 | _temp[i+1] = RangePatterns[i+1](_temp[i][1]); 470 | } 471 | 472 | struct MatchResult 473 | { 474 | GetType!(RangePatterns[0]).Types[0] a; 475 | GetType!(RangePatterns[1]).Types[0] b; 476 | GetType!(RangePatterns[2]).Types[0] c; 477 | } 478 | 479 | return MatchResult(_temp[0][0],_temp[1][0],_temp[2][0]); 480 | } 481 | } 482 | 483 | -------------------------------------------------------------------------------- /examples/misc/src/pegged/examples/testergrammar.d: -------------------------------------------------------------------------------- 1 | module pegged.examples.testergrammar; 2 | 3 | enum string testerGrammar = ` 4 | TesterGrammar: 5 | 6 | Root < Node eoi 7 | 8 | Node < 9 | / :'^' identifier 10 | / identifier (%Branch)* 11 | 12 | Branch < 13 | / OrderedBranch 14 | / UnorderedBranch 15 | / ConciseBranch 16 | 17 | OrderedBranch < 18 | / :'->' :'{' Node+ :'}' 19 | / :'->' Node 20 | 21 | UnorderedBranch < 22 | / :'~>' :'{' Node+ :'}' 23 | / :'~>' Node 24 | 25 | ConciseBranch < :'->' '{..}' 26 | 27 | Spacing <: (blank / Comment)* 28 | 29 | Comment <- 30 | / '//' (!eol .)* (eol) 31 | / '/*' (!'*/' .)* '*/' 32 | / NestedComment 33 | 34 | NestedComment <- '/+' (!NestedCommentEnd . / NestedComment) NestedCommentEnd 35 | 36 | # This is needed to make the /+ +/ nest when the grammar is placed into a D nested comment ;) 37 | NestedCommentEnd <- '+/' 38 | `; 39 | -------------------------------------------------------------------------------- /examples/numbers/dub.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "numbers", 3 | "description": "Example numbers PEG grammar. Parses different kind of numbers: integral, floating point, hexadecimal.", 4 | "license": "Boost", 5 | "targetType": "library", 6 | "dependencies": { 7 | "pegged": { 8 | "version": "*", 9 | "path": "../.." 10 | } 11 | }, 12 | "dflags": [ "-preview=dip1000" ] 13 | } 14 | -------------------------------------------------------------------------------- /examples/numbers/src/pegged/examples/numbers.d: -------------------------------------------------------------------------------- 1 | /** 2 | This module contains a example grammar rules to parse different kind of numbers literals. 3 | */ 4 | module pegged.examples.numbers; 5 | 6 | import pegged.grammar; 7 | 8 | @safe: 9 | 10 | /// Numbers 11 | mixin(grammar(` 12 | Numbers: 13 | Scientific <~ Floating ( ('e' / 'E' ) Integer )? 14 | Floating <~ Integer ('.' Unsigned )? 15 | Unsigned <~ [0-9]+ 16 | Integer <~ Sign? Unsigned 17 | Hexa <~ [0-9a-fA-F]+ 18 | Binary <~ "0b" [01] [01_]* 19 | Sign <- '-' / '+' 20 | `)); 21 | 22 | unittest 23 | { 24 | string[] testNumbers = 25 | [ 26 | "0", "0.0", "0.01", 27 | "-0", "+0", "-0.0", "+0.0", 28 | "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", 29 | "0123456789", 30 | "123", "123.0", "123.01", "-123", "-123.0", "-123.01", 31 | "-123e+12", "-123e-12", "+123e+12", "+123e-12", "-123E+12", "-123E-12", "+123E+12", "+123E-12", 32 | "123.456e+00", "123.456E+00", "123.456e-00", "123.456E-00", 33 | "-123.456e+00", "-123.456E+00", "-123.456e-00", "-123.456E-00", 34 | "+123.456e+00", "+123.456E+00", "+123.456e-00", "+123.456E-00" 35 | ]; 36 | 37 | foreach(number; testNumbers) 38 | { 39 | const parseTree = Numbers(number); 40 | auto match = parseTree.matches; 41 | assert(parseTree.successful, "Expected to parse successfully number " ~ number); 42 | assert(match == [number], "Expected " ~ number ~ " but was " ~ match[0]); // Shall parse 43 | } 44 | 45 | // Failures 46 | testNumbers = 47 | [ 48 | ".", ".0", "0.", "123..456", 49 | "", "abc", "+", "-", "+.", "-.", 50 | "--1", "++1", "+-1", "-+1", 51 | "1e", "1e+", "1e-","1ee" 52 | ]; 53 | 54 | foreach(number; testNumbers) 55 | { 56 | assert(Numbers(number).matches != [number], "Number \"" ~ number ~ "\" musn't be parsed"); // None shall parse 57 | } 58 | 59 | // Hexadecimal numbers 60 | testNumbers = 61 | [ 62 | "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", 63 | "A", "B", "C", "D", "E", "F", 64 | "a", "b", "c", "d", "e", "f", 65 | "0123456789ABCDEF", 66 | "0123456789abcdef", 67 | "DEADBEEF", "0123BEEF", "DEAD0123", 68 | "deadbeef", "0123beef", "dead0123", 69 | "123E", "123e" 70 | ]; 71 | 72 | foreach(number; testNumbers) 73 | { 74 | const parseTree = Numbers.decimateTree(Numbers.Hexa(number)); 75 | auto match = parseTree.matches; 76 | assert(parseTree.successful, "Expected to parse successfully number " ~ number); 77 | assert(match == [number], "Expected " ~ number ~ " but was " ~ match[0]); // Shall parse 78 | } 79 | 80 | // Hexadecimal failures 81 | testNumbers = 82 | [ 83 | "", "G", "g", "-1", "123.456", "123e+100" 84 | ]; 85 | 86 | foreach(number; testNumbers) 87 | { 88 | assert(Numbers.decimateTree(Numbers.Hexa(number)).matches != [number], 89 | "Number \"" ~ number ~ "\" musn't be parsed"); // None shall parse 90 | } 91 | 92 | // Binary numbers 93 | testNumbers = 94 | [ 95 | "0b0", "0b1", "0b0000", "0b0001", "0b11110000", "0b0000_1111", "0b1010_00_11" 96 | ]; 97 | 98 | foreach(number; testNumbers) 99 | { 100 | const parseTree = Numbers.decimateTree(Numbers.Binary(number)); 101 | auto match = parseTree.matches; 102 | assert(parseTree.successful, "Expected to parse successfully number " ~ number); 103 | assert(match == [number], "Expected " ~ number ~ " but was " ~ match[0]); // Shall parse 104 | } 105 | 106 | // Hexadecimal failures 107 | testNumbers = 108 | [ 109 | "", "G", "g", "-1", "123.456", "123e+100", "0b", "01010", "0b3456" 110 | ]; 111 | 112 | foreach(number; testNumbers) 113 | { 114 | assert(Numbers.decimateTree(Numbers.Binary(number)).matches != [number], 115 | "Number \"" ~ number ~ "\" musn't be parsed"); // None shall parse 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /examples/oberon2/dub.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "oberon2", 3 | "description": "The Oberon-2 programming language grammar. This grammar was written by Bjoern Lietz-Spendig.", 4 | "license": "Boost", 5 | "targetType": "library", 6 | "dependencies": { 7 | "pegged": { 8 | "version": "*", 9 | "path": "../.." 10 | } 11 | }, 12 | "dflags": [ "-preview=dip1000" ] 13 | } 14 | -------------------------------------------------------------------------------- /examples/oberon2/src/pegged/examples/oberon2.d: -------------------------------------------------------------------------------- 1 | /** 2 | * This module was given by Bjoern Lietz-Spendig 3 | **/ 4 | module pegged.examples.oberon2; 5 | 6 | 7 | /* 8 | * 9 | * PEG Grammar for Oberon-2 10 | * A detailed language report is available at 11 | * http://www-vs.informatik.uni-ulm.de:81/projekte/Oberon-2.Report/index.html 12 | */ 13 | 14 | /* 15 | The remarkable short syntax of Oberon-2 in --- Wirth EBNF --- 16 | 17 | Module = MODULE ident ";" [ImportList] DeclSeq [BEGIN StatementSeq] END ident ".". 18 | ImportList = IMPORT [ident ":="] ident {"," [ident ":="] ident} ";". 19 | DeclSeq = { CONST {ConstDecl ";" } | TYPE {TypeDecl ";"} | VAR {VarDecl ";"}} {ProcDecl ";" | ForwardDecl ";"}. 20 | ConstDecl = IdentDef "=" ConstExpr. 21 | TypeDecl = IdentDef "=" Type. 22 | VarDecl = IdentList ":" Type. 23 | ProcDecl = PROCEDURE [Receiver] IdentDef [FormalPars] ";" DeclSeq [BEGIN StatementSeq] END ident. 24 | ForwardDecl = PROCEDURE "^" [Receiver] IdentDef [FormalPars]. 25 | FormalPars = "(" [FPSection {";" FPSection}] ")" [":" Qualident]. 26 | FPSection = [VAR] ident {"," ident} ":" Type. 27 | Receiver = "(" [VAR] ident ":" ident ")". 28 | Type = Qualident 29 | | ARRAY [ConstExpr {"," ConstExpr}] OF Type 30 | | RECORD ["("Qualident")"] FieldList {";" FieldList} END 31 | | POINTER TO Type 32 | | PROCEDURE [FormalPars]. 33 | FieldList = [IdentList ":" Type]. 34 | StatementSeq = Statement {";" Statement}. 35 | Statement = [ Designator ":=" Expr 36 | | Designator ["(" [ExprList] ")"] 37 | | IF Expr THEN StatementSeq {ELSIF Expr THEN StatementSeq} [ELSE StatementSeq] END 38 | | CASE Expr OF Case {"|" Case} [ELSE StatementSeq] END 39 | | WHILE Expr DO StatementSeq END 40 | | REPEAT StatementSeq UNTIL Expr 41 | | FOR ident ":=" Expr TO Expr [BY ConstExpr] DO StatementSeq END 42 | | LOOP StatementSeq END 43 | | WITH Guard DO StatementSeq {"|" Guard DO StatementSeq} [ELSE StatementSeq] END 44 | | EXIT 45 | | RETURN [Expr] 46 | ]. 47 | Case = [CaseLabels {"," CaseLabels} ":" StatementSeq]. 48 | CaseLabels = ConstExpr [".." ConstExpr]. 49 | Guard = Qualident ":" Qualident. 50 | ConstExpr = Expr. 51 | Expr = SimpleExpr [Relation SimpleExpr]. 52 | SimpleExpr = ["+" | "-"] Term {AddOp Term}. 53 | Term = Factor {MulOp Factor}. 54 | Factor = Designator ["(" [ExprList] ")"] | number | character | string | NIL | Set | "(" Expr ")" | " ~ " Factor. 55 | Set = "{" [Element {"," Element}] "}". 56 | Element = Expr [".." Expr]. 57 | Relation = "=" | "#" | "<" | "<=" | ">" | ">=" | IN | IS. 58 | AddOp = "+" | "-" | OR. 59 | MulOp = " * " | "/" | DIV | MOD | "&". 60 | Designator = Qualident {"." ident | "[" ExprList "]" | " ^ " | "(" Qualident ")"}. 61 | ExprList = Expr {"," Expr}. 62 | IdentList = IdentDef {"," IdentDef}. 63 | Qualident = [ident "."] ident. 64 | IdentDef = ident [" * " | "-"]. 65 | */ 66 | 67 | 68 | /* 69 | FOUR SIMPLE EBNF TO PEGGED TRANFORMATION RULES 70 | Pegged Wirth EBNF 71 | 72 | Sequence 73 | A <- B C A = B C. 74 | 75 | B or C 76 | A <- B / C A = B|C. 77 | 78 | Zero or one B 79 | A <- B? A = [B]. 80 | 81 | Zero or more Bs 82 | A <- B* A = {B}. 83 | 84 | List of comma (or otherwise) separated Bs 85 | A <- List(B, ',') A = B {"," B}. 86 | 87 | */ 88 | 89 | /// The Oberon-2 PEG grammar (Finally!) 90 | enum string Oberon2Grammar = ` 91 | Oberon2: 92 | 93 | Module <- "MODULE" Identifier ";" ImportList? DeclSeq ("BEGIN" StatementSeq)? "END" Identifier "." 94 | 95 | ImportList <- "IMPORT" (Identifier ":=")? Identifier ("," (Identifier ":=")? Identifier)* ";" 96 | 97 | DeclSeq <- "CONST" (ConstDecl ";")* 98 | / "TYPE" (TypeDecl ";")* 99 | / "VAR" (VarDecl ";")* (ProcDecl ";" / ForwardDecl ";")* 100 | 101 | ConstDecl <- IdentDef "=" ConstExpr 102 | TypeDecl <- IdentDef "=" Type 103 | VarDecl <- IdentList ":" Type 104 | ProcDecl <- "PROCEDURE" Receiver? IdentDef FormalPars? ";" DeclSeq ("BEGIN" StatementSeq)? "END" Identifier 105 | ForwardDecl <- "PROCEDURE" "^" Receiver? IdentDef FormalPars? 106 | FormalPars <- "(" (FPSection (";" FPSection)*)? ")" (":" Qualident)? 107 | FPSection <- "VAR"? Identifier ("," Identifier)? ":" Type 108 | Receiver <- "(" "VAR"? Identifier ":" Identifier ")" 109 | 110 | Type <- Qualident 111 | / "ARRAY" (ConstExpr ("," ConstExpr)*)? "OF" Type 112 | / "RECORD" ("("Qualident")")? FieldList (";" FieldList)* "END" 113 | / "POINTER" "TO" Type 114 | / "PROCEDURE" (FormalPars)? 115 | 116 | FieldList <- (IdentList ":" Type)? 117 | 118 | # 119 | StatementSeq <- Statement (";" Statement)* # List( Statement, ';') 120 | 121 | Statement <- ( Designator ":=" Expr 122 | / Designator ("(" (ExprList)? ")") 123 | / IfStatement 124 | / CaseStatement 125 | / WhileStatement 126 | / RepeatStatement 127 | / ForStatement 128 | / LoopStatement 129 | / WithStatement 130 | / ExitStatement 131 | / ReturnStatement 132 | )? 133 | 134 | IfStatement <- "IF" Expr "THEN" StatementSeq ("ELSIF" Expr "THEN" StatementSeq)* ("ELSE" StatementSeq)? "END" 135 | CaseStatement <- "CASE" Expr "OF" Case ("|" Case)* ("ELSE" StatementSeq) "END" 136 | WhileStatement <- "WHILE" Expr "DO" StatementSeq "END" 137 | RepeatStatement <- "REPEAT" StatementSeq "UNTIL" Expr 138 | ForStatement <- "FOR" Identifier ":=" Expr "TO" Expr ("BY" ConstExpr)? "DO" StatementSeq "END" 139 | LoopStatement <- "LOOP" StatementSeq "END" 140 | WithStatement <- "WITH" Guard "DO" StatementSeq ("|" Guard "DO" StatementSeq)* ("ELSE" StatementSeq)? "END" 141 | ExitStatement <- "EXIT" 142 | ReturnStatement <- "RETURN" Expr? 143 | 144 | Case <- (CaseLabels ("," CaseLabels)* ":" StatementSeq)? 145 | CaseLabels <- ConstExpr (".." ConstExpr)? 146 | Guard <- Qualident ":" Qualident 147 | ConstExpr <- Expr 148 | Expr <- SimpleExpr (Relation SimpleExpr)? 149 | SimpleExpr <- ("+" / "-")? Term (AddOp Term)* 150 | Term <- Factor (MulOp Factor)* 151 | Factor <- Designator ("(" ExprList? ")")? 152 | / Number 153 | / Character 154 | / String 155 | / "NIL" 156 | / Set 157 | / "(" Expr ")" 158 | / " ~ " Factor 159 | 160 | Set <- "{" (Element ("," Element)*)? "}" 161 | Element <- Expr (".." Expr)? 162 | 163 | Relation <- "IN" / "IS" / "<=" / ">=" / "=" / "#" / "<" / ">" 164 | AddOp <- "OR" / "+" / "-" 165 | MulOp <- "DIV" / "MOD" / "*" / "/" / "&" 166 | Designator <- Qualident ("." Identifier / "[" ExprList "]" / " ^ " / "(" Qualident ")")* 167 | List(E,S) <- E (S E)* 168 | ExprList <- Expr (',' Expr)* 169 | IdentList <- IdentDef (',' IdentDef)* 170 | Qualident <- (Identifier ".")? Identifier 171 | IdentDef <- Identifier (" * " / "-")? 172 | 173 | #Numbers 174 | Number <- Integer / Real 175 | Integer <- Digit Digit* / Digit HexDigit* "H" 176 | Real <- Digit Digit* "." Digit* ScaleFactor? 177 | ScaleFactor <- ("E" / "D") / ("+" / "-")? Digit Digit* 178 | HexDigit <- [0-9A-F] 179 | Digit <- [0-9] 180 | 181 | #Number Examples 182 | # 1991 INTEGER 1991 183 | # 0DH SHORTINT 13 184 | # 12.3 REAL 12.3 185 | # 4.567E8 REAL 456700000 186 | # 0.57712566D-6 LONGREAL 0.00000057712566 187 | 188 | String <- DoubleQuotedString / SingleQuotedString 189 | DoubleQuotedString <- doublequote DQChar* doublequote 190 | SingleQuotedString <- quote SQChar* quote 191 | 192 | DQChar <- EscapeSequence 193 | / !doublequote . 194 | 195 | SQChar <- EscapeSequence 196 | / !quote . 197 | 198 | EscapeSequence <- backslash ( quote 199 | / doublequote 200 | / backslash 201 | / [abfnrtv] 202 | / 'x' HexDigit HexDigit 203 | / 'u' HexDigit HexDigit HexDigit HexDigit 204 | / 'U' HexDigit HexDigit HexDigit HexDigit HexDigit HexDigit HexDigit HexDigit 205 | ) 206 | 207 | Character <- quote (!quote (EscapeSequence / .)) quote 208 | 209 | #Oberon-2 comments look like (* Some Text *) 210 | Comment <- '(*' (!'*)' .)* '*)' 211 | 212 | # I had to add it. Otherwise, keywords are recognized as identifiers. Note that Oberon does not allow '_' 213 | Identifier <~ !Keyword [a-zA-Z] [a-zA-Z0-9]* 214 | 215 | Keyword <- "ARRAY" / "ABS"/ "ASH" / "BOOLEAN" / "BEGIN" / "BY" 216 | / "CASE" / "CHAR" / "CONST" / "COPY" / "CAP"/ "CHR" 217 | / "DEC" / "DIV" / "DO" / "ELSIF" / "ELSE" / "ENTIER" / "EXCL" / "EXIT" / "END" 218 | / "FALSE" / "FOR" / "HALT" / "INTEGER" / "IMPORT" / "INCL" / "INC" / "IF" / "IN" /"IS" 219 | / "LONGREAL" / "LONGINT" / "LONG" / "LOOP" / "LEN" 220 | / "MODULE" / "MOD" / "MIN" / "MAX"/ "NIL" /"NEW" 221 | / "ODD" / "ORD" / "OF" / "OR" / "PROCEDURE" / "REAL" 222 | / "SET" / "SHORTINT" / "SHORT" / "SIZE" / "TRUE" 223 | / "POINTER" / "RECORD" / "REPEAT" / "RETURN" / "THEN" / "TYPE" / "TO" / "UNTIL" / "VAR" 224 | / "WHILE" / "WITH" 225 | 226 | `; 227 | -------------------------------------------------------------------------------- /examples/parameterized/dub.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "parameterized", 3 | "description": "Examples of parameterized rules, as described on the Parameterized Rules page.", 4 | "license": "Boost", 5 | "targetType": "library", 6 | "dependencies": { 7 | "pegged": { 8 | "version": "*", 9 | "path": "../.." 10 | } 11 | }, 12 | "dflags": [ "-preview=dip1000" ] 13 | } 14 | -------------------------------------------------------------------------------- /examples/parameterized/src/pegged/examples/parameterized.d: -------------------------------------------------------------------------------- 1 | module pegged.examples.parameterized; 2 | 3 | import pegged.grammar; 4 | 5 | /** 6 | * Example of parameterized rules. Pick and chose the ones you need. 7 | */ 8 | enum parameterizedExamples = ` 9 | Parameterized: 10 | 11 | # Standard list: skip spaces, drop the separator 12 | # Minimum one Elem 13 | List(Elem, Sep) < Elem (:Sep Elem)* 14 | 15 | # A list accepting 0 element as a valid input 16 | List0(Elem, Sep) < List(Elem, Sep)? 17 | 18 | # Standard comma-separated list 19 | CommaList(Elem) < List(Elem, ',') 20 | 21 | # Standard space-separated list 22 | SpaceList(Elem) < List(Elem, ' ') 23 | 24 | # Standard array rule: [1, 2, ... ]. 25 | Array(Elem) < :'[' List0(Elem, ',') :']' 26 | 27 | 28 | # Apply Pattern until End 29 | Until(Pattern, End) <- (!End Pattern)* :End 30 | 31 | # Everything but the End marker. Concatenates the entire match 32 | But(End) <~ Until(., End) 33 | 34 | # Input delimited by a begin and a close marker 35 | Delimited(Begin, Close) <- :Begin But(Close) 36 | 37 | # Standard double-quoted string 38 | String <- Delimited(doublequote, doublequote) 39 | 40 | # Line (everything to the end of the line) 41 | Line <- Delimited(eps, endOfLine) 42 | 43 | # Line comment 44 | LineComment <- Delimited(:"//", endOfLine) 45 | `; 46 | 47 | mixin(grammar(parameterizedExamples)); 48 | 49 | unittest 50 | { 51 | mixin(grammar(" 52 | ParamTest1: 53 | A <- Parameterized.List(identifier, ',') 54 | ")); 55 | 56 | assert(ParamTest1("abc, def, ghi").successful); 57 | assert(ParamTest1("abc, def, ghi").matches == ["abc", "def", "ghi"]); 58 | assert(ParamTest1("abc, def, ").successful); 59 | assert(ParamTest1("abc, def, ").matches == ["abc", "def"]); 60 | assert(ParamTest1("abc, def, ghi").successful); 61 | assert(ParamTest1("abc, def, ghi").matches == ["abc", "def", "ghi"]); 62 | assert(ParamTest1("abc,").successful); 63 | assert(ParamTest1("a").successful); 64 | // stops before the end: 65 | assert(ParamTest1("abc,, def, ghi").successful); 66 | assert(ParamTest1("abc,, def, ghi").matches == ["abc"]); 67 | // not lists: 68 | assert(!ParamTest1("").successful); 69 | assert(!ParamTest1(",abc, def, ghi").successful); 70 | 71 | mixin(grammar(" 72 | ParamTest2: 73 | A <- Parameterized.List(identifier, ' ') 74 | ")); 75 | 76 | assert(ParamTest2("abc def ghi").successful); 77 | assert(ParamTest2("abc def ").successful); 78 | assert(ParamTest2("abc def ghi").successful); 79 | assert(ParamTest2("abc ").successful); 80 | assert(ParamTest2("a").successful); 81 | // not lists: 82 | assert(!ParamTest2("").successful); 83 | assert(!ParamTest2(" ").successful); 84 | 85 | mixin(grammar(" 86 | ParamTest3: 87 | A <- Parameterized.Array( ~[0-9]+ ) 88 | ")); 89 | 90 | assert(ParamTest3("[1]").successful); 91 | assert(ParamTest3("[]").successful); 92 | assert(ParamTest3("[1, 2, 3]").successful); 93 | assert(ParamTest3("[1, 2, 3]").matches == ["1", "2", "3"]); 94 | assert(ParamTest3("[123,456,789]").successful); 95 | assert(ParamTest3("[123,456,789]").matches == ["123", "456", "789"]); 96 | // not arrays: 97 | assert(!ParamTest3("[1,2,]").successful, "Trailing comma."); 98 | assert(!ParamTest3("[1,,2,3]").successful, "Two commas in a row."); 99 | assert(!ParamTest3("[1,2,3").successful, "Missing closing ']'."); 100 | assert(!ParamTest3("1,2,3]").successful, "Missing opening '['."); 101 | assert(!ParamTest3("[,]").successful, "No numbers in array."); 102 | 103 | mixin(grammar(" 104 | ParamTest4: 105 | A <- Parameterized.String 106 | ")); 107 | 108 | assert(ParamTest4(`"abc"`).matches == [`abc`]); 109 | assert(ParamTest4(`""`).matches == []); 110 | 111 | mixin(grammar(" 112 | ParamTest5: 113 | A <- Parameterized.LineComment 114 | ")); 115 | 116 | ParseTree p5 = ParamTest5("// This is a comment! 117 | This is not a comment. 118 | End."); 119 | assert(p5.successful); 120 | assert(p5.matches == [" This is a comment!"]); 121 | } 122 | -------------------------------------------------------------------------------- /examples/peggedgrammar/dub.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "peggedgrammar", 3 | "description": "The somewhat extended PEG grammar used by Pegged itself, as described in Extended PEG Syntax.", 4 | "license": "Boost", 5 | "targetType": "library", 6 | "dependencies": { 7 | "pegged": { 8 | "version": "*", 9 | "path": "../.." 10 | } 11 | }, 12 | "dflags": [ "-preview=dip1000" ] 13 | } 14 | -------------------------------------------------------------------------------- /examples/peggedgrammar/src/pegged/examples/peggedgrammar.d: -------------------------------------------------------------------------------- 1 | module pegged.examples.peggedgrammar; 2 | 3 | import pegged.grammar; 4 | 5 | enum PEGGEDgrammar = ` 6 | # This is the PEG extended grammar used by Pegged 7 | Pegged: 8 | 9 | # Syntactic rules: 10 | Grammar <- Spacing GrammarName Definition+ :eoi 11 | Definition <- LhsName Arrow Expression 12 | Expression <- FirstExpression / LongestExpression 13 | FirstExpression <- :OR? Sequence (:OR Sequence)+ 14 | LongestExpression <- :(OR / LONGEST_OR)? Sequence (:LONGEST_OR Sequence)* 15 | Sequence <- Prefix+ 16 | Prefix <- (POS / NEG / FUSE / DISCARD / KEEP / DROP / PROPAGATE)* Suffix 17 | Suffix <- Primary (OPTION / ZEROORMORE / ONEORMORE / Action)* 18 | Primary <- !(LhsName Arrow) 19 | ( RhsName 20 | / :OPEN Expression :CLOSE 21 | / Literal 22 | / CILiteral 23 | / CharClass 24 | / ANY) 25 | # Lexical syntax 26 | Identifier <- identifier 27 | GrammarName <- Identifier ParamList? Spacing :':' Spacing 28 | LhsName <- Identifier ParamList? Spacing 29 | RhsName <- Identifier ArgList? (NAMESEP Identifier ArgList?)* Spacing # NAMESEP is *not* discarded 30 | ParamList <- :OPEN Param (:SEPARATOR Param)* :CLOSE 31 | Param <- DefaultParam / SingleParam 32 | DefaultParam <- Identifier Spacing :ASSIGN Expression 33 | SingleParam <- Identifier Spacing 34 | ArgList <- :OPEN Expression (:SEPARATOR Expression)* :CLOSE 35 | 36 | Literal <- quote ~(!quote Char)* quote !'i' Spacing 37 | / doublequote ~(!doublequote Char)* doublequote !'i' Spacing 38 | CILiteral <- quote ~(!quote Char)* quote :'i' Spacing 39 | / doublequote ~(!doublequote Char)* doublequote :'i' Spacing 40 | CharClass <- :'[' (!']' CharRange)* :']' Spacing 41 | CharRange <- Char '-' Char / Char 42 | 43 | # Terminals 44 | Char <~ backslash ( quote 45 | / doublequote 46 | / backquote 47 | / backslash 48 | / '-' 49 | / '[' 50 | / ']' 51 | / [nrt] 52 | / [0-2][0-7][0-7] 53 | / [0-7][0-7]? 54 | / 'x' hexDigit hexDigit 55 | / 'u' hexDigit hexDigit hexDigit hexDigit 56 | / 'U' hexDigit hexDigit hexDigit hexDigit hexDigit hexDigit hexDigit hexDigit 57 | ) 58 | / . # or anything else 59 | 60 | Arrow <- LEFTARROW / FUSEARROW / DISCARDARROW / KEEPARROW / DROPARROW / PROPAGATEARROW / ACTIONARROW / SPACEARROW 61 | LEFTARROW <- '<-' Spacing 62 | FUSEARROW <- '<~' Spacing 63 | DISCARDARROW <- '<:' Spacing 64 | KEEPARROW <- '<^' Spacing 65 | DROPARROW <- '<;' Spacing 66 | PROPAGATEARROW <- '<%' Spacing 67 | SPACEARROW <- '<' Spacing 68 | ACTIONARROW <- '<' Action Spacing 69 | 70 | OR <- '/' Spacing 71 | LONGEST_OR <- '|' Spacing 72 | 73 | POS <- '&' Spacing 74 | NEG <- '!' Spacing 75 | FUSE <- '~' Spacing 76 | DISCARD <- ':' Spacing 77 | KEEP <- '^' Spacing 78 | DROP <- ';' Spacing 79 | PROPAGATE <- '%' Spacing 80 | 81 | OPTION <- '?' Spacing 82 | ZEROORMORE <- '*' Spacing 83 | ONEORMORE <- '+' Spacing 84 | ACTIONOPEN <- '{' Spacing 85 | ACTIONCLOSE <- '}' Spacing 86 | SEPARATOR <- ',' Spacing 87 | ASSIGN <- '=' Spacing 88 | NAMESEP <- '.' # No Spacing 89 | OPEN <- '(' Spacing 90 | CLOSE <- ')' Spacing 91 | ANY <- '.' Spacing 92 | Spacing <: (blank / Comment)* 93 | Comment <- '#' (!eol .)* :eol 94 | Space <- spacing / "\\t" / "\\n" / "\\r" 95 | 96 | # Action Rule 97 | Action <- :ACTIONOPEN Spacing ((Lambda / qualifiedIdentifier) 98 | (:SEPARATOR (Lambda / qualifiedIdentifier))*) Spacing :ACTIONCLOSE 99 | Lambda <~ (!(ACTIONCLOSE/SEPARATOR) (LambdaItems / NestedList('{',LambdaItems,'}') / .))* 100 | 101 | LambdaItems <- ~DComment / ~DString / ~DParamList 102 | DString <- WYSString / DBQString / TKNString / DLMString 103 | 104 | WYSString <- 'r' doublequote (!doublequote .)* doublequote / 105 | backquote (!backquote .)* backquote 106 | 107 | DBQString <- doublequote (!doublequote Char)* doublequote 108 | 109 | TKNString <- (&'q{' ('q' NestedList('{',DString,'}'))) 110 | 111 | DLMString <- ('q' doublequote) ( (&'{' NestedList('{',DString,'}')) 112 | / (&'[' NestedList('[',DString,']')) 113 | / (&'(' NestedList('(',DString,')')) 114 | / (&'<' NestedList('<',DString,'>')) 115 | ) doublequote 116 | 117 | DComment <- DLineComment / DBlockComment / DNestingBlockComment 118 | 119 | DLineComment <- "//" (!endOfLine .)* endOfLine 120 | DBlockComment <- "/*" (!"*/" .)* "*/" 121 | DNestingBlockComment <- NestedList("/+","+/") 122 | 123 | DParamList <- NestedList('(',')') 124 | 125 | # Linear nested lists with and without special items 126 | NestedList(L,Items,R) <- ^L ( !(L/R/Items) . )* ( Items 127 | / NestedList(L,Items,R) 128 | / ( !(L/R/Items) . )* 129 | )* ( !(L/R/Items) . )* ^R 130 | 131 | NestedList(L,R) <- ^L ( !(L/R) . )* (NestedList(L,R) / ( !(L/R) . )*)* ( !(L/R) . )* ^R 132 | `; 133 | -------------------------------------------------------------------------------- /examples/python/Makefile: -------------------------------------------------------------------------------- 1 | 2 | test: 3 | dub test 4 | -------------------------------------------------------------------------------- /examples/python/dub.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "python", 3 | "description": "The Python-3 programming language grammar.", 4 | "license": "PSF LICENSE", 5 | "targetType": "library", 6 | "dependencies": { 7 | "pegged": { 8 | "version": "*", 9 | "path": "../.." 10 | } 11 | }, 12 | "dflags": [ "-preview=dip1000" ], 13 | "dflags-dmd": [ "-lowmem" ], 14 | "dflags-ldc": [ "--lowmem" ] 15 | } 16 | -------------------------------------------------------------------------------- /examples/simple_arithmetic/dub.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "simple_arithmetic", 3 | "description": "Example simple arithmetic PEG grammar. Parses arithmetic expression, like 1*(2+ x/3) - ( x * y * y -4).", 4 | "license": "Boost", 5 | "targetType": "library", 6 | "dependencies": { 7 | "pegged": { 8 | "version": "*", 9 | "path": "../.." 10 | } 11 | }, 12 | "dflags": [ "-preview=dip1000" ] 13 | } 14 | -------------------------------------------------------------------------------- /examples/simple_arithmetic/src/pegged/examples/simple_arithmetic.d: -------------------------------------------------------------------------------- 1 | /** 2 | This module contains a simple example of a arithmetic expression grammar and 3 | how use the ParseTree to calculate a expression. 4 | */ 5 | module pegged.examples.simple_arithmetic; 6 | 7 | import std.conv: to; 8 | 9 | import pegged.grammar; 10 | 11 | @safe: 12 | 13 | mixin(grammar(` 14 | Arithmetic: 15 | Term < Factor (Add / Sub)* 16 | Add < "+" Factor 17 | Sub < "-" Factor 18 | Factor < Primary (Mul / Div)* 19 | Mul < "*" Primary 20 | Div < "/" Primary 21 | Primary < Parens / Neg / Number / Variable 22 | Parens < :"(" Term :")" 23 | Neg < "-" Primary 24 | Number < ~([0-9]+) 25 | Variable <- identifier 26 | `)); 27 | 28 | /// Example interpreter 29 | float interpreter(string expr) 30 | { 31 | auto p = Arithmetic(expr); 32 | 33 | // Travels the ParseTree, calculting the expresion value 34 | float value(ParseTree p) 35 | { 36 | switch (p.name) 37 | { 38 | case "Arithmetic": 39 | return value(p.children[0]); 40 | case "Arithmetic.Term": 41 | float v = 0.0; 42 | foreach(child; p.children) v += value(child); 43 | return v; 44 | case "Arithmetic.Add": 45 | return value(p.children[0]); 46 | case "Arithmetic.Sub": 47 | return -value(p.children[0]); 48 | case "Arithmetic.Factor": 49 | float v = 1.0; 50 | foreach(child; p.children) v *= value(child); 51 | return v; 52 | case "Arithmetic.Mul": 53 | return value(p.children[0]); 54 | case "Arithmetic.Div": 55 | return 1.0/value(p.children[0]); 56 | case "Arithmetic.Primary": 57 | return value(p.children[0]); 58 | case "Arithmetic.Parens": 59 | return value(p.children[0]); 60 | case "Arithmetic.Neg": 61 | return -value(p.children[0]); 62 | case "Arithmetic.Number": 63 | return to!float(p.matches[0]); 64 | default: 65 | return float.nan; 66 | } 67 | } 68 | 69 | return value(p); 70 | } 71 | 72 | unittest 73 | { 74 | assert(interpreter("1") == 1.0); 75 | assert(interpreter("-1") == -1.0); 76 | assert(interpreter("1+1") == 2.0); 77 | assert(interpreter("1-1") == 0.0); 78 | 79 | assert(interpreter("1+1+1") == 3.0); 80 | assert(interpreter("1-1-1") == -1.0); 81 | assert(interpreter("1+1-1") == 1.0); 82 | assert(interpreter("1-1+1") == 1.0); 83 | assert(interpreter("-1+1+1") == 1.0); 84 | 85 | assert(interpreter("(-1+1)+1") == 1.0); 86 | assert(interpreter("-1+(1+1)") == 1.0); 87 | assert(interpreter("(-1+1+1)") == 1.0); 88 | assert(interpreter("1-(1-1)") == 1.0); 89 | 90 | assert(interpreter("1*1") == 1.0); 91 | assert(interpreter("1/1") == 1.0); 92 | assert(interpreter("-1*1") == -1.0); 93 | assert(interpreter("-1/1") == -1.0); 94 | 95 | assert(interpreter("1+2*3") == 7.0); 96 | assert(interpreter("1-2*3") == -5.0); 97 | assert(interpreter("-1-2*-3") == 5.0); 98 | assert(interpreter("-1+2*-3") == -7.0); 99 | 100 | assert(interpreter("1/2/(1/2)") == 1.0); 101 | assert(interpreter("1/2/1/2") == .25); 102 | assert(interpreter("1 - 2*3 - 2*3") == -11.0); 103 | 104 | assert(interpreter("2*3*3 - 3*3+3*4") == 21.0); 105 | assert(interpreter("2 * 3 * 3 - 3 * (3 + 3 * 4)") == -27.0); 106 | } 107 | -------------------------------------------------------------------------------- /examples/strings/dub.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "strings", 3 | "description": "Example strings PEG grammar. Parses double-quoted strings. An example of how to do escaping and looking for an end marker.", 4 | "license": "Boost", 5 | "targetType": "library", 6 | "dependencies": { 7 | "pegged": { 8 | "version": "*", 9 | "path": "../.." 10 | } 11 | }, 12 | "dflags": [ "-preview=dip1000" ] 13 | } 14 | -------------------------------------------------------------------------------- /examples/strings/src/pegged/examples/strings.d: -------------------------------------------------------------------------------- 1 | module pegged.examples.strings; 2 | 3 | import pegged.grammar; 4 | 5 | @safe: 6 | 7 | mixin(grammar(` 8 | String: 9 | # Example of a rule for double-quoted strings 10 | 11 | String <~ doublequote (!doublequote Char)* doublequote 12 | 13 | Char <~ backslash ( doublequote # '\' Escapes 14 | / quote 15 | / backslash 16 | / [bfnrt] 17 | / [0-2][0-7][0-7] 18 | / [0-7][0-7]? 19 | / 'x' Hex Hex 20 | / 'u' Hex Hex Hex Hex 21 | / 'U' Hex Hex Hex Hex Hex Hex Hex Hex 22 | ) 23 | / . # Or any char, really 24 | 25 | Hex <- [0-9a-fA-F] 26 | `)); 27 | 28 | unittest 29 | { 30 | assert(String(`"Hello, World!"`).successful); 31 | assert(String(`"Hello, 32 | 33 | World!"`).successful); 34 | assert(String(`""`).successful); 35 | assert(String(`"\'\""`).successful); 36 | assert(String(`"\\"`).successful); 37 | assert(String(`"\n\t\r"`).successful); 38 | assert(String(`"\60\61\7\111"`).successful); 39 | assert(String(`"\x40\x41"`).successful); 40 | assert(String(`"\u00A0\u00FF"`).successful); 41 | assert(String(`"\U000000A0\U000000B2"`).successful); 42 | 43 | // Failures 44 | assert(!String(`"Hello, World!`).successful); 45 | assert(!String(`Hello, World!"`).successful); 46 | assert(!String(`Hello, World!`).successful); 47 | } 48 | -------------------------------------------------------------------------------- /examples/xml/dub.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "xml", 3 | "description": "Two example of XML grammars. xml.d that is a very simple aproach, and xml2.d that follows W3C grammar.", 4 | "license": "Boost", 5 | "targetType": "library", 6 | "dependencies": { 7 | "pegged": { 8 | "version": "*", 9 | "path": "../.." 10 | } 11 | }, 12 | "dflags": [ "-preview=dip1000" ] 13 | } 14 | -------------------------------------------------------------------------------- /examples/xml/src/pegged/examples/xml.d: -------------------------------------------------------------------------------- 1 | /** 2 | * Ultra-simple XML grammar 3 | */ 4 | module pegged.examples.xml; 5 | 6 | import pegged.grammar; 7 | 8 | import std.array; 9 | 10 | @safe: 11 | 12 | string[] nameStack; 13 | 14 | /// Semantic action to push a tag name on a stack 15 | O opening(O)(O o) 16 | { 17 | if (o.successful) 18 | nameStack ~= o.matches; 19 | return o; 20 | } 21 | 22 | /** 23 | * Semantic action to pop the name stack and compare a tag name 24 | * The parsing fails if the tags do not nest correctly (See docs, the Semantic Actions wiki page) 25 | */ 26 | O closing(O)(O o) 27 | { 28 | if (o.matches.empty || nameStack.back != o.matches[0]) 29 | o.successful = false; 30 | else 31 | nameStack.popBack(); 32 | return o; 33 | } 34 | 35 | /** 36 | * Semantic action to flush the name stack 37 | */ 38 | O flush(O)(O o) 39 | { 40 | nameStack = null; 41 | return o; 42 | } 43 | 44 | mixin(grammar(` 45 | XML: 46 | Node <- OpeningTag{opening} (Node / Text)* ClosingTag{closing} 47 | OpeningTag <- :"<" identifier :">" 48 | ClosingTag <- :"" 49 | Text <~ (!OpeningTag !ClosingTag .)+ 50 | `)); 51 | 52 | unittest 53 | { 54 | auto p1 = XML(""); 55 | assert(p1.successful); 56 | assert(p1.matches == ["a", "a"]); 57 | assert(p1.children[0].children.length == 2); 58 | 59 | assert(p1.children[0].name == "XML.Node"); 60 | assert(p1.children[0].children[0].name == "XML.OpeningTag"); 61 | assert(p1.children[0].children[1].name == "XML.ClosingTag"); 62 | 63 | assert(!XML("").successful); // incomplete closing tag 64 | assert(!XML("").successful); // unmatched tag 65 | assert( XML("").successful); // OK 66 | assert(!XML("").successful); // badly enclosed tags 67 | 68 | auto p2 = XML("Hello World! This is an important announcement!"); 69 | assert(p2.successful); 70 | 71 | assert(p2.matches == ["text", "Hello World! This is an ", "emph", "important", "emph", " announcement!", "text"]); 72 | assert(p2.children[0].children[0].matches == ["text"]); 73 | assert(p2.children[0].children[1].matches == ["Hello World! This is an "]); 74 | assert(p2.children[0].children[$-1].matches == ["text"]); 75 | } 76 | -------------------------------------------------------------------------------- /examples/xml/src/pegged/examples/xml2.d: -------------------------------------------------------------------------------- 1 | module pegged.examples.xml2; 2 | 3 | import pegged.grammar; 4 | 5 | @safe: 6 | 7 | enum XMLgrammar = ` 8 | XML: 9 | 10 | Document <- prolog element Misc* 11 | 12 | Char <- . 13 | 14 | # RestrictedChar <- [\u0001-\uD7FF\uE000-\uFFFD] 15 | #\U00010000-\U0010FFFF] 16 | 17 | S <: ~('\x20' / '\x09' / '\x0D' / '\x0A')+ 18 | 19 | NameStartChar <- ":" / [A-Z] / "_" / [a-z] / [\xC0-\xD6\xD8-\xF6] 20 | 21 | # \xF8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD] 22 | # \U00010000-\U000EFFFF] 23 | 24 | NameChar <- NameStartChar / "-" / "." / [0-9] / '\xB7' 25 | # / [\u0300-\u036F] / [\x203F-\x2040] 26 | 27 | Name <~ NameStartChar (NameChar)* 28 | 29 | Names <- Name (' ' Name)* 30 | 31 | Nmtoken <~ (NameChar)+ 32 | 33 | nmtokens <- Nmtoken (' ' Nmtoken)* 34 | 35 | EntityValue <- doublequote (!('%' / '&' / doublequote) Char / PEReference / Reference)* doublequote 36 | / quote (!('%' / '&' / quote) Char / PEReference / Reference)* quote 37 | 38 | AttValue <- doublequote (!('%' / '&' / doublequote) Char / Reference)* doublequote 39 | / quote (!('%' / '&' / quote) Char / Reference)* quote 40 | 41 | SystemLiteral <~ doublequote (!doublequote Char)* doublequote 42 | / quote (!quote Char)* quote 43 | 44 | PubidLiteral <~ doublequote PubidChar* doublequote 45 | / quote (!quote PubidChar)* quote 46 | 47 | PubidChar <- [\x20\x0D\x0A] / [a-zA-Z0-9] / [-'()+,./:=?;!*#@$_%] 48 | 49 | CharData <~ (!('<' / '&' / "]]>" ) Char)* 50 | 51 | Comment <- "" 52 | 53 | PI <- "" Char)*)? "?>" 54 | 55 | PITarget <- !([xX][mM][lL]) Name 56 | 57 | CDSect <- CDStart CData CDEnd 58 | 59 | CDStart <- "" Char)* 62 | 63 | CDEnd <- "]]>" 64 | 65 | prolog <- XMLDecl Misc* (doctypedecl Misc*)? 66 | 67 | XMLDecl <- "" 68 | 69 | VersionInfo <- S "version" Eq (quote VersionNum quote / doublequote VersionNum doublequote) 70 | 71 | Eq <- S? '=' S? 72 | 73 | VersionNum <- '1.0' / '1.1' 74 | 75 | Misc <- Comment / PI / S 76 | 77 | doctypedecl <- "' 78 | 79 | DeclSep <- PEReference / S 80 | 81 | intSubset <- (markupdecl / DeclSep)* 82 | 83 | markupdecl <- elementdecl / AttlistDecl / EntityDecl / NotationDecl / PI / Comment 84 | 85 | extSubset <- TextDecl? extSubsetDecl 86 | extSubsetDecl <- (markupdecl / conditionalSect / DeclSep)* 87 | 88 | 89 | SDDecl <- S 'standalone' Eq ( doublequote ("yes"/"no") doublequote 90 | / quote ("yes"/"no") quote) 91 | 92 | element <- EmptyElemTag / STag content ETag 93 | 94 | STag <- "<" Name (S Attribute)* S? ">" 95 | Attribute <- Name Eq AttValue 96 | 97 | ETag <- "" 98 | 99 | content <- CharData? ((element / Reference / CDSect / PI / Comment) CharData?)* 100 | 101 | EmptyElemTag <- "<" (S Attribute)* S? "/>" 102 | 103 | elementdecl <- "" 104 | contentspec <- "EMPTY" / "ANY" / Mixed / children 105 | 106 | children <- (choice / seq) ('?' / '*' / '+')? 107 | cp <- (Name / choice / seq) ('?' / '*' / '+')? 108 | choice <- '(' S? cp ( S? '|' S? cp )+ S? ')' 109 | seq <- '(' S? cp ( S? ',' S? cp )* S? ')' 110 | 111 | Mixed <- '(' S? "#PCDATA" (S? '|' S? Name)* S? ")*" 112 | / '(' S? "#PCDATA" S? ")" 113 | 114 | AttlistDecl <- "" 115 | AttDef <- S Name S AttType S DefaultDecl 116 | 117 | AttType <- StringType / TokenizedType / EnumeratedType 118 | StringType <- "CDATA" 119 | TokenizedType <- "IDREFS" / "IDREF" / "ID" 120 | / "ENTITIES" / "ENTITY" 121 | / "NMTOKENS" / "NMTOKEN" 122 | 123 | EnumeratedType <- NotationType / Enumeration 124 | NotationType <- "NOTATION" S "(" S? Name (S? '|' S? Name)* S? ')' 125 | 126 | Enumeration <- '(' S? Nmtoken (S? '|' S? Nmtoken)* S? ')' 127 | 128 | DefaultDecl <- "#REQUIRED" / "#IMPLIED" 129 | / (("#FIXED" S)? AttValue) 130 | 131 | conditionalSect <- includeSect / ignoreSect 132 | 133 | includeSect <- "" 134 | 135 | ignoreSect <- "" 136 | 137 | ignoreSectContents <- Ignore ("" Ignore)* 138 | 139 | Ignore <- (!("") Char)* 140 | 141 | CharRef <- "&#" [0-9]+ ";" 142 | / "&#x" [0-9a-fA-F]+ ";" 143 | 144 | Reference <- EntityRef / CharRef 145 | 146 | EntityRef <- '&' Name ';' 147 | 148 | PEReference <- '%' Name ';' 149 | 150 | EntityDecl <- GEDecl / PEDecl 151 | 152 | GEDecl <- "' 153 | PEDecl <- "' 154 | 155 | EntityDef <- EntityValue / (ExternalID NDataDecl?) 156 | 157 | PEDef <- EntityValue / ExternalID 158 | 159 | ExternalID <- "SYSTEM" S SystemLiteral 160 | / "PUBLIC" S PubidLiteral S SystemLiteral 161 | 162 | NDataDecl <- S "NDATA" S Name 163 | 164 | TextDecl <- "" 165 | 166 | extParsedEnt <- (TextDecl? content) 167 | 168 | EncodingDecl <- S "encoding" Eq ( doublequote EncName doublequote 169 | / quote EncName quote) 170 | EncName <~ [A-Za-z] ([A-Za-z0-9._] / '-')* 171 | 172 | NotationDecl <- "" 173 | PublicID <- "PUBLIC" S PubidLiteral 174 | 175 | `; 176 | 177 | mixin(grammar(XMLgrammar)); 178 | 179 | enum example1 = 180 | ` 181 | 182 | 183 | 184 | Empire Burlesque 185 | Bob Dylan 186 | USA 187 | Columbia 188 | 10.90 189 | 1985 190 | 191 | 192 | Hide your heart 193 | Bonnie Tyler 194 | UK 195 | CBS Records 196 | 9.90 197 | 1988 198 | 199 | 200 | Greatest Hits 201 | Dolly Parton 202 | USA 203 | RCA 204 | 9.90 205 | 1982 206 | 207 | 208 | Still got the blues 209 | Gary Moore 210 | UK 211 | Virgin records 212 | 10.20 213 | 1990 214 | 215 | 216 | Eros 217 | Eros Ramazzotti 218 | EU 219 | BMG 220 | 9.90 221 | 1997 222 | 223 | 224 | One night only 225 | Bee Gees 226 | UK 227 | Polydor 228 | 10.90 229 | 1998 230 | 231 | 232 | Sylvias Mother 233 | Dr.Hook 234 | UK 235 | CBS 236 | 8.10 237 | 1973 238 | 239 | 240 | Maggie May 241 | Rod Stewart 242 | UK 243 | Pickwick 244 | 8.50 245 | 1990 246 | 247 | 248 | Romanza 249 | Andrea Bocelli 250 | EU 251 | Polydor 252 | 10.80 253 | 1996 254 | 255 | 256 | When a man loves a woman 257 | Percy Sledge 258 | USA 259 | Atlantic 260 | 8.70 261 | 1987 262 | 263 | 264 | Black angel 265 | Savage Rose 266 | EU 267 | Mega 268 | 10.90 269 | 1995 270 | 271 | 272 | 1999 Grammy Nominees 273 | Many 274 | USA 275 | Grammy 276 | 10.20 277 | 1999 278 | 279 | 280 | For the good times 281 | Kenny Rogers 282 | UK 283 | Mucik Master 284 | 8.70 285 | 1995 286 | 287 | 288 | Big Willie style 289 | Will Smith 290 | USA 291 | Columbia 292 | 9.90 293 | 1997 294 | 295 | 296 | Tupelo Honey 297 | Van Morrison 298 | UK 299 | Polydor 300 | 8.20 301 | 1971 302 | 303 | 304 | Soulsville 305 | Jorn Hoel 306 | Norway 307 | WEA 308 | 7.90 309 | 1996 310 | 311 | 312 | The very best of 313 | Cat Stevens 314 | UK 315 | Island 316 | 8.90 317 | 1990 318 | 319 | 320 | Stop 321 | Sam Brown 322 | UK 323 | A and M 324 | 8.90 325 | 1988 326 | 327 | 328 | Bridge of Spies 329 | T'Pau 330 | UK 331 | Siren 332 | 7.90 333 | 1987 334 | 335 | 336 | Private Dancer 337 | Tina Turner 338 | UK 339 | Capitol 340 | 8.90 341 | 1983 342 | 343 | 344 | Midt om natten 345 | Kim Larsen 346 | EU 347 | Medley 348 | 7.80 349 | 1983 350 | 351 | 352 | Pavarotti Gala Concert 353 | Luciano Pavarotti 354 | UK 355 | DECCA 356 | 9.90 357 | 1991 358 | 359 | 360 | The dock of the bay 361 | Otis Redding 362 | USA 363 | Atlantic 364 | 7.90 365 | 1987 366 | 367 | 368 | Picture book 369 | Simply Red 370 | EU 371 | Elektra 372 | 7.20 373 | 1985 374 | 375 | 376 | Red 377 | The Communards 378 | UK 379 | London 380 | 7.80 381 | 1987 382 | 383 | 384 | Unchain my heart 385 | Joe Cocker 386 | USA 387 | EMI 388 | 8.20 389 | 1987 390 | 391 | 392 | `; 393 | 394 | enum example2 = 395 | ` 396 | 397 | 398 | Gambardella, Matthew 399 | XML Developer's Guide 400 | Computer 401 | 44.95 402 | 2000-10-01 403 | An in-depth look at creating applications 404 | with XML. 405 | 406 | 407 | Ralls, Kim 408 | Midnight Rain 409 | Fantasy 410 | 5.95 411 | 2000-12-16 412 | A former architect battles corporate zombies, 413 | an evil sorceress, and her own childhood to become queen 414 | of the world. 415 | 416 | 417 | Corets, Eva 418 | Maeve Ascendant 419 | Fantasy 420 | 5.95 421 | 2000-11-17 422 | After the collapse of a nanotechnology 423 | society in England, the young survivors lay the 424 | foundation for a new society. 425 | 426 | 427 | Corets, Eva 428 | Oberon's Legacy 429 | Fantasy 430 | 5.95 431 | 2001-03-10 432 | In post-apocalypse England, the mysterious 433 | agent known only as Oberon helps to create a new life 434 | for the inhabitants of London. Sequel to Maeve 435 | Ascendant. 436 | 437 | 438 | Corets, Eva 439 | The Sundered Grail 440 | Fantasy 441 | 5.95 442 | 2001-09-10 443 | The two daughters of Maeve, half-sisters, 444 | battle one another for control of England. Sequel to 445 | Oberon's Legacy. 446 | 447 | 448 | Randall, Cynthia 449 | Lover Birds 450 | Romance 451 | 4.95 452 | 2000-09-02 453 | When Carla meets Paul at an ornithology 454 | conference, tempers fly as feathers get ruffled. 455 | 456 | 457 | Thurman, Paula 458 | Splish Splash 459 | Romance 460 | 4.95 461 | 2000-11-02 462 | A deep sea diver finds true love twenty 463 | thousand leagues beneath the sea. 464 | 465 | 466 | Knorr, Stefan 467 | Creepy Crawlies 468 | Horror 469 | 4.95 470 | 2000-12-06 471 | An anthology of horror stories about roaches, 472 | centipedes, scorpions and other insects. 473 | 474 | 475 | Kress, Peter 476 | Paradox Lost 477 | Science Fiction 478 | 6.95 479 | 2000-11-02 480 | After an inadvertant trip through a Heisenberg 481 | Uncertainty Device, James Salway discovers the problems 482 | of being quantum. 483 | 484 | 485 | O'Brien, Tim 486 | Microsoft .NET: The Programming Bible 487 | Computer 488 | 36.95 489 | 2000-12-09 490 | Microsoft's .NET initiative is explored in 491 | detail in this deep programmer's reference. 492 | 493 | 494 | O'Brien, Tim 495 | MSXML3: A Comprehensive Guide 496 | Computer 497 | 36.95 498 | 2000-12-01 499 | The Microsoft MSXML3 parser is covered in 500 | detail, with attention to XML DOM interfaces, XSLT processing, 501 | SAX and more. 502 | 503 | 504 | Galos, Mike 505 | Visual Studio 7: A Comprehensive Guide 506 | Computer 507 | 49.95 508 | 2001-04-16 509 | Microsoft Visual Studio 7 is explored in depth, 510 | looking at how Visual Basic, Visual C++, C#, and ASP+ are 511 | integrated into a comprehensive development 512 | environment. 513 | 514 | 515 | `; 516 | 517 | unittest 518 | { 519 | assert(XML(example1).successful); 520 | assert(XML(example2).successful); 521 | } 522 | -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | all: 2 | if [ -x /usr/bin/dmd ]; then \ 3 | dmd -w -wi -O -release -noboundscheck -lib -oflibpegged.a pegged/peg.d pegged/grammar.d pegged/parser.d pegged/introspection.d pegged/dynamic/grammar.d pegged/dynamic/peg.d; \ 4 | elif [ -x /usr/bin/ldc2 ]; then \ 5 | ldc2 -w -wi -O2 -release -boundscheck=off -c -of=libpegged.a pegged/peg.d pegged/grammar.d pegged/parser.d pegged/dynamic/grammar.d pegged/dynamic/peg.d; \ 6 | elif [ -x /usr/bin/gdc ]; then \ 7 | gdc -Wall -O2 -frelease -fbounds-check=off -c -olibpegged.a pegged/peg.d pegged/grammar.d pegged/parser.d pegged/dynamic/grammar.d pegged/dynamic/peg.d; \ 8 | fi 9 | 10 | clean: 11 | rm -f libpegged.a 12 | -------------------------------------------------------------------------------- /pegged.valgrind: -------------------------------------------------------------------------------- 1 | { 2 | 3 | Memcheck:Leak 4 | fun:malloc 5 | fun:thread_attachThis 6 | fun:thread_init 7 | fun:gc_init 8 | fun:_D2rt6dmain24mainUiPPaZi6runAllMFZv 9 | fun:_D2rt6dmain24mainUiPPaZi7tryExecMFMDFZvZv 10 | fun:main 11 | } 12 | 13 | { 14 | 15 | Memcheck:Leak 16 | fun:malloc 17 | fun:_D4core6thread6Thread5slockFNdZC4core4sync5mutex5Mutex 18 | fun:_D4core6thread6Thread3addFC4core6thread6ThreadZv 19 | fun:thread_attachThis 20 | fun:thread_init 21 | fun:gc_init 22 | fun:_D2rt6dmain24mainUiPPaZi6runAllMFZv 23 | fun:_D2rt6dmain24mainUiPPaZi7tryExecMFMDFZvZv 24 | fun:main 25 | } 26 | 27 | { 28 | 29 | Memcheck:Leak 30 | fun:calloc 31 | fun:_d_monitor_create 32 | fun:_d_monitorenter 33 | fun:_D4core6thread6Thread8isDaemonMFNdZb 34 | fun:_D4core6thread14thread_joinAllUZv16__foreachbody333MFKC4core6thread6ThreadZi 35 | fun:_D4core6thread6Thread7opApplyFMDFKC4core6thread6ThreadZiZi 36 | fun:thread_joinAll 37 | fun:_D2rt6dmain24mainUiPPaZi6runAllMFZv 38 | fun:_D2rt6dmain24mainUiPPaZi7tryExecMFMDFZvZv 39 | fun:main 40 | } 41 | 42 | { 43 | 44 | Memcheck:Leak 45 | fun:malloc 46 | fun:_D2rt5minfo14getModuleInfosFZAPS6object10ModuleInfo 47 | fun:rt_moduleCtor 48 | fun:_D2rt6dmain24mainUiPPaZi6runAllMFZv 49 | fun:_D2rt6dmain24mainUiPPaZi7tryExecMFMDFZvZv 50 | fun:main 51 | } 52 | -------------------------------------------------------------------------------- /pegged/dev/README.md: -------------------------------------------------------------------------------- 1 | # Folder `pegged/dev` 2 | 3 | The files used for Pegged development. Also, some files for possible, yet-to-come, extensions. 4 | 5 | ## `regenerate.d` 6 | 7 | Regenerates `parser.d` according to the Pegged grammar in `examples/peggedgrammar.d`. Depends on an existing and functioning `parser.d`. 8 | 9 | ``` 10 | rdmd -I../.. -I../../examples/peggedgrammar/src -I../../examples/misc/src regenerate.d 11 | ``` 12 | -------------------------------------------------------------------------------- /pegged/dev/TODO.md: -------------------------------------------------------------------------------- 1 | Pegged TODO: 2 | ============ 3 | 4 | Short term: 5 | 6 | TODO: add an enum inside ParseTree's, containing the rules's name, to enable final switch selection 7 | TODO: option infrastructure (easier for the user: grammar!(memoizing, inlining, debug)) 8 | TODO: Add a debug mode that logs everything a parser does: which rule was tested by sequences and choices, which was unsuccessful, and so on. 9 | TODO: (Almost done in the 'betterintrospection' branch) introspection: unit rules (A <- B), generating rules (terminals are generating, sequences are if all subrules are generating), non reachable rules, useless rules (non-reachable or non generating) 10 | 11 | Long term: 12 | 13 | TODO: Make it possible for rules to be both non-parameterized and parameterized (ie A <- ... and A(B) <- ... in the same grammar) ? 14 | TODO: parsing a range. 15 | TODO: a function that reconstitutes D code from a parse tree. 16 | TODO: tree functions (at least filtering, reducing and matching on trees). 17 | TODO: parsing context and undoing any change done by a failed rule. 18 | TODO: code lowerings. 19 | TODO: Add a boolean grammar (&&, ||, !) and a comparison grammar( ==, !=, <, >, <=, >=), calling arithmeric expressions. 20 | TODO: import expressions in grammars? 21 | TODO: rules parameterized on numbers 22 | TODO: external rules, introduced by < name > or automatically recognized. 23 | TODO: direct D code, with {{ }} ? Or use < > for actions and { } for D code 24 | TODO: [ ] after rule names and grammars, for options. 25 | TODO: adding [ ] after a grammar name for importing other grammars. 26 | TODO: another option for grammars, coupled to external rules: creating inner variables. 27 | TODO: drop the static methods and try standard methods? -------------------------------------------------------------------------------- /pegged/dev/regenerate.d: -------------------------------------------------------------------------------- 1 | /** 2 | * Recreate the Pegged parser from the grammar. 3 | * 4 | * When called without arguments: generate sources. 5 | * Otherwise: validate that sources were generated. 6 | */ 7 | module pegged.dev.regenerate; 8 | 9 | import pegged.grammar; 10 | import pegged.examples.peggedgrammar; 11 | import pegged.examples.testergrammar; 12 | 13 | enum Task {generate, validate} 14 | 15 | void main(string[] args) 16 | { 17 | const task = args.length == 1 ? Task.generate : Task.validate; 18 | doModule!(Memoization.no) (task, "pegged.parser", "../parser", PEGGEDgrammar); 19 | doModule!(Memoization.yes)(task, "pegged.tester.testerparser", "../tester/testerparser", testerGrammar); 20 | } 21 | 22 | void doModule(Memoization withMemo = Memoization.yes)(Task task, string moduleName, string fileName, string grammarString, string optHeader = "") 23 | { 24 | final switch (task) with (Task) 25 | { 26 | case generate: 27 | asModule!(withMemo)(moduleName, fileName, grammarString, optHeader); 28 | break; 29 | case validate: 30 | { 31 | import std.file : remove; 32 | import std.algorithm : equal; 33 | import std.exception : enforce; 34 | import std.stdio : File; 35 | 36 | const tempName = "tempfile"; 37 | const tempNameExt = tempName ~ ".d"; 38 | const fileNameExt = fileName ~ ".d"; 39 | const chunk = 1024; 40 | scope (exit) { remove(tempNameExt); } 41 | asModule!(withMemo)(moduleName, tempName, grammarString, optHeader); 42 | enforce(equal(File(fileNameExt).byChunk(chunk), File(tempNameExt).byChunk(chunk)), 43 | `"` ~ fileNameExt ~ `" deviates from its grammar. Consult pegged/dev/README.md.`); 44 | break; 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /pegged/dev/test.d: -------------------------------------------------------------------------------- 1 | /// Testing Pegged modifications. 2 | module pegged.dev.test; 3 | 4 | //import std.algorithm; 5 | //import std.array; 6 | //import std.conv; 7 | import std.datetime; 8 | //import std.functional; 9 | //import std.range; 10 | import std.stdio; 11 | //import std.typecons; 12 | //import std.typetuple; 13 | 14 | import pegged.grammar; 15 | 16 | mixin(grammar(` 17 | Test: 18 | A <- B* C 19 | B <- 'b' 20 | C <- 'c' 21 | `)); 22 | 23 | 24 | void main() { 25 | writeln(Test("bbbbc")); 26 | } 27 | -------------------------------------------------------------------------------- /pegged/docs/README.md: -------------------------------------------------------------------------------- 1 | # Folder `pegged/docs` 2 | 3 | The github Pegged wiki is a git submodule. To get the latest wiki dump, do: 4 | 5 | ```bash 6 | $ cd 7 | $ git submodule init 8 | $ git submodule update 9 | ``` 10 | 11 | This will download the wiki as a bunch of markdown files, for your perusal. 12 | -------------------------------------------------------------------------------- /pegged/docs/cheatsheet/Makefile: -------------------------------------------------------------------------------- 1 | # A (very) simple build script to generate a PDF for a LaTeX project. 2 | 3 | SRC := cheatsheet 4 | BUILDDIR := build 5 | 6 | LATEXC := pdflatex 7 | LATEXCFLAGS := -interaction=nonstopmode -output-directory ${BUILDDIR} 8 | 9 | .PHONY: all clean 10 | all:: 11 | -@mkdir ${BUILDDIR} 2>/dev/null; exit 0 12 | @${LATEXC} ${LATEXCFLAGS} ${SRC} 13 | 14 | clean:: 15 | -@rm -rf ${SRCDIR}/*~ ${BUILDDIR} 16 | -------------------------------------------------------------------------------- /pegged/docs/cheatsheet/cheatsheet.tex: -------------------------------------------------------------------------------- 1 | % based on the fantastic work from http://www.stdout.org/~winston/latex/ 2 | \documentclass[10pt]{article} 3 | 4 | \usepackage{multicol} 5 | \usepackage{calc} 6 | \usepackage{ifthen} 7 | \usepackage{geometry} 8 | 9 | % conditional page margins based on paper size 10 | \ifthenelse{\lengthtest { \paperwidth = 11in}} 11 | { \geometry{top=.5in,left=.5in,right=.5in,bottom=.5in} } 12 | {\ifthenelse{ \lengthtest{ \paperwidth = 297mm}} 13 | {\geometry{top=1cm,left=1cm,right=1cm,bottom=1cm} } 14 | {\geometry{top=1cm,left=1cm,right=1cm,bottom=1cm} } 15 | } 16 | 17 | % remove page header and footer 18 | \pagestyle{empty} 19 | 20 | % redefine section commands to use less space 21 | \makeatletter 22 | \renewcommand{\section}{\@startsection{section}{1}{0mm}% 23 | {-1ex plus -.5ex minus -.2ex}% 24 | {0.5ex plus .2ex}%x 25 | {\normalfont\large\bfseries}} 26 | \renewcommand{\subsection}{\@startsection{subsection}{2}{0mm}% 27 | {-1explus -.5ex minus -.2ex}% 28 | {0.5ex plus .2ex}% 29 | {\normalfont\normalsize\bfseries}} 30 | \renewcommand{\subsubsection}{\@startsection{subsubsection}{3}{0mm}% 31 | {-1ex plus -.5ex minus -.2ex}% 32 | {1ex plus .2ex}% 33 | {\normalfont\small\bfseries}} 34 | \makeatother 35 | 36 | % disable section numbering 37 | \setcounter{secnumdepth}{0} 38 | 39 | \setlength{\parindent}{0pt} 40 | \setlength{\parskip}{0pt plus 0.5ex} 41 | 42 | \begin{document} 43 | 44 | \raggedright 45 | \footnotesize 46 | \begin{multicols}{2} 47 | % multicol parameters 48 | \setlength{\premulticols}{1pt} 49 | \setlength{\postmulticols}{1pt} 50 | \setlength{\multicolsep}{1pt} 51 | \setlength{\columnsep}{2pt} 52 | 53 | % header 54 | \begin{center} 55 | \Large{\textbf{Pegged Cheat Sheet}} \\ 56 | \end{center} 57 | 58 | \section{Rules} 59 | \begin{tabular}{@{}ll@{}} 60 | \verb! < ! & Creates a space consuming sequence. \\ 61 | \verb! <~! & Concatenates a sequences of matches into one string. \\ 62 | \verb! <:! & Creates a sequence to be discarded. \\ 63 | \verb! <;! & Creates a sequence stored in the parent node. \\ 64 | \end{tabular} 65 | 66 | Every operator suffix of a \verb!= begin && p.input[p.end] <= end) 104 | return ParseTree("charRange!(" ~ to!string(begin) ~ ", " ~ to!string(end) ~ ")", true, [p.input[p.end..p.end+1]], p.input, p.end, p.end+1); 105 | else 106 | return ParseTree("charRange!(" ~ to!string(begin) ~ ", " ~ to!string(end) ~ ")", false, [longName], p.input, p.end, p.end); 107 | }; 108 | 109 | } 110 | 111 | Dynamic wrapAround(B, M, A)(B before, M middle, A after) 112 | { 113 | return(ParseTree p) 114 | { 115 | ParseTree temp = callDynamic(before,p); 116 | if (!temp.successful) 117 | return temp; 118 | 119 | ParseTree result = callDynamic(middle,temp); 120 | if (!result.successful) 121 | return result; 122 | result.begin = temp.begin; 123 | 124 | temp = callDynamic(after,result); 125 | if (!temp.successful) 126 | return temp; 127 | 128 | result.end = temp.end; 129 | return result; 130 | }; 131 | } 132 | 133 | Dynamic zeroOrMore(D)(D d) 134 | { 135 | return (ParseTree p) 136 | { 137 | string name = "zeroOrMore!(" ~ getName(d) ~ ")"; 138 | ParseTree result = ParseTree(name, true, [], p.input, p.end, p.end); 139 | ParseTree temp = callDynamic(d,result); 140 | while(temp.successful 141 | && (temp.begin < temp.end // To avoid infinite loops on epsilon-matching rules 142 | || temp.name.startsWith("discard!("))) 143 | { 144 | result.matches ~= temp.matches; 145 | result.children ~= temp; 146 | result.end = temp.end; 147 | temp = callDynamic(d, result); 148 | } 149 | result.successful = true; 150 | return result; 151 | }; 152 | } 153 | 154 | Dynamic oneOrMore(D)(D d) 155 | { 156 | return(ParseTree p) 157 | { 158 | string name = "oneOrMore!(" ~ getName(d) ~ ")"; 159 | ParseTree result = ParseTree(name, false, [], p.input, p.end, p.end); 160 | ParseTree temp = callDynamic(d, result); 161 | 162 | if (!temp.successful) 163 | { 164 | result.matches = temp.matches; 165 | result.children = [temp]; 166 | result.end = temp.end; 167 | } 168 | else 169 | { 170 | while( temp.successful 171 | && (temp.begin < temp.end // To avoid infinite loops on epsilon-matching rules 172 | || temp.name.startsWith("discard!("))) 173 | { 174 | result.matches ~= temp.matches; 175 | result.children ~= temp; 176 | result.end = temp.end; 177 | temp = callDynamic(d, result); 178 | } 179 | result.successful = true; 180 | } 181 | return result; 182 | }; 183 | } 184 | 185 | Dynamic option(D)(D d) 186 | { 187 | return (ParseTree p) 188 | { 189 | string name = "option!(" ~ getName(d) ~ ")"; 190 | ParseTree result = callDynamic(d, p); 191 | if (result.successful) 192 | return ParseTree(name, true, result.matches, result.input, result.begin, result.end, [result]); 193 | else 194 | return ParseTree(name, true, [], p.input, p.end, p.end, null); 195 | }; 196 | } 197 | 198 | Dynamic and(T...)(T rules) if (T.length) 199 | { 200 | return (ParseTree p) 201 | { 202 | bool keepNode(ParseTree node) 203 | { 204 | return node.name.startsWith("keep!(") 205 | || ( !node.name.startsWith("discard!(") 206 | //&& !node.name.startsWith("drop!(") 207 | && node.matches !is null 208 | //&& node.begin != node.end 209 | ); 210 | } 211 | 212 | 213 | string name = "and!(" ~ ")"; 214 | 215 | ParseTree result = ParseTree(name, false, [], p.input, p.end, p.end, []); 216 | 217 | foreach(i,r; rules) 218 | { 219 | ParseTree temp = callDynamic(r, result); 220 | 221 | result.end = temp.end; 222 | if (temp.successful) 223 | { 224 | if (keepNode(temp)) 225 | { 226 | result.matches ~= temp.matches; 227 | if (temp.name.startsWith("drop!(")) 228 | {} 229 | else if (temp.name.startsWith("propagate!(")) 230 | result.children ~= temp.children; 231 | else 232 | result.children ~= temp; 233 | } 234 | } 235 | else 236 | { 237 | result.children ~= temp;// add the failed node, to indicate which failed 238 | if (temp.matches.length > 0) 239 | result.matches ~= temp.matches[$-1]; 240 | return result; // and end the parsing attempt right there 241 | } 242 | } 243 | result.successful = true; 244 | return result; 245 | }; 246 | } 247 | 248 | Dynamic or(T...)(T rules) 249 | { 250 | return (ParseTree p) @safe 251 | { 252 | // error-management 253 | ParseTree longestFail = ParseTree("or", false, [], p.input, p.end, 0); 254 | string[] errorStrings; 255 | size_t errorStringChars; 256 | string orErrorString; 257 | 258 | ParseTree[rules.length] results; 259 | string[rules.length] names; 260 | size_t[rules.length] failedLength; 261 | size_t maxFailedLength; 262 | 263 | // Real 'or' loop 264 | foreach(i,r; rules) 265 | { 266 | ParseTree temp = callDynamic(r, p); 267 | if (temp.successful) 268 | { 269 | temp.children = [temp]; 270 | temp.name = "or"; 271 | return temp; 272 | } 273 | else 274 | { 275 | enum errName = " (" ~")"; 276 | failedLength[i] = temp.end; 277 | if (temp.end >= longestFail.end) 278 | { 279 | maxFailedLength = temp.end; 280 | longestFail = temp; 281 | names[i] = errName; 282 | results[i] = temp; 283 | 284 | if (temp.end == longestFail.end) 285 | errorStringChars += temp.matches[$-1].length + errName.length + 4; 286 | else 287 | errorStringChars = temp.matches[$-1].length + errName.length + 4; 288 | } 289 | // Else, this error parsed less input than another one: we discard it. 290 | } 291 | } 292 | 293 | 294 | // All subrules failed, we will take the longest match as the result 295 | // If more than one node failed at the same (farthest) position, we concatenate their error messages 296 | 297 | 298 | string errString; 299 | errString.reserve(errorStringChars); 300 | foreach(i; 0..rules.length) 301 | if (failedLength[i] == maxFailedLength) 302 | errString ~= results[i].matches[$-1] ~ names[i] ~ " or "; 303 | orErrorString = errString[0..$-4]; 304 | 305 | longestFail.matches = longestFail.matches[0..$-1] // discarding longestFail error message 306 | ~ [orErrorString]; // and replacing it by the new, concatenated one. 307 | longestFail.name = "or"; 308 | longestFail.begin = p.end; 309 | return longestFail; 310 | }; 311 | } 312 | 313 | Dynamic posLookahead(D)(D d) 314 | { 315 | return (ParseTree p) 316 | { 317 | string name = "posLookahead!(" ~ getName(d) ~ ")"; 318 | ParseTree temp = callDynamic(d,p); 319 | if (temp.successful) 320 | return ParseTree(name, temp.successful, [], p.input, p.end, p.end); 321 | else 322 | return ParseTree(name, temp.successful, [temp.matches[$-1]], p.input, p.end, p.end); 323 | }; 324 | } 325 | 326 | Dynamic negLookahead(D)(D d) 327 | { 328 | return (ParseTree p) 329 | { 330 | string name = "negLookahead!(" ~ getName(d) ~ ")"; 331 | ParseTree temp = callDynamic(d,p); 332 | if (temp.successful) 333 | return ParseTree(name, false, ["anything but \"" ~ p.input[temp.begin..temp.end] ~ "\""], p.input, p.end, p.end); 334 | else 335 | return ParseTree(name, true, [], p.input, p.end, p.end); 336 | }; 337 | } 338 | 339 | Dynamic named(D)(D d, string name) 340 | { 341 | return (ParseTree p) 342 | { 343 | ParseTree result = callDynamic(d,p); 344 | result.name = name; 345 | return result; 346 | }; 347 | } 348 | 349 | Dynamic action(D, A)(D d, A act) 350 | { 351 | return (ParseTree p) 352 | { 353 | return callDynamic(act, callDynamic(d,p)); 354 | }; 355 | } 356 | 357 | Dynamic fuse(D)(D d) 358 | { 359 | return(ParseTree p) 360 | { 361 | p = callDynamic(d,p); 362 | if (p.successful) 363 | { 364 | if (p.matches.length != 0) 365 | p.matches = [join(p.matches)]; 366 | 367 | p.children = null; // also discard children 368 | } 369 | return p; 370 | }; 371 | } 372 | 373 | Dynamic discardChildren(D)(D d) 374 | { 375 | return (ParseTree p) 376 | { 377 | p = callDynamic(d,p); 378 | p.children = null; 379 | return p; 380 | }; 381 | } 382 | 383 | Dynamic discardMatches(D)(D d) 384 | { 385 | return (ParseTree p) 386 | { 387 | p = callDynamic(d,p); 388 | if (p.successful) 389 | p.matches = null; 390 | return p; 391 | }; 392 | } 393 | 394 | Dynamic discard(D)(D d) 395 | { 396 | return (ParseTree p) 397 | { 398 | ParseTree result = callDynamic(d,p); 399 | result.name = "discard!(" ~ getName(d) ~ ")"; 400 | //result.begin = result.end; 401 | result.children = null; 402 | if (result.successful) 403 | result.matches = null;//to keep error messages, if any 404 | 405 | return result; 406 | }; 407 | } 408 | 409 | Dynamic drop(D)(D d) 410 | { 411 | return (ParseTree p) 412 | { 413 | ParseTree result = callDynamic(d,p); 414 | result.children = null; 415 | if (result.successful) 416 | result.name = "drop!(" ~ getName(d) ~ ")"; 417 | return result; 418 | }; 419 | } 420 | 421 | Dynamic propagate(D)(D d) 422 | { 423 | return (ParseTree p) 424 | { 425 | ParseTree result = callDynamic(d,p); 426 | if (result.successful) 427 | result.name = "propagate!(" ~ getName(d) ~ ")"; 428 | return result; 429 | }; 430 | } 431 | 432 | Dynamic keep(D)(D d) 433 | { 434 | return (ParseTree p) 435 | { 436 | ParseTree result = callDynamic(d,p); 437 | if (result.successful) 438 | { 439 | result.children = [result]; 440 | result.name = "keep!(" ~ getName(d) ~ ")"; 441 | } 442 | return result; 443 | }; 444 | } 445 | -------------------------------------------------------------------------------- /pegged/performancetest/cursive/generator.d: -------------------------------------------------------------------------------- 1 | module pegged.performancetest.cursive.generator; 2 | 3 | import pegged.grammar; 4 | 5 | void main() 6 | { 7 | asModule("pegged.performancetest.cursive.parser2", 8 | "parser2", 9 | 10 | 11 | "Cursive: 12 | Program <- Spacing Module Spacing (Declaration Spacing)* Spacing eoi 13 | LineComment <- :(slash slash (&(endOfLine / eoi) (endOfLine / eoi) / .*)) 14 | BlockComment <- :(slash '*' (&('*' slash) '*' slash / .*)) 15 | 16 | Boolean <- 'true' / 'false' 17 | Null <- 'null' 18 | 19 | IntegerSuffix <- slash ('i8' / 'u8' / 'i16' / 'u16' / 'i32' / 'u32' / 'i64' / 'u64') 20 | RealSuffix <- slash ('f32' / 'f64') 21 | 22 | Sign <- '+' / '-' 23 | 24 | Decimal <~ [0-9]+ 25 | Binary <~ '0' ('b' / 'B') [0-1]+ 26 | Octal <~ '0' ('o' / 'O') [0-7]+ 27 | Hexadecimal <~ '0' ('x' / 'X') [0-9a-fA-F]+ 28 | 29 | Size <- Binary / Octal / Hexadecimal / Decimal 30 | Integer <- Sign? (Binary / Octal / Hexadecimal / Decimal) IntegerSuffix 31 | Real <- Sign? Decimal '.' Decimal (('e' / 'E') Sign? Decimal)? RealSuffix 32 | 33 | EscapeSequence <- backslash (quote / doublequote / backslash / 'a' / 'b' / 'f' / 'n' / 'r' / 't' / 'v' / '0') 34 | UnicodeSequence <- backslash ('u' / 'U') '+'? [0-9a-fA-F]+ 35 | 36 | Character <~ :quote (EscapeSequence / UnicodeSequence / !quote .) :quote 37 | String <~ :doublequote (EscapeSequence / UnicodeSequence / !doublequote .)* :doublequote 38 | 39 | Literal <- Boolean / Null / Real / Integer / Character / String 40 | 41 | Qualifiedidentifier <- identifier (Spacing '.' Spacing identifier)* 42 | 43 | FixedIntegralType <- 'int8' / 'uint8' / 'int16' / 'uint16' / 'int32' / 'uint32' / 'int64' / 'uint64' 44 | IntegralType <- FixedIntegralType / 'int' / 'uint' 45 | FloatingPointType <- 'float32' / 'float64' 46 | CoreType <- 'object' / 'bool' / IntegralType / FloatingPointType 47 | 48 | TypeReference <- Qualifiedidentifier (Spacing GenericParameters)? 49 | TypeSpecification <- (CoreType / TypeReference) Spacing NullableType? 50 | GenericParameters <- '<' Spacing Type (Spacing ',' Spacing Type)* Spacing '>' 51 | 52 | FunctionType <- CallingConvention? Spacing ParameterTypes Spacing NullableType? 53 | ParameterTypes <- '(' Spacing (Type (Spacing ',' Spacing Type)*)? ')' 54 | 55 | PointerType <- '*' 56 | ArrayType <- '[' Spacing ']' 57 | VectorType <- '[' Spacing Size Spacing ']' 58 | NullableType <- '?' 59 | 60 | TupleType <- '{' Spacing Type (Spacing ',' Spacing Type)* Spacing '}' 61 | 62 | TypeModifiers <- (PointerType / ArrayType / VectorType)+ Spacing NullableType? 63 | Type <- TupleType / TypeSpecification (Spacing (TypeModifiers / FunctionType))? 64 | InferredType <- 'var' / Type 65 | 66 | ReturnType <- 'void' / Type 67 | CallingConvention <- 'cdecl' / 'stdcall' 68 | 69 | Module <- 'module' Spacing Qualifiedidentifier Spacing ';' 70 | 71 | Import <- 'import' Spacing Qualifiedidentifier (Spacing ',' Spacing Qualifiedidentifier)* ';' 72 | 73 | Declaration <- Import / Class / Interface / Struct / Enum / Data / ModuleConstructor / ModuleFinalizer / Field / ModuleFunction / Operator 74 | 75 | Visibility <- 'public' / 'internal' / 'private' / 'protected' (('and' / 'or') 'internal')? 76 | 77 | InheritanceList <- ':' Spacing TypeReference (Spacing ',' Spacing TypeReference)* 78 | 79 | Class <- Visibility? Spacing ClassModifiers Spacing 'class' Spacing identifier Spacing InheritanceList? '{' Spacing (ClassMember Spacing)* Spacing '}' 80 | ClassModifiers <- ('open' / 'abstract')? Spacing ('pure' / 'impure')? Spacing ('safe' / 'unsafe')? 81 | ClassMember <- ClassConstructor / ClassFinalizer / Constructor / Finalizer / Field / Property / Method / Operator 82 | 83 | Interface <- Visibility? Spacing 'interface' Spacing identifier Spacing InheritanceList? Spacing '{' Spacing (InterfaceMember Spacing)* Spacing '}' 84 | InterfaceMember <- Property / Method / Operator 85 | 86 | Struct <- Visibility? Spacing StructModifiers Spacing 'struct' Spacing identifier Spacing InheritanceList? Spacing '{' Spacing (StructMember Spacing)* Spacing '}' 87 | StructModifiers <- ('pure' / 'impure')? Spacing ('safe' / 'unsafe')? 88 | StructMember <- StructConstructor / StructFinalizer / Constructor / Field / Property / Function / Operator 89 | 90 | Enum <- Visibility? Spacing 'enum' Spacing identifier Spacing EnumBase Spacing '{' Spacing (EnumMember Spacing)* Spacing '}' 91 | EnumBase <- 'of' Spacing FixedIntegralType 92 | EnumMember <- identifier (Spacing ',' Spacing identifier)* Spacing '=' Spacing Size Spacing ';' 93 | 94 | Data <- Visibility? Spacing 'data' Spacing DataSemantics Spacing identifier Spacing '{' Spacing (DataMember Spacing)* Spacing '}' 95 | DataSemantics <- 'byref' / 'byval' 96 | DataMember <- DataField / DataCase / Property / Function / Operator 97 | DataField <- Type Spacing identifier (Spacing ',' Spacing identifier)* Spacing ';' 98 | DataCase <- 'case' Spacing identifier '{' Spacing (DataField Spacing)* Spacing '}' 99 | 100 | StaticConstructorModifiers <- 'thread'? Spacing ('pure' / 'impure')? Spacing ('safe' / 'unsafe')? 101 | StaticConstructorBody <- BlockStatement 102 | 103 | ModuleConstructor <- StaticConstructorModifiers Spacing 'module' Spacing '(' Spacing ')' Spacing StaticConstructorBody 104 | ModuleFinalizer <- StaticConstructorModifiers Spacing '~' Spacing 'module' Spacing EmptyParameterList Spacing StaticConstructorBody 105 | 106 | ClassConstructor <- StaticConstructorModifiers Spacing 'class' Spacing '(' Spacing ')' Spacing StaticConstructorBody 107 | ClassFinalizer <- StaticConstructorModifiers Spacing '~' Spacing 'class' Spacing EmptyParameterList Spacing StaticConstructorBody 108 | 109 | StructConstructor <- StaticConstructorModifiers Spacing 'struct' Spacing '(' Spacing ')' Spacing StaticConstructorBody 110 | StructFinalizer <- StaticConstructorModifiers Spacing '~' Spacing 'struct' Spacing EmptyParameterList Spacing StaticConstructorBody 111 | 112 | Field <- Visibility? Spacing FieldModifiers Spacing Type Spacing identifier (Spacing ',' Spacing identifier)* Spacing ';' 113 | FieldModifiers <- 'const' / ('thread' / 'static')? Spacing 'final'? 114 | 115 | ModuleFunction <- RawFunction / ExternFunction / Function 116 | 117 | RawFunction <- Visibility? Spacing 'raw' Spacing ReturnType Spacing identifier Spacing ParameterList Spacing RawFunctionBody 118 | RawFunctionBody <- BlockStatement 119 | 120 | ExternFunction <- Visibility? Spacing 'extern' Spacing ExternFunctionLocation Spacing ReturnType Spacing identifier Spacing ParameterList Spacing ';' 121 | ExternFunctionLocation <- '(' Spacing String Spacing ',' Spacing String Spacing ')' 122 | 123 | Function <- Visibility? Spacing FunctionModifiers Spacing ReturnType Spacing identifier Spacing ParameterList Spacing FunctionBody 124 | FunctionModifiers <- ('pure' / 'impure')? Spacing ('safe' / 'unsafe')? 125 | FunctionBody <- BlockStatement 126 | 127 | EmptyParameterList <- '(' Spacing ')' 128 | ParameterList <- '(' Spacing (Parameter (Spacing ',' Spacing Parameter)*)? Spacing ')' 129 | Parameter <- ParameterModifiers Spacing Type Spacing identifier 130 | ParameterModifiers <- ('ref' / 'out' / 'params')? 131 | 132 | Operator <- Visibility? Spacing Type Spacing 'operator' Spacing CustomOperator Spacing ParameterList Spacing OperatorBody 133 | CustomOperator <- '+' / '-' / '*' / slash / '%' / '&' / '|' / '^' 134 | OperatorBody <- BlockStatement 135 | 136 | Property <- Visibility? Spacing PropertyModifiers Spacing Type Spacing identifier Spacing '{' Spacing PropertyBody Spacing '}' 137 | PropertyModifiers <- ('pure' / 'impure')? Spacing ('safe' / 'unsafe')? Spacing (('virtual' / 'abstract') / 'override'? Spacing 'final'?) 138 | PropertyBody <- PropertyGetter Spacing PropertySetter / PropertyGetter / PropertySetter 139 | PropertyGetter <- AccessorModifiers Spacing 'get' Spacing AccessorBody 140 | PropertySetter <- AccessorModifiers Spacing 'set' Spacing AccessorBody 141 | AccessorModifiers <- ('pure' / 'impure')? Spacing ('safe' / 'unsafe')? 142 | AccessorBody <- BlockStatement / ';' 143 | 144 | Method <- Visibility? Spacing MethodModifiers Spacing ReturnType Spacing identifier Spacing ParameterList Spacing MethodBody 145 | MethodModifiers <- ('pure' / 'impure')? Spacing ('safe' / 'unsafe')? Spacing (('virtual' / 'abstract') / 'override'? Spacing 'final'?) 146 | MethodBody <- BlockStatement / ';' 147 | 148 | Constructor <- Visibility? Spacing 'this' Spacing ParameterList Spacing FunctionBody 149 | Finalizer <- '~' Spacing 'this' Spacing EmptyParameterList Spacing FunctionBody 150 | 151 | BlockStatement <- '{' Spacing '}' 152 | 153 | "); 154 | } 155 | -------------------------------------------------------------------------------- /pegged/performancetest/cursive/reader.d: -------------------------------------------------------------------------------- 1 | module pegged.performancetest.cursive.reader; 2 | 3 | import std.datetime; 4 | import pegged.performancetest.cursive.parser; 5 | 6 | void main(string[] args) 7 | { 8 | import std.stdio, std.file; 9 | 10 | string input = readText(args[1]); 11 | 12 | int N = 100; 13 | auto time = benchmark!( () => Cursive(input) )(N); 14 | 15 | writeln("Parser 1: ", time[0].to!("msecs",int)/N, " ms to parse test.crs on average."); 16 | } 17 | -------------------------------------------------------------------------------- /pegged/performancetest/cursive/test.crs: -------------------------------------------------------------------------------- 1 | module test; 2 | 3 | class A {} 4 | class A {} 5 | class A {} 6 | class A {} 7 | class A {} 8 | class A {} 9 | class A {} 10 | class A {} 11 | class A {} 12 | class A {} 13 | class A {} 14 | class A {} 15 | class A {} 16 | class A {} 17 | class A {} 18 | class A {} 19 | class A {} 20 | class A {} 21 | class A {} 22 | class A {} 23 | class A {} 24 | class A {} 25 | class A {} 26 | class A {} 27 | class A {} 28 | class A {} 29 | class A {} 30 | class A {} 31 | class A {} 32 | class A {} 33 | class A {} 34 | class A {} 35 | class A {} 36 | class A {} 37 | class A {} 38 | class A {} 39 | class A {} 40 | class A {} 41 | class A {} 42 | class A {} 43 | class A {} 44 | class A {} 45 | class A {} 46 | class A {} 47 | class A {} 48 | class A {} 49 | class A {} 50 | class A {} 51 | class A {} 52 | class A {} 53 | class A {} 54 | class A {} 55 | class A {} 56 | class A {} 57 | class A {} 58 | class A {} 59 | class A {} 60 | class A {} 61 | class A {} 62 | class A {} 63 | class A {} 64 | class A {} 65 | class A {} 66 | class A {} 67 | class A {} 68 | class A {} 69 | class A {} 70 | class A {} 71 | class A {} 72 | class A {} 73 | class A {} 74 | class A {} 75 | class A {} 76 | class A {} 77 | class A {} 78 | class A {} 79 | class A {} 80 | class A {} 81 | class A {} 82 | class A {} 83 | class A {} 84 | class A {} 85 | class A {} 86 | class A {} 87 | class A {} 88 | class A {} 89 | class A {} 90 | class A {} 91 | class A {} 92 | class A {} 93 | class A {} 94 | class A {} 95 | class A {} 96 | class A {} 97 | class A {} 98 | class A {} 99 | class A {} 100 | class A {} 101 | class A {} 102 | class A {} 103 | class A {} 104 | class A {} 105 | class A {} 106 | class A {} 107 | class A {} 108 | class A {} 109 | class A {} 110 | class A {} 111 | class A {} 112 | class A {} 113 | class A {} 114 | class A {} 115 | class A {} 116 | class A {} 117 | class A {} 118 | class A {} 119 | class A {} 120 | class A {} 121 | class A {} 122 | class A {} 123 | class A {} 124 | class A {} 125 | class A {} 126 | class A {} 127 | class A {} 128 | class A {} 129 | class A {} 130 | class A {} 131 | class A {} 132 | class A {} 133 | class A {} 134 | class A {} 135 | class A {} 136 | class A {} 137 | class A {} 138 | class A {} 139 | class A {} 140 | class A {} 141 | class A {} 142 | class A {} 143 | class A {} 144 | class A {} 145 | class A {} 146 | class A {} 147 | class A {} 148 | class A {} 149 | class A {} 150 | class A {} 151 | class A {} 152 | class A {} 153 | class A {} 154 | class A {} 155 | class A {} 156 | class A {} 157 | class A {} 158 | class A {} 159 | class A {} 160 | class A {} 161 | class A {} 162 | class A {} 163 | class A {} 164 | class A {} 165 | class A {} 166 | class A {} 167 | class A {} 168 | class A {} 169 | class A {} 170 | class A {} 171 | class A {} 172 | class A {} 173 | class A {} 174 | class A {} 175 | class A {} 176 | class A {} 177 | class A {} 178 | class A {} 179 | class A {} 180 | class A {} 181 | class A {} 182 | class A {} 183 | class A {} 184 | class A {} 185 | class A {} 186 | class A {} 187 | class A {} 188 | class A {} 189 | class A {} 190 | class A {} 191 | class A {} 192 | class A {} 193 | class A {} 194 | class A {} 195 | class A {} 196 | class A {} 197 | class A {} 198 | class A {} 199 | class A {} 200 | class A {} 201 | class A {} 202 | class A {} 203 | class A {} 204 | class A {} 205 | class A {} 206 | class A {} 207 | class A {} 208 | class A {} 209 | class A {} 210 | class A {} 211 | class A {} 212 | class A {} 213 | class A {} 214 | class A {} 215 | class A {} 216 | class A {} 217 | class A {} 218 | class A {} 219 | class A {} 220 | class A {} 221 | class A {} 222 | class A {} 223 | class A {} 224 | class A {} 225 | class A {} 226 | class A {} 227 | class A {} 228 | class A {} 229 | class A {} 230 | class A {} 231 | class A {} 232 | class A {} 233 | class A {} 234 | class A {} 235 | class A {} 236 | class A {} 237 | class A {} 238 | class A {} 239 | class A {} 240 | class A {} 241 | class A {} 242 | class A {} 243 | class A {} 244 | class A {} 245 | class A {} 246 | class A {} 247 | class A {} 248 | class A {} 249 | class A {} 250 | class A {} 251 | class A {} 252 | class A {} 253 | class A {} 254 | class A {} 255 | class A {} 256 | class A {} 257 | class A {} 258 | class A {} 259 | class A {} 260 | class A {} 261 | class A {} 262 | class A {} 263 | class A {} 264 | class A {} 265 | class A {} 266 | class A {} 267 | class A {} 268 | class A {} 269 | class A {} 270 | class A {} 271 | class A {} 272 | class A {} 273 | class A {} 274 | class A {} 275 | class A {} 276 | class A {} 277 | class A {} 278 | class A {} 279 | class A {} 280 | class A {} 281 | class A {} 282 | class A {} 283 | class A {} 284 | class A {} 285 | class A {} 286 | class A {} 287 | class A {} 288 | class A {} 289 | class A {} 290 | class A {} 291 | class A {} 292 | class A {} 293 | class A {} 294 | class A {} 295 | class A {} 296 | class A {} 297 | class A {} 298 | class A {} 299 | class A {} 300 | class A {} 301 | class A {} 302 | class A {} 303 | class A {} 304 | class A {} 305 | class A {} 306 | class A {} 307 | class A {} 308 | class A {} 309 | class A {} 310 | class A {} 311 | class A {} 312 | class A {} 313 | class A {} 314 | class A {} 315 | class A {} 316 | class A {} 317 | class A {} 318 | class A {} 319 | class A {} 320 | class A {} 321 | class A {} 322 | class A {} 323 | class A {} 324 | class A {} 325 | class A {} 326 | class A {} 327 | class A {} 328 | class A {} 329 | class A {} 330 | class A {} 331 | class A {} 332 | class A {} 333 | class A {} 334 | class A {} 335 | class A {} 336 | class A {} 337 | class A {} 338 | class A {} 339 | class A {} 340 | class A {} 341 | class A {} 342 | class A {} 343 | class A {} 344 | class A {} 345 | class A {} 346 | class A {} 347 | class A {} 348 | class A {} 349 | class A {} 350 | class A {} 351 | class A {} 352 | class A {} 353 | class A {} 354 | class A {} 355 | class A {} 356 | class A {} 357 | class A {} 358 | class A {} 359 | class A {} 360 | class A {} 361 | class A {} 362 | class A {} 363 | class A {} 364 | class A {} 365 | class A {} 366 | class A {} 367 | class A {} 368 | class A {} 369 | class A {} 370 | class A {} 371 | class A {} 372 | class A {} 373 | class A {} 374 | class A {} 375 | class A {} 376 | class A {} 377 | class A {} 378 | class A {} 379 | class A {} 380 | class A {} 381 | class A {} 382 | class A {} 383 | class A {} 384 | class A {} 385 | class A {} 386 | class A {} 387 | class A {} 388 | class A {} 389 | class A {} 390 | class A {} 391 | class A {} 392 | class A {} 393 | class A {} 394 | class A {} 395 | class A {} 396 | class A {} 397 | class A {} 398 | class A {} 399 | class A {} 400 | class A {} 401 | class A {} 402 | class A {} 403 | class A {} 404 | class A {} 405 | class A {} 406 | class A {} 407 | class A {} 408 | class A {} 409 | class A {} 410 | class A {} 411 | class A {} 412 | class A {} 413 | class A {} 414 | class A {} 415 | class A {} 416 | class A {} 417 | class A {} 418 | class A {} 419 | class A {} 420 | class A {} 421 | class A {} 422 | class A {} 423 | class A {} 424 | class A {} 425 | class A {} 426 | class A {} 427 | class A {} 428 | class A {} 429 | class A {} 430 | class A {} 431 | class A {} 432 | class A {} 433 | class A {} 434 | class A {} 435 | class A {} 436 | class A {} 437 | class A {} 438 | class A {} 439 | class A {} 440 | class A {} 441 | class A {} 442 | class A {} 443 | class A {} 444 | class A {} 445 | class A {} 446 | class A {} 447 | class A {} 448 | class A {} 449 | class A {} 450 | class A {} 451 | class A {} 452 | class A {} 453 | class A {} 454 | class A {} 455 | class A {} 456 | class A {} 457 | class A {} 458 | class A {} 459 | class A {} 460 | class A {} 461 | class A {} 462 | class A {} 463 | class A {} 464 | class A {} 465 | class A {} 466 | class A {} 467 | class A {} 468 | class A {} 469 | class A {} 470 | class A {} 471 | class A {} 472 | class A {} 473 | class A {} 474 | class A {} 475 | class A {} 476 | class A {} 477 | class A {} 478 | class A {} 479 | class A {} 480 | class A {} 481 | class A {} 482 | class A {} 483 | class A {} 484 | class A {} 485 | class A {} 486 | class A {} 487 | class A {} 488 | class A {} 489 | class A {} 490 | class A {} 491 | class A {} 492 | class A {} 493 | class A {} 494 | class A {} 495 | class A {} 496 | class A {} 497 | class A {} 498 | class A {} 499 | class A {} 500 | class A {} 501 | class A {} 502 | class A {} 503 | class A {} 504 | class A {} 505 | class A {} 506 | class A {} 507 | class A {} 508 | class A {} 509 | class A {} 510 | class A {} 511 | class A {} 512 | class A {} 513 | class A {} 514 | class A {} 515 | class A {} 516 | class A {} 517 | class A {} 518 | class A {} 519 | class A {} 520 | class A {} 521 | class A {} 522 | class A {} 523 | class A {} 524 | class A {} 525 | class A {} 526 | class A {} 527 | class A {} 528 | class A {} 529 | class A {} 530 | class A {} 531 | class A {} 532 | class A {} 533 | class A {} 534 | class A {} 535 | class A {} 536 | class A {} 537 | class A {} 538 | class A {} 539 | class A {} 540 | class A {} 541 | class A {} 542 | class A {} 543 | class A {} 544 | class A {} 545 | class A {} 546 | class A {} 547 | class A {} 548 | class A {} 549 | class A {} 550 | class A {} 551 | class A {} 552 | class A {} 553 | class A {} 554 | class A {} 555 | class A {} 556 | class A {} 557 | class A {} 558 | class A {} 559 | class A {} 560 | class A {} 561 | class A {} 562 | class A {} 563 | class A {} 564 | class A {} 565 | class A {} 566 | class A {} 567 | class A {} 568 | class A {} 569 | class A {} 570 | class A {} 571 | class A {} 572 | class A {} 573 | class A {} 574 | class A {} 575 | class A {} 576 | class A {} 577 | class A {} 578 | class A {} 579 | class A {} 580 | class A {} 581 | class A {} 582 | class A {} 583 | class A {} 584 | class A {} 585 | class A {} 586 | class A {} 587 | class A {} 588 | class A {} 589 | class A {} 590 | class A {} 591 | class A {} 592 | class A {} 593 | class A {} 594 | class A {} 595 | class A {} 596 | class A {} 597 | class A {} 598 | class A {} 599 | class A {} 600 | class A {} 601 | class A {} 602 | class A {} 603 | class A {} 604 | class A {} 605 | class A {} 606 | class A {} 607 | class A {} 608 | class A {} 609 | class A {} 610 | class A {} 611 | class A {} 612 | class A {} 613 | class A {} 614 | class A {} 615 | class A {} 616 | class A {} 617 | class A {} 618 | class A {} 619 | class A {} 620 | class A {} 621 | class A {} 622 | class A {} 623 | class A {} 624 | class A {} 625 | class A {} 626 | class A {} 627 | class A {} 628 | class A {} 629 | class A {} 630 | class A {} 631 | class A {} 632 | class A {} 633 | class A {} 634 | class A {} 635 | class A {} 636 | class A {} 637 | class A {} 638 | class A {} 639 | class A {} 640 | class A {} 641 | class A {} 642 | class A {} 643 | class A {} 644 | class A {} 645 | class A {} 646 | class A {} 647 | class A {} 648 | class A {} 649 | class A {} 650 | class A {} 651 | class A {} 652 | class A {} 653 | class A {} 654 | class A {} 655 | class A {} 656 | class A {} 657 | class A {} 658 | class A {} 659 | class A {} 660 | class A {} 661 | class A {} 662 | class A {} 663 | class A {} 664 | class A {} 665 | class A {} 666 | class A {} 667 | class A {} 668 | class A {} 669 | class A {} 670 | class A {} 671 | class A {} 672 | class A {} 673 | class A {} 674 | class A {} 675 | class A {} 676 | class A {} 677 | class A {} 678 | class A {} 679 | class A {} 680 | class A {} 681 | class A {} 682 | class A {} 683 | class A {} 684 | class A {} 685 | class A {} 686 | class A {} 687 | class A {} 688 | class A {} 689 | class A {} 690 | class A {} 691 | class A {} 692 | class A {} 693 | class A {} 694 | class A {} 695 | class A {} 696 | class A {} 697 | class A {} 698 | class A {} 699 | class A {} 700 | class A {} 701 | class A {} 702 | class A {} 703 | class A {} 704 | class A {} 705 | class A {} 706 | class A {} 707 | class A {} 708 | class A {} 709 | class A {} 710 | class A {} 711 | class A {} 712 | class A {} 713 | class A {} 714 | class A {} 715 | class A {} 716 | class A {} 717 | class A {} 718 | class A {} 719 | class A {} 720 | class A {} 721 | class A {} 722 | class A {} 723 | class A {} 724 | class A {} 725 | class A {} 726 | class A {} 727 | class A {} 728 | class A {} 729 | class A {} 730 | class A {} 731 | class A {} 732 | class A {} 733 | class A {} 734 | class A {} 735 | class A {} 736 | class A {} 737 | class A {} 738 | class A {} 739 | class A {} 740 | class A {} 741 | class A {} 742 | class A {} 743 | class A {} 744 | class A {} 745 | class A {} 746 | class A {} 747 | class A {} 748 | class A {} 749 | class A {} 750 | class A {} 751 | class A {} 752 | class A {} 753 | class A {} 754 | class A {} 755 | class A {} 756 | class A {} 757 | class A {} 758 | class A {} 759 | class A {} 760 | class A {} 761 | class A {} 762 | class A {} 763 | class A {} 764 | class A {} 765 | class A {} 766 | class A {} 767 | class A {} 768 | class A {} 769 | class A {} 770 | class A {} 771 | class A {} 772 | class A {} 773 | class A {} 774 | class A {} 775 | class A {} 776 | class A {} 777 | class A {} 778 | class A {} 779 | class A {} 780 | class A {} 781 | class A {} 782 | class A {} 783 | class A {} 784 | class A {} 785 | class A {} 786 | class A {} 787 | class A {} 788 | class A {} 789 | class A {} 790 | class A {} 791 | class A {} 792 | class A {} 793 | class A {} 794 | class A {} 795 | class A {} 796 | class A {} 797 | class A {} 798 | class A {} 799 | class A {} 800 | class A {} 801 | class A {} 802 | class A {} 803 | class A {} 804 | class A {} 805 | class A {} 806 | class A {} 807 | class A {} 808 | class A {} 809 | class A {} 810 | class A {} 811 | class A {} 812 | class A {} 813 | class A {} 814 | class A {} 815 | class A {} 816 | class A {} 817 | class A {} 818 | class A {} 819 | class A {} 820 | class A {} 821 | class A {} 822 | class A {} 823 | class A {} 824 | class A {} 825 | class A {} 826 | class A {} 827 | class A {} 828 | class A {} 829 | class A {} 830 | class A {} 831 | class A {} 832 | class A {} 833 | class A {} 834 | class A {} 835 | class A {} 836 | class A {} 837 | class A {} 838 | class A {} 839 | class A {} 840 | class A {} 841 | class A {} 842 | class A {} 843 | class A {} 844 | class A {} 845 | class A {} 846 | class A {} 847 | class A {} 848 | class A {} 849 | class A {} 850 | class A {} 851 | class A {} 852 | class A {} 853 | class A {} 854 | class A {} 855 | class A {} 856 | class A {} 857 | class A {} 858 | class A {} 859 | class A {} 860 | class A {} 861 | class A {} 862 | class A {} 863 | class A {} 864 | class A {} 865 | class A {} 866 | class A {} 867 | class A {} 868 | class A {} 869 | class A {} 870 | class A {} 871 | class A {} 872 | class A {} 873 | class A {} 874 | class A {} 875 | class A {} 876 | class A {} 877 | class A {} 878 | class A {} 879 | class A {} 880 | class A {} 881 | class A {} 882 | class A {} 883 | class A {} 884 | class A {} 885 | class A {} 886 | class A {} 887 | class A {} 888 | class A {} 889 | class A {} 890 | class A {} 891 | class A {} 892 | class A {} 893 | class A {} 894 | class A {} 895 | class A {} 896 | class A {} 897 | class A {} 898 | class A {} 899 | class A {} 900 | class A {} 901 | class A {} 902 | class A {} 903 | class A {} 904 | class A {} 905 | class A {} 906 | class A {} 907 | class A {} 908 | class A {} 909 | class A {} 910 | class A {} 911 | class A {} 912 | class A {} 913 | class A {} 914 | class A {} 915 | class A {} 916 | class A {} 917 | class A {} 918 | class A {} 919 | class A {} 920 | class A {} 921 | class A {} 922 | class A {} 923 | class A {} 924 | class A {} 925 | class A {} 926 | class A {} 927 | class A {} 928 | class A {} 929 | class A {} 930 | class A {} 931 | class A {} 932 | class A {} 933 | class A {} 934 | class A {} 935 | class A {} 936 | class A {} 937 | class A {} 938 | class A {} 939 | class A {} 940 | class A {} 941 | class A {} 942 | class A {} 943 | class A {} 944 | class A {} 945 | class A {} 946 | class A {} 947 | class A {} 948 | class A {} 949 | class A {} 950 | class A {} 951 | class A {} 952 | class A {} 953 | class A {} 954 | class A {} 955 | class A {} 956 | class A {} 957 | class A {} 958 | class A {} 959 | class A {} 960 | class A {} 961 | class A {} 962 | class A {} 963 | class A {} 964 | class A {} 965 | class A {} 966 | class A {} 967 | class A {} 968 | class A {} 969 | class A {} 970 | class A {} 971 | class A {} 972 | class A {} 973 | class A {} 974 | class A {} 975 | class A {} 976 | class A {} 977 | class A {} 978 | class A {} 979 | class A {} 980 | class A {} 981 | class A {} 982 | class A {} 983 | class A {} 984 | class A {} 985 | class A {} 986 | class A {} 987 | class A {} 988 | class A {} 989 | class A {} 990 | class A {} 991 | class A {} 992 | class A {} 993 | class A {} 994 | class A {} 995 | class A {} 996 | class A {} 997 | class A {} 998 | class A {} 999 | class A {} 1000 | class A {} 1001 | class A {} 1002 | class A {} 1003 | -------------------------------------------------------------------------------- /pegged/test/tester.d: -------------------------------------------------------------------------------- 1 | module pegged.tester.main; 2 | 3 | import std.stdio; 4 | 5 | // Import the modules with unit tests. 6 | import pegged.grammar, 7 | pegged.peg; 8 | 9 | int main() 10 | { 11 | // This main function implicitly triggers unit tests 12 | // of all loaded modules. This is its sole purpose. 13 | version (unittest) 14 | { 15 | writeln("All unit tests passed!"); 16 | return 0; 17 | } 18 | else 19 | { 20 | // The build system doesn't actually let this 21 | // happen, but just in case someone compiles it 22 | // in an awkward way... 23 | writeln("Not compiled with unit tests; no tests run."); 24 | return 1; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /pegged/tester/README.md: -------------------------------------------------------------------------------- 1 | # Folder `pegged/tester` 2 | 3 | This contains the modules used to test a grammar. 4 | -------------------------------------------------------------------------------- /pegged/tohtml.d: -------------------------------------------------------------------------------- 1 | module pegged.tohtml; 2 | 3 | import std.stdio; 4 | import std.conv, std.string; 5 | import std.algorithm.searching; 6 | import pegged.peg; 7 | 8 | enum Expand 9 | { 10 | no, ifMatch, ifNotMatch 11 | } 12 | 13 | /** 14 | * Writes a parse tree to a html file. 15 | * 16 | * Params: 17 | * e = Defines if the tree is expanded. 18 | * Details = Defines the details, as a list of strings, that are expanded 19 | * when e is equal to `Expand.ifMatch`, and not expanded when e is equal to 20 | * `Expand.ifNotMatch`. When no details are passed, each node is expanded. 21 | * p = The ParseTree to represent. 22 | * file = The file where to write the tree. 23 | */ 24 | void toHTML(Expand e = Expand.no, Details...)(const ref ParseTree p, 25 | File file) 26 | { 27 | file.write(` 28 | 29 | 30 | 31 | 32 | Pegged produced parse tree 33 | 70 | 71 | 72 | `); 73 | 74 | void treeToHTML(const ref ParseTree p) 75 | { 76 | file.write(" -1L) 89 | { 90 | file.write(" open"); 91 | break; 92 | } 93 | } 94 | else 95 | { 96 | bool w; 97 | foreach(detail; Details) 98 | if (indexOf(p.name, detail) > -1L) 99 | { 100 | w = true; 101 | break; 102 | } 103 | if (!w) 104 | file.write(" open"); 105 | } 106 | } 107 | } 108 | 109 | if (p.children.length == 0) 110 | file.write(` class="leaf"`); 111 | file.write(">", p.name, " ", to!string([p.begin, p.end])); 112 | 113 | if (p.children.length == 0 && !p.successful) 114 | { // Failure leaf. 115 | Position pos = position(p); 116 | auto left = pos.index < 10 ? p.input[0 .. pos.index] : p.input[pos.index-10 .. pos.index]; 117 | auto right = pos.index + 10 < p.input.length ? p.input[pos.index .. pos.index + 10] : p.input[pos.index .. $]; 118 | file.write(" failure at line ", to!string(pos.line), ", col ", to!string(pos.col), ", "); 119 | if (left.length > 0) 120 | file.write("after ", left.stringified, " "); 121 | file.write("expected "); 122 | if (p.matches.length > 0) 123 | file.write(p.matches[$-1].stringified); 124 | else 125 | file.write("NO MATCH"); 126 | file.write(`, but got `, right.stringified, "\n"); 127 | } 128 | else 129 | { 130 | file.write(" = 0 ? p.begin + firstNewLine : p.end]; 135 | if (firstLine.length > 0) 136 | file.write(">", firstLine, "
", p.input[p.begin .. p.end].stripReturns, "
"); 137 | else // Insert the return-symbol so the mouse has something to hover over. 138 | file.write(">⏎
⏎", p.input[p.begin .. p.end].stripReturns, "
"); 139 | } 140 | 141 | file.write("
\n"); 142 | foreach (child; p.children) 143 | treeToHTML(child); 144 | file.write("\n"); 145 | } 146 | 147 | treeToHTML(p); 148 | 149 | file.write(` 150 | 151 | 152 | `); 153 | } 154 | 155 | /** 156 | * Writes a parse tree to a html file. 157 | * 158 | * Params: 159 | * e = Defines if the tree is expanded. 160 | * Details = Defines the details, as a list of strings, that are expanded 161 | * when e is equal to `Expand.yes`, and not expanded when e is equal to 162 | * `Expand.invert`. When no details are passed, each node is expanded. 163 | * p = The ParseTree to represent. 164 | * filename = The name of file where tree is written. 165 | */ 166 | void toHTML(Expand e = Expand.no, Details...)(const ref ParseTree p, 167 | string filename) 168 | { 169 | if (filename.endsWith(".html", ".htm") == 0) 170 | filename ~= ".html"; 171 | toHTML!(e, Details)(p, File(filename, "w")); 172 | } 173 | 174 | /* Pegged should probably just read its input in text mode, so no "\r" occur and 175 | * indices into the input are consistent across all platforms. 176 | * https://forum.dlang.org/post/pf3lvo$2804$1@digitalmars.com 177 | */ 178 | string stripReturns(string str) 179 | { 180 | return str.tr("\r", "", "d"); 181 | } 182 | -------------------------------------------------------------------------------- /scripts/core-dump.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -veo pipefail 4 | 5 | for file in /cores/*; do 6 | echo "Core file: $file" 7 | EXECUTABLE_FILE=$(echo "$file" | sed 's/\/cores\///' | sed -E 's/\.[0-9]+$//' | tr '!' '/') 8 | echo "Executable: $EXECUTABLE_FILE" 9 | gdb -c "$file" "$EXECUTABLE_FILE" -ex 'set print pretty on' -ex "thread apply all bt" -ex "set pagination 0" -ex 'info files' -ex 'p $_siginfo._sifields._sigfault.si_addr' -ex 'info locals' -ex 'info frame' -ex 'info args' -ex 'p *sym' -batch 10 | done 11 | -------------------------------------------------------------------------------- /wscript: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import os, shutil, sys, subprocess, tarfile, tempfile 4 | from waflib import Build, Context, Scripting, Utils 5 | 6 | APPNAME = 'libpegged' 7 | VERSION = '1.0' 8 | 9 | TOP = os.curdir 10 | OUT = 'build' 11 | 12 | def options(opt): 13 | opt.load('compiler_d') 14 | 15 | opt.add_option('--lp64', action = 'store', default = 'true', help = 'compile for 64-bit CPUs (true/false)') 16 | opt.add_option('--mode', action = 'store', default = 'debug', help = 'the mode to compile in (debug/release)') 17 | opt.add_option('--valgrind', action = 'store', default = 'false', help = 'use Valgrind for unit tests') 18 | 19 | def configure(conf): 20 | conf.load('compiler_d') 21 | 22 | if conf.options.valgrind != 'true' and conf.options.valgrind != 'false': 23 | conf.fatal('--valgrind must be either true or false.') 24 | 25 | conf.env.VALGRIND = conf.options.valgrind 26 | 27 | def add_option(option, flags = 'DFLAGS'): 28 | if option not in conf.env[flags]: 29 | conf.env.append_value(flags, option) 30 | 31 | if conf.env.COMPILER_D == 'dmd': 32 | add_option('-w') 33 | add_option('-wi') 34 | add_option('-ignore') 35 | add_option('-property') 36 | add_option('-g') 37 | 38 | if conf.options.mode == 'debug': 39 | add_option('-debug') 40 | elif conf.options.mode == 'release': 41 | add_option('-release') 42 | add_option('-O') 43 | add_option('-inline') 44 | else: 45 | conf.fatal('--mode must be either debug or release.') 46 | elif conf.env.COMPILER_D == 'gdc': 47 | add_option('-Wall') 48 | add_option('-fignore-unknown-pragmas') 49 | add_option('-fproperty') 50 | add_option('-g') 51 | add_option('-ggdb') 52 | 53 | if conf.options.mode == 'debug': 54 | add_option('-fdebug') 55 | elif conf.options.mode == 'release': 56 | add_option('-frelease') 57 | add_option('-O3') 58 | else: 59 | conf.fatal('--mode must be either debug or release.') 60 | elif conf.env.COMPILER_D == 'ldc2': 61 | add_option('-w') 62 | add_option('-wi') 63 | add_option('-ignore') 64 | add_option('-property') 65 | add_option('-g') 66 | 67 | if conf.options.mode == 'debug': 68 | add_option('-d-debug') 69 | elif conf.options.mode == 'release': 70 | add_option('-release') 71 | add_option('-O3') 72 | add_option('--enable-inlining') 73 | else: 74 | conf.fatal('--mode must be either debug or release.') 75 | else: 76 | conf.fatal('Unsupported D compiler.') 77 | 78 | if conf.options.lp64 == 'true': 79 | add_option('-m64') 80 | conf.env.append_value('LINKFLAGS', '-m64') 81 | elif conf.options.lp64 == 'false': 82 | add_option('-m32') 83 | conf.env.append_value('LINKFLAGS', '-m32') 84 | else: 85 | conf.fatal('--lp64 must be either true or false.') 86 | 87 | def build(bld): 88 | bld.stlib(source = bld.path.ant_glob([os.path.join('pegged', '*.d'), 89 | os.path.join('pegged', 'dynamic', '*.d')]), 90 | target = 'pegged', 91 | includes = [TOP]) 92 | 93 | if bld.env.COMPILER_D == 'dmd': 94 | unittest = '-unittest' 95 | elif bld.env.COMPILER_D == 'gdc': 96 | unittest = '-funittest' 97 | elif bld.env.COMPILER_D == 'ldc2': 98 | unittest = '-unittest' 99 | else: 100 | bld.fatal('Unsupported D compiler.') 101 | 102 | bld.program(source = bld.path.ant_glob(os.path.join('pegged', 'test', '*.d')), 103 | target = 'pegged.tester', 104 | use = ['pegged'], 105 | includes = [TOP], 106 | install_path = None, 107 | dflags = unittest) 108 | 109 | def _run_shell(dir, ctx, args): 110 | cwd = os.getcwd() 111 | os.chdir(dir) 112 | 113 | code = subprocess.Popen(args, shell = True).wait() 114 | 115 | if code != 0: 116 | ctx.fatal(str(args) + ' exited with: ' + str(code)) 117 | 118 | os.chdir(cwd) 119 | 120 | def unittest(ctx): 121 | '''runs the unit test suite''' 122 | 123 | if ctx.env.VALGRIND == 'true': 124 | cmd = 'valgrind' 125 | cmd += ' --suppressions=' + os.path.join(os.pardir, 'pegged.valgrind') 126 | cmd += ' --leak-check=full' 127 | cmd += ' --track-fds=yes' 128 | cmd += ' --num-callers=50' 129 | cmd += ' --show-reachable=yes' 130 | cmd += ' --undef-value-errors=no' 131 | cmd += ' --error-exitcode=1' 132 | cmd += ' --gen-suppressions=all' 133 | cmd += ' ' + os.path.join(os.curdir, 'pegged.tester') 134 | 135 | _run_shell(OUT, ctx, cmd) 136 | else: 137 | _run_shell(OUT, ctx, './pegged.tester') 138 | 139 | class UnitTestContext(Build.BuildContext): 140 | cmd = 'unittest' 141 | fun = 'unittest' 142 | 143 | def dist(dst): 144 | '''makes a tarball for redistributing the sources''' 145 | 146 | with open('.gitignore', 'r') as f: 147 | dst.excl = ' '.join(l.strip() for l in f if l.strip()) 148 | dst.excl += ' .git/* .gitignore .arcconfig' 149 | 150 | class DistCheckContext(Scripting.Dist): 151 | cmd = 'distcheck' 152 | fun = 'distcheck' 153 | 154 | def execute(self): 155 | self.recurse([os.path.dirname(Context.g_module.root_path)]) 156 | self.archive() 157 | self.check() 158 | 159 | def check(self): 160 | with tarfile.open(self.get_arch_name()) as t: 161 | for x in t: 162 | t.extract(x) 163 | 164 | instdir = tempfile.mkdtemp('.inst', self.get_base_name()) 165 | cfg = [x for x in sys.argv if x.startswith('-')] 166 | 167 | ret = Utils.subprocess.Popen([sys.argv[0], 168 | 'configure', 169 | 'install', 170 | 'uninstall', 171 | '--destdir=' + instdir] + cfg, cwd = self.get_base_name()).wait() 172 | 173 | if ret: 174 | self.fatal('distcheck failed with code {0}'.format(ret)) 175 | 176 | if os.path.exists(instdir): 177 | self.fatal('distcheck succeeded, but files were left in {0}'.format(instdir)) 178 | 179 | shutil.rmtree(self.get_base_name()) 180 | 181 | def distcheck(ctx): 182 | '''checks if the project compiles (tarball from 'dist')''' 183 | 184 | pass 185 | 186 | class PackageContext(Build.InstallContext): 187 | cmd = 'package' 188 | fun = 'build' 189 | 190 | def init_dirs(self, *k, **kw): 191 | super(PackageContext, self).init_dirs(*k, **kw) 192 | 193 | self.tmp = self.bldnode.make_node('package_tmp_dir') 194 | 195 | try: 196 | shutil.rmtree(self.tmp.abspath()) 197 | except: 198 | pass 199 | if os.path.exists(self.tmp.abspath()): 200 | self.fatal('Could not remove the temporary directory {0}'.format(self.tmp)) 201 | 202 | self.tmp.mkdir() 203 | self.options.destdir = self.tmp.abspath() 204 | 205 | def execute(self, *k, **kw): 206 | back = self.options.destdir 207 | 208 | try: 209 | super(PackageContext, self).execute(*k, **kw) 210 | finally: 211 | self.options.destdir = back 212 | 213 | files = self.tmp.ant_glob('**') 214 | 215 | appname = getattr(Context.g_module, Context.APPNAME, 'noname') 216 | version = getattr(Context.g_module, Context.VERSION, '1.0') 217 | 218 | ctx = Scripting.Dist() 219 | ctx.arch_name = '{0}-{1}-bin.tar.bz2'.format(appname, version) 220 | ctx.files = files 221 | ctx.tar_prefix = '' 222 | ctx.base_path = self.tmp 223 | ctx.archive() 224 | 225 | shutil.rmtree(self.tmp.abspath()) 226 | 227 | def package(ctx): 228 | '''packages built binaries into a tarball''' 229 | 230 | pass 231 | --------------------------------------------------------------------------------