├── .codecov.yml
├── .editorconfig
├── .github
└── workflows
│ ├── default.yml
│ ├── deploy-pages.yml
│ ├── pr_info_intro.yml
│ ├── pr_info_post.yml
│ └── pr_info_untrusted.yml
├── .gitignore
├── .gitmodules
├── DGrammar
├── .gitignore
├── begin.txt
├── end.txt
└── generate_html_from_libdparse.sh
├── LICENSE_1_0.txt
├── README.md
├── ci
├── summary_comment.sh
└── summary_comment_diff.sh
├── doc-src
├── index.ddoc
└── macros.ddoc
├── dub.json
├── img
├── logo.kra
└── logo.png
├── macros.ddoc
├── meson.build
├── src
├── dparse
│ ├── ast.d
│ ├── astprinter.d
│ ├── entities.d
│ ├── formatter.d
│ ├── lexer.d
│ ├── parser.d
│ ├── rollback_allocator.d
│ ├── stack_buffer.d
│ ├── strings.d
│ └── trivia.d
└── std
│ └── experimental
│ └── lexer.d
└── test
├── ast_checks
├── assert_args.d
├── assert_args.txt
├── errorRecovery.d
├── errorRecovery.txt
├── file1.d
├── file1.txt
├── foreach.d
├── foreach.txt
├── interpolated_string.d
├── interpolated_string.txt
├── issue428.d
├── issue428.txt
├── issue471.d
├── issue471.txt
├── moduleDec4.d
├── moduleDec4.txt
├── named_arguments.d
├── named_arguments.txt
├── oneLineFunctionDoc.d
├── oneLineFunctionDoc.txt
├── scope_exit.d
├── scope_exit.txt
├── shortenedFunction.d
├── shortenedFunction.txt
├── switch_condition.d
├── switch_condition.txt
├── throw_expressions.d
├── throw_expressions.txt
├── while_condition.d
└── while_condition.txt
├── fail_files
├── aliases.d
├── asm-gcc.d
├── bad_asm.d
├── bad_enum_1.d
├── bad_enum_2.d
├── bad_enum_3.d
├── bad_enums.d
├── bad_parens.d
├── better_block_leave.d
├── contracts.d
├── dcd_tricks.d
├── ifConditions.d
├── incompleteStatement198_0.d
├── incompleteStatement198_1.d
├── incompleteStatement198_2.d
├── incompleteStatement198_3.d
├── incompleteStatement198_4.d
├── incompleteStatement198_5.d
├── incompleteStatement198_6.d
├── incompleteStatement198_7.d
├── issue0078.d
├── issue0158.d
├── issue0171.d
├── issue0176.d
├── issue0179.d
├── issue0227.d
├── issue095.d
├── issue245.d
├── issue459.d
├── killer.d
├── killer2.d
├── misc_coverage.d
├── pragma_exp_bound.d
├── shortenedMethod.d
├── sillyparse.d
├── throwattribute.d
├── varargs-attributes.d
└── with_better_dcd.d
├── fuzzer.d
├── fuzzer.sh
├── pass_files
├── ae.d
├── alias_assign.d
├── aliases.d
├── asm-gcc.d
├── asm.d
├── attributes.d
├── auto_declarations.d
├── bitfields.d
├── body_as_ident.d
├── casts.d
├── classes.d
├── compiler_2_104_0.d
├── constructors_destructors.d
├── crazy1.d
├── declarations.d
├── dip1000.d
├── dip25.d
├── do_body.d
├── enums.d
├── exceptions.d
├── expressions.d
├── function_aliases.d
├── function_declarations.d
├── function_literals.d
├── helloworld.d
├── ifConditions.d
├── imports.d
├── innerclass.d
├── interfaces.d
├── issue00114.d
├── issue0042.d
├── issue0047.d
├── issue0067.d
├── issue0070.d
├── issue0095.d
├── issue0106.d
├── issue0156.d
├── issue0158.d
├── issue0291.d
├── issue0413.d
├── lexical.d
├── linkageAttributes.d
├── misc_coverage.d
├── mixin_types.d
├── moduleDec1.d
├── moduleDec2.d
├── moduleDec3.d
├── moduleDec4.d
├── much_recursion.d
├── named_arguments.d
├── pragmas.d
├── ptrntab.d
├── shortenedMethods.d
├── single_line_with_decl.d
├── statements.d
├── structs.d
├── switch_condition_assignment.d
├── templates.d
├── test8898.d
├── throwattribute.d
├── unions.d
├── varargs-attributes.d
└── while_condition_assignment.d
├── run_tests.sh
├── tester.d
└── watcher.sh
/.codecov.yml:
--------------------------------------------------------------------------------
1 | # Documentation: https://github.com/codecov/support/wiki/codecov.yml
2 | codecov:
3 | coverage:
4 | precision: 3
5 | round: down
6 |
7 | status:
8 | # Learn more at https://codecov.io/docs#yaml_default_commit_status
9 | project: true
10 | patch: true
11 | changes: false
12 |
13 | comment: false
14 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | [*]
2 | end_of_line = lf
3 | insert_final_newline = true
4 | indent_size = 4
5 | tab_width = 8
6 | trim_trailing_whitespace = true
7 | indent_style = space
8 |
--------------------------------------------------------------------------------
/.github/workflows/default.yml:
--------------------------------------------------------------------------------
1 | name: run-tests
2 |
3 | on:
4 | pull_request:
5 |
6 | push:
7 | branches:
8 | - master
9 |
10 | jobs:
11 | main:
12 | name: Run all tests
13 | strategy:
14 | fail-fast: false
15 | matrix:
16 | include:
17 | - compiler: dmd-latest
18 | dmd: dmd
19 |
20 | - compiler: ldc-latest
21 | dmd: ldmd2
22 |
23 | - compiler: gdc-latest
24 | dmd: gdmd
25 |
26 | runs-on: ubuntu-latest
27 |
28 | steps:
29 | # Clone repo + submodules
30 | - name: Checkout repo
31 | uses: actions/checkout@v2
32 | with:
33 | submodules: 'recursive'
34 |
35 | # Update packages and install test dependencies
36 | - name: Install required dependencies
37 | run: |
38 | sudo apt-get update
39 | sudo apt-get install libxml2-utils -y
40 |
41 | # Install the host compiler (DMD or LDC)
42 | - name: Install ${{ matrix.compiler }}
43 | if: ${{ matrix.compiler != 'gdc-latest' }}
44 | uses: dlang-community/setup-dlang@v1
45 | with:
46 | compiler: ${{ matrix.compiler }}
47 |
48 | # GDC not yet supported by setup-dlang
49 | - name: Install GDC
50 | if: ${{ matrix.compiler == 'gdc-latest' }}
51 | run: |
52 | sudo apt-get install gdc-12 gdmd -y
53 | # hack:
54 | sudo rm /usr/bin/gdc
55 | sudo ln -s /usr/bin/gdc-12 /usr/bin/gdc
56 | gdc --version
57 |
58 | # Execute all other tests (parsing, XPath, ...)
59 | - name: Run run_tests.sh
60 | env:
61 | DMD: ${{ matrix.dmd }}
62 | shell: bash
63 | working-directory: test
64 | run: source run_tests.sh
65 |
66 | # Upload coverage reports to CodeCov
67 | - uses: codecov/codecov-action@v2
68 | if: ${{ matrix.compiler == 'ldc-latest' }}
69 | with:
70 | directory: test/coverage
71 |
--------------------------------------------------------------------------------
/.github/workflows/deploy-pages.yml:
--------------------------------------------------------------------------------
1 | name: deploy-pages
2 |
3 | on:
4 | push:
5 | branches:
6 | - deploy-pages
7 | - master
8 |
9 | jobs:
10 | main:
11 | name: Deploy to ghpages
12 |
13 | runs-on: ubuntu-latest
14 |
15 | steps:
16 | # Clone repo + submodules
17 | - name: Checkout source repo
18 | uses: actions/checkout@v3
19 | with:
20 | submodules: 'recursive'
21 | path: main
22 |
23 | - name: Checkout ghpages repo
24 | uses: actions/checkout@v3
25 | with:
26 | submodules: 'recursive'
27 | ref: gh-pages
28 | path: gh-pages
29 |
30 | - name: Install DMD
31 | uses: dlang-community/setup-dlang@v1
32 | with:
33 | compiler: dmd-latest
34 |
35 | - name: Build HTML
36 | shell: bash
37 | run: |
38 | cd main
39 | dub upgrade
40 | dub build -b ddox -v
41 | ./DGrammar/generate_html_from_libdparse.sh
42 | cp ./DGrammar/grammar.html docs/grammar.html
43 | cp -r docs/* ../gh-pages
44 | cd ../gh-pages
45 |
46 | - uses: stefanzweifel/git-auto-commit-action@v4
47 | with:
48 | branch: gh-pages
49 | repository: gh-pages
50 |
--------------------------------------------------------------------------------
/.github/workflows/pr_info_intro.yml:
--------------------------------------------------------------------------------
1 | name: PR Info (pre-comment)
2 |
3 | on:
4 | # NOTE: high probability for security vulnerabilities if doing ANYTHING in
5 | # this file other than commenting something!
6 | pull_request_target:
7 | branches:
8 | - master
9 |
10 | jobs:
11 | intro_comment:
12 | name: Make intro comment
13 | runs-on: ubuntu-20.04
14 | steps:
15 | - name: 'Prepare sticky comment'
16 | # commit of v2.5.0
17 | # same one used again at the bottom of the file to update the comment.
18 | uses: marocchino/sticky-pull-request-comment@3d60a5b2dae89d44e0c6ddc69dd7536aec2071cd
19 | with:
20 | message: |
21 | Thanks for your Pull Request and making D better!
22 |
23 | This comment will automatically be updated to summarize some statistics in a few minutes.
24 | only_create: true
25 |
--------------------------------------------------------------------------------
/.github/workflows/pr_info_post.yml:
--------------------------------------------------------------------------------
1 | name: PR Info (comment)
2 |
3 | on:
4 | workflow_run:
5 | workflows: ["PR Info"]
6 | types:
7 | - completed
8 |
9 | jobs:
10 | comment:
11 | name: PR Info
12 | runs-on: ubuntu-20.04
13 | if: >
14 | github.event.workflow_run.event == 'pull_request' &&
15 | github.event.workflow_run.conclusion == 'success'
16 | steps:
17 | # from https://securitylab.github.com/research/github-actions-preventing-pwn-requests/
18 | - name: 'Download artifact'
19 | uses: actions/github-script@v3.1.0
20 | with:
21 | script: |
22 | var artifacts = await github.actions.listWorkflowRunArtifacts({
23 | owner: context.repo.owner,
24 | repo: context.repo.repo,
25 | run_id: ${{github.event.workflow_run.id }},
26 | });
27 | var matchArtifact = artifacts.data.artifacts.filter((artifact) => {
28 | return artifact.name == "pr"
29 | })[0];
30 | var download = await github.actions.downloadArtifact({
31 | owner: context.repo.owner,
32 | repo: context.repo.repo,
33 | artifact_id: matchArtifact.id,
34 | archive_format: 'zip',
35 | });
36 | var fs = require('fs');
37 | fs.writeFileSync('${{github.workspace}}/pr.zip', Buffer.from(download.data));
38 | - run: unzip pr.zip
39 |
40 | - name: Set variable
41 | run: |
42 | PR_ID=$(cat ./NR)
43 | echo "PR_ID=$PR_ID" >> $GITHUB_ENV
44 |
45 | - name: Update GitHub comment
46 | uses: marocchino/sticky-pull-request-comment@3d60a5b2dae89d44e0c6ddc69dd7536aec2071cd
47 | with:
48 | path: ./comment.txt
49 | number: ${{ env.PR_ID }}
50 |
--------------------------------------------------------------------------------
/.github/workflows/pr_info_untrusted.yml:
--------------------------------------------------------------------------------
1 | name: PR Info
2 |
3 | # This workflow builds the whole project once and:
4 | # - comments build deprecations/warnings (highlighting new ones since last tested PR)
5 |
6 | on:
7 | pull_request:
8 | branches:
9 | - master
10 |
11 | jobs:
12 | pr_info:
13 | name: PR Info
14 | runs-on: ubuntu-latest
15 | steps:
16 | # Compiler to test with
17 | - name: Prepare compiler
18 | uses: dlang-community/setup-dlang@v1
19 | with:
20 | compiler: dmd-latest
21 |
22 | - name: Prepare compiler
23 | uses: dlang-community/setup-dlang@v1
24 | with:
25 | compiler: ldc-latest
26 |
27 | - name: Checkout
28 | uses: actions/checkout@v3
29 | with:
30 | fetch-depth: 0
31 |
32 | - name: Checkout old stuff, with new comment script
33 | run: |
34 | git checkout ${{ github.base_ref }}
35 | git checkout ${{ github.sha }} -- ./ci/summary_comment.sh ./ci/summary_comment_diff.sh
36 |
37 | # first dump old info
38 |
39 | - name: Check pre-PR status
40 | run: ./ci/summary_comment.sh | tee ../OLD_OUTPUT.txt
41 |
42 | - name: Checkout PR target
43 | run: |
44 | git checkout ${{ github.sha }}
45 | git clean -fd
46 | git reset --hard
47 |
48 | - name: Evaluate PR
49 | run: ./ci/summary_comment.sh | tee ../NEW_OUTPUT.txt
50 |
51 | - name: Generate comment
52 | run: ./ci/summary_comment_diff.sh ../OLD_OUTPUT.txt ../NEW_OUTPUT.txt | tee comment.txt
53 |
54 | - name: Prepare comment for upload
55 | run: |
56 | mkdir -p ./pr
57 | mv comment.txt pr
58 | echo ${{ github.event.number }} > ./pr/NR
59 |
60 | - name: upload comment to high-trust action making the comment
61 | uses: actions/upload-artifact@v4
62 | with:
63 | name: pr
64 | path: pr/
65 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .dub
2 | docs.json
3 | __dummy.html
4 | *.[oa]
5 | *.obj
6 | test/coverage/*
7 | test/tester
8 | test/fuzzer
9 | test/output.txt
10 | test/tokens-newlines.txt
11 | test/tokens.txt
12 | test/unittests
13 | dub.selections.json
14 | *.lst
15 |
16 | # Perf reports
17 | perf.data
18 | perf.data.old
19 |
20 | # Valgrind reports
21 | callgrind.*
22 | massif.*
23 |
24 | # D profiling tools
25 | profilegc.log
26 |
27 | # GDB temp files
28 | .gdb_history
29 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dlang-community/libdparse/f8a6c28589aae180532fb460a1b22e92a0978292/.gitmodules
--------------------------------------------------------------------------------
/DGrammar/.gitignore:
--------------------------------------------------------------------------------
1 | *.html
2 | pup*
3 |
--------------------------------------------------------------------------------
/DGrammar/begin.txt:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | D Grammar
6 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/DGrammar/end.txt:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/DGrammar/generate_html_from_libdparse.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -euo pipefail
4 |
5 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
6 | LIBDPARSE_PATH=${DIR}/..
7 | cd $DIR
8 |
9 | dmd -D ${LIBDPARSE_PATH}/src/dparse/parser.d\
10 | -I${LIBDPARSE_PATH}/src\
11 | ${LIBDPARSE_PATH}/macros.ddoc -c -o-
12 |
13 | # install pup (if not existent)
14 | pup=pup
15 | if [[ $(command -v "$pup" 2>&1 > /dev/null || echo 131) -eq 131 ]] ; then
16 | if [ -f $DIR/pup ] ; then
17 | pup="./pup"
18 | else
19 | version="v0.4.0"
20 | shasum="c1706d13aa04f3665b4a3a73958870268b41c672"
21 | out="pup_${version}_linux_amd64.zip"
22 | wget "https://github.com/ericchiang/pup/releases/download/${version}/pup_${version}_linux_amd64.zip" -O "${out}"
23 | echo "${shasum} ${out}" | sha1sum -c -
24 | unzip pup_${version}_linux_amd64.zip
25 | pup="./pup"
26 | fi
27 | fi
28 |
29 | cat begin.txt > grammar.html
30 | cat parser.html | "$pup" 'pre[class="grammar"]' --pre >> grammar.html
31 | cat end.txt >> grammar.html
32 |
--------------------------------------------------------------------------------
/LICENSE_1_0.txt:
--------------------------------------------------------------------------------
1 | Boost Software License - Version 1.0 - August 17th, 2003
2 |
3 | Permission is hereby granted, free of charge, to any person or organization
4 | obtaining a copy of the software and accompanying documentation covered by
5 | this license (the "Software") to use, reproduce, display, distribute,
6 | execute, and transmit the Software, and to prepare derivative works of the
7 | Software, and to permit third-parties to whom the Software is furnished to
8 | do so, all subject to the following:
9 |
10 | The copyright notices in the Software and this entire statement, including
11 | the above license grant, this restriction and the following disclaimer,
12 | must be included in all copies of the Software, in whole or in part, and
13 | all derivative works of the Software, unless such copies or derivative
14 | works are solely in the form of machine-executable object code generated by
15 | a source language processor.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
20 | SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
21 | FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 | DEALINGS IN THE SOFTWARE.
24 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | libdparse
2 | =========
3 | Library for lexing and parsing D source code.
4 |
5 | # Documentation
6 |
7 | Online documentation is available [here](http://libdparse.dlang.io).
8 |
9 | A HTML version of libdparse's grammar is also [automatically generated](http://libdparse.dlang.io/grammar.html).
10 |
11 | # Testing
12 | [](https://travis-ci.org/dlang-community/libdparse)
13 |
14 | Tests are present in the test directory. To run them execute the run\_tests.sh
15 | script. Running the tests on Windows is not currently supported.
16 |
17 | # Differences with the official grammar
18 | * [Static array initialization syntax](http://dlang.org/arrays.html#static-init-static). Due to ambiguities they are supported when the expression that gives the elements indexes is not an array. In the opposite case they are parsed as associative array literals.
19 |
20 | # Unsupported Syntax
21 | * [Class allocators](http://dlang.org/class.html#allocators). These are deprecated in D2.
22 | * [Class deallocators](http://dlang.org/class.html#deallocators). These are deprecated in D2.
23 |
24 | # Example
25 |
26 | ```d
27 | /+dub.sdl:
28 | dependency "libdparse" version="~>0.7"
29 | +/
30 | import dparse.ast;
31 | import std.stdio, std.range;
32 |
33 | class TestVisitor : ASTVisitor
34 | {
35 | alias visit = ASTVisitor.visit;
36 | int indentLevel;
37 |
38 | override void visit(const FunctionDeclaration decl)
39 | {
40 | writeln(' '.repeat(indentLevel * 4), decl.name.text);
41 | indentLevel++;
42 | scope (exit) indentLevel--;
43 | decl.accept(this);
44 | }
45 | }
46 |
47 | void main()
48 | {
49 | import dparse.lexer;
50 | import dparse.parser : parseModule;
51 | import dparse.rollback_allocator : RollbackAllocator;
52 |
53 | auto sourceCode = q{
54 | void foo() @safe {
55 | void bar();
56 | }
57 | };
58 | LexerConfig config;
59 | auto cache = StringCache(StringCache.defaultBucketCount);
60 | auto tokens = getTokensForParser(sourceCode, config, &cache);
61 |
62 | RollbackAllocator rba;
63 | auto m = parseModule(tokens, "test.d", &rba);
64 | auto visitor = new TestVisitor();
65 | visitor.visit(m);
66 | }
67 | ```
68 | [](https://run.dlang.io/is/qZsGDD)
69 |
--------------------------------------------------------------------------------
/ci/summary_comment.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | set -u
4 |
5 | # Output from this script is piped to a file by CI, being run from before a
6 | # change has been made and after a change has been made. Then both outputs are
7 | # compared using summary_comment_diff.sh
8 |
9 | # cd to git folder, just in case this is manually run:
10 | ROOT_DIR="$( cd "$(dirname "${BASH_SOURCE[0]}")/../" && pwd )"
11 | cd ${ROOT_DIR}
12 |
13 | dub --version
14 | ldc2 --version
15 |
16 | # fetch missing packages before timing
17 | dub upgrade --missing-only
18 |
19 | start=`date +%s`
20 | dub build --build=release --force 2>&1 || echo "LIB BUILD FAILED"
21 | end=`date +%s`
22 | build_time=$( echo "$end - $start" | bc -l )
23 |
24 | strip libdparse.a
25 |
26 | echo "STAT:------ libdparse statistics ------"
27 | echo "STAT:"
28 | echo "STAT:statistics (-before, +after)"
29 | echo "STAT:library size=$(wc -c libdparse.a)"
30 | echo "STAT:rough build time=${build_time}s"
31 | echo "STAT:"
32 |
33 | cleanup() {
34 | rm -rf "$ROOT_DIR/DCD"
35 | }
36 | trap cleanup EXIT
37 |
38 | git clone https://github.com/dlang-community/DCD.git
39 | cd DCD
40 | echo "STAT:"
41 | echo "STAT:------ DCD statistics ------"
42 | echo "STAT:"
43 |
44 | sed -E -i 's/"libdparse":\s*"[^"]+"/"libdparse": {"path":".."}/' dub.json
45 | cat dub.json
46 | sed -E -i 's/"libdparse":\s*"[^"]+"/"libdparse": {"path":".."}/' dub.selections.json
47 | cat dub.selections.json
48 |
49 | ./ci/summary_comment.sh 2>&1 | grep -E "^STAT:|DCD BUILD FAILED|unix:tc|\d+ tests passed and \d+ failed|No such file|[Ee]rror"
50 |
--------------------------------------------------------------------------------
/ci/summary_comment_diff.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | set -u
4 |
5 | EMPTY=1
6 |
7 | ADDED=$(diff --new-line-format='%L' --old-line-format='' --unchanged-line-format='' "$1" "$2")
8 | REMOVED=$(diff --new-line-format='' --old-line-format='%L' --unchanged-line-format='' "$1" "$2")
9 | TOTAL=$(cat "$2")
10 |
11 | STATS_OLD=$(grep -E '^STAT:' "$1" | sed -E 's/^STAT://')
12 | STATS_NEW=$(grep -E '^STAT:' "$2" | sed -E 's/^STAT://')
13 |
14 | STATS_DIFFED=$(diff --new-line-format='+%L' --old-line-format='-%L' --unchanged-line-format=' %L' <(echo "$STATS_OLD") <(echo "$STATS_NEW"))
15 |
16 | ADDED_DEPRECATIONS=$(grep -Pi '\b(deprecation|deprecated)\b' <<< "$ADDED")
17 | REMOVED_DEPRECATIONS=$(grep -Pi '\b(deprecation|deprecated)\b' <<< "$REMOVED")
18 | ADDED_WARNINGS=$(grep -Pi '\b(warn|warning)\b' <<< "$ADDED")
19 | REMOVED_WARNINGS=$(grep -Pi '\b(warn|warning)\b' <<< "$REMOVED")
20 |
21 | DEPRECATION_COUNT=$(grep -Pi '\b(deprecation|deprecated)\b' <<< "$TOTAL" | wc -l)
22 | WARNING_COUNT=$(grep -Pi '\b(warn|warning)\b' <<< "$TOTAL" | wc -l)
23 |
24 | if [ -z "$ADDED_DEPRECATIONS" ]; then
25 | # no new deprecations
26 | true
27 | else
28 | echo "⚠️ This PR introduces new deprecations:"
29 | echo
30 | echo '```'
31 | echo "$ADDED_DEPRECATIONS"
32 | echo '```'
33 | echo
34 | EMPTY=0
35 | fi
36 |
37 | if [ -z "$ADDED_WARNINGS" ]; then
38 | # no new deprecations
39 | true
40 | else
41 | echo "⚠️ This PR introduces new warnings:"
42 | echo
43 | echo '```'
44 | echo "$ADDED_WARNINGS"
45 | echo '```'
46 | echo
47 | EMPTY=0
48 | fi
49 |
50 | if grep "LIB BUILD FAILED" <<< "$TOTAL"; then
51 | echo '❌ Basic `dub build` failed! Please check your changes again.'
52 | echo
53 | elif grep "DCD BUILD FAILED" <<< "$TOTAL"; then
54 | echo '❌ `dub build` of DCD has failed with these changes! Please check your changes again.'
55 | echo
56 | else
57 | if [ -z "$REMOVED_DEPRECATIONS" ]; then
58 | # no removed deprecations
59 | true
60 | else
61 | echo "✅ This PR fixes following deprecations:"
62 | echo
63 | echo '```'
64 | echo "$REMOVED_DEPRECATIONS"
65 | echo '```'
66 | echo
67 | EMPTY=0
68 | fi
69 |
70 | if [ -z "$REMOVED_WARNINGS" ]; then
71 | # no removed warnings
72 | true
73 | else
74 | echo "✅ This PR fixes following warnings:"
75 | echo
76 | echo '```'
77 | echo "$REMOVED_WARNINGS"
78 | echo '```'
79 | echo
80 | EMPTY=0
81 | fi
82 |
83 | if [ $EMPTY == 1 ]; then
84 | echo "✅ PR OK, no changes in deprecations or warnings"
85 | echo
86 | fi
87 |
88 | echo "Total deprecations: $DEPRECATION_COUNT"
89 | echo
90 | echo "Total warnings: $WARNING_COUNT"
91 | echo
92 | fi
93 |
94 | if [ -z "$STATS_DIFFED" ]; then
95 | # no statistics?
96 | true
97 | else
98 | echo "Build statistics:"
99 | echo
100 | echo '```diff'
101 | echo "$STATS_DIFFED"
102 | echo '```'
103 | echo
104 | fi
105 |
106 | echo ''
107 | echo
108 | echo 'Full build output
'
109 | echo
110 | echo '```'
111 | echo "$TOTAL"
112 | echo '```'
113 | echo
114 | echo ' '
115 |
--------------------------------------------------------------------------------
/doc-src/index.ddoc:
--------------------------------------------------------------------------------
1 | $(B libdparse documentation)
2 |
3 | Documentation for individual modules is available through the links on the left.
4 |
--------------------------------------------------------------------------------
/doc-src/macros.ddoc:
--------------------------------------------------------------------------------
1 | GRAMMAR = $0
2 | RULEDEF = $0
3 | RULE = $0
4 | LITERAL = $0
5 | LREF = $0
6 | D_KEYWORD = $(B $0)
7 |
--------------------------------------------------------------------------------
/dub.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "libdparse",
3 | "targetName": "dparse",
4 | "targetType": "library",
5 | "description": "Library for lexing and parsing D source code",
6 | "license": "BSL-1.0",
7 | "-ddoxFilterArgs": [
8 | "--unittest-examples",
9 | "--min-protection=Protected"
10 | ],
11 | "-ddoxTool": "scod"
12 | }
13 |
--------------------------------------------------------------------------------
/img/logo.kra:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dlang-community/libdparse/f8a6c28589aae180532fb460a1b22e92a0978292/img/logo.kra
--------------------------------------------------------------------------------
/img/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dlang-community/libdparse/f8a6c28589aae180532fb460a1b22e92a0978292/img/logo.png
--------------------------------------------------------------------------------
/macros.ddoc:
--------------------------------------------------------------------------------
1 | GRAMMAR = $0
2 | RULEDEF = $(B $(DDOC_ANCHOR $0) $0)
3 | RULE = $(LINK2 #$0, $(B $0))
4 | LITERAL = $(D_STRING $(I $0))
5 |
--------------------------------------------------------------------------------
/meson.build:
--------------------------------------------------------------------------------
1 | project('dparse', 'd',
2 | meson_version: '>=0.44',
3 | license: 'BSL-1.0',
4 | version: '0.10.4'
5 | )
6 |
7 | project_soversion = '0'
8 |
9 | pkgc = import('pkgconfig')
10 |
11 | #
12 | # Sources
13 | #
14 | dparse_src = [
15 | 'src/dparse/ast.d',
16 | 'src/dparse/entities.d',
17 | 'src/dparse/formatter.d',
18 | 'src/dparse/lexer.d',
19 | 'src/dparse/parser.d',
20 | 'src/dparse/rollback_allocator.d',
21 | 'src/dparse/stack_buffer.d',
22 | 'src/dparse/trivia.d',
23 | 'src/std/experimental/lexer.d',
24 | ]
25 |
26 | src_dir = include_directories('src/')
27 |
28 | #
29 | # Targets
30 | #
31 | dparse_lib = library('dparse',
32 | [dparse_src],
33 | include_directories: [src_dir],
34 | install: true,
35 | version: meson.project_version(),
36 | soversion: project_soversion
37 | )
38 |
39 | pkgc.generate(name: 'dparse',
40 | libraries: [dparse_lib],
41 | subdirs: 'd/dparse',
42 | version: meson.project_version(),
43 | description: 'Library for lexing and parsing D source code.'
44 | )
45 |
46 | # for use by others which embed this as subproject
47 | dparse_dep = declare_dependency(
48 | link_with: [dparse_lib],
49 | include_directories: [src_dir]
50 | )
51 |
52 | #
53 | # Tests
54 | #
55 | if meson.get_compiler('d').get_id() == 'llvm'
56 | extra_args = ['-main', '-link-defaultlib-shared']
57 | else
58 | extra_args = ['-main']
59 | endif
60 |
61 | dparse_test_exe = executable('test_dparse',
62 | [dparse_src],
63 | include_directories: [src_dir],
64 | d_unittest: true,
65 | link_args: extra_args,
66 | )
67 | test('test_dparse', dparse_test_exe)
68 |
69 | #
70 | # Install
71 | #
72 | install_subdir('src/dparse/', install_dir: 'include/d/dparse/')
73 | install_subdir('src/std/', install_dir: 'include/d/dparse/')
74 |
--------------------------------------------------------------------------------
/src/dparse/rollback_allocator.d:
--------------------------------------------------------------------------------
1 | module dparse.rollback_allocator;
2 |
3 | import core.memory : GC;
4 |
5 | //version = debug_rollback_allocator;
6 |
7 | /**
8 | * Pointer-bump allocator with rollback functionality.
9 | */
10 | struct RollbackAllocator
11 | {
12 | public:
13 |
14 | // must be multiple of 8
15 | enum memoryAlignment = 16u;
16 |
17 | @disable this(this);
18 |
19 | ~this()
20 | {
21 | while (first !is null)
22 | deallocateNode();
23 | }
24 |
25 | /**
26 | * Allocates `size` bytes of memory.
27 | */
28 | void[] allocate(const size_t size)
29 | out (arr)
30 | {
31 | assert(arr.length == size);
32 | }
33 | do
34 | {
35 | import std.algorithm.comparison : min;
36 |
37 | if (first is null)
38 | allocateNode(size);
39 |
40 | // Memory align the size
41 | immutable size_t s = size & ~(cast(size_t) memoryAlignment - 1);
42 | immutable size_t s2 = s == size ? size : s + memoryAlignment;
43 |
44 | size_t fu = first.used;
45 | size_t end = fu + s2;
46 | //assert(end >= fu + size);
47 | //assert(end % 8 == 0);
48 | if (end > first.mem.length)
49 | {
50 | allocateNode(size);
51 | fu = first.used;
52 | end = fu + s2;
53 | }
54 | //assert((cast(size_t) first.mem.ptr) % 8 == 0);
55 | //assert(((cast(size_t) first.mem.ptr) + end) % 8 == 0);
56 | void[] m = first.mem[fu .. fu + size];
57 | // alignment can make our size here bigger than what we actually have, so we clamp down to the used amount
58 | first.used = min(end, first.mem.length);
59 | return m;
60 | }
61 |
62 | /**
63 | * Rolls back the allocator to the given checkpoint.
64 | */
65 | void rollback(size_t point)
66 | {
67 | import std.stdio : stderr;
68 |
69 | if (point == 0)
70 | {
71 | while (first)
72 | deallocateNode();
73 | return;
74 | }
75 | else
76 | assert(contains(point), "Attepmted to roll back to a point not in the allocator.");
77 |
78 | // while `first !is null` is always going to pass after the contains(point) check, it may no longer pass after deallocateNode
79 | while (first !is null && !first.contains(point))
80 | deallocateNode();
81 | assert(first !is null);
82 |
83 | immutable begin = point - cast(size_t) first.mem.ptr;
84 | version (debug_rollback_allocator)
85 | (cast(ubyte[]) first.mem)[begin .. $] = 0;
86 | first.used = begin;
87 | assert(cast(size_t) first.mem.ptr + first.used == point);
88 | }
89 |
90 | /**
91 | * Get a checkpoint for the allocator.
92 | */
93 | size_t setCheckpoint() const nothrow @nogc
94 | {
95 | assert(first is null || first.used <= first.mem.length);
96 | return first is null ? 0 : cast(size_t) first.mem.ptr + first.used;
97 | }
98 |
99 | /**
100 | * Allocates a T and returns a pointer to it
101 | */
102 | auto make(T, Args...)(auto ref Args args)
103 | {
104 | import std.algorithm.comparison : max;
105 | import std.experimental.allocator : stateSize;
106 | import std.conv : emplace;
107 |
108 | void[] mem = allocate(max(stateSize!T, 1));
109 | if (mem.ptr is null)
110 | return null;
111 | static if (is(T == class))
112 | return emplace!T(mem, args);
113 | else
114 | return emplace(cast(T*) mem.ptr, args);
115 | }
116 |
117 | private:
118 |
119 | // Used for debugging
120 | bool contains(size_t point) const
121 | {
122 | for (const(Node)* n = first; n !is null; n = n.next)
123 | if (n.contains(point))
124 | return true;
125 | return false;
126 | }
127 |
128 | static struct Node
129 | {
130 | Node* next;
131 | size_t used;
132 | ubyte[] mem;
133 |
134 | bool contains(size_t p) const pure nothrow @nogc @safe
135 | {
136 | return p >= cast(size_t) mem.ptr && p <= cast(size_t) mem.ptr + mem.length;
137 | }
138 | }
139 |
140 | void allocateNode(size_t size)
141 | {
142 | import core.exception : onOutOfMemoryError;
143 | import std.algorithm : max;
144 | import std.conv : emplace;
145 | import std.experimental.allocator.mallocator : AlignedMallocator;
146 |
147 | enum ALLOC_SIZE = 1024 * 8;
148 |
149 | ubyte[] m = cast(ubyte[]) AlignedMallocator.instance.alignedAllocate(max(size + Node.sizeof, ALLOC_SIZE), memoryAlignment);
150 | if (m is null)
151 | onOutOfMemoryError();
152 | GC.addRange(m.ptr, m.length);
153 |
154 | version (debug_rollback_allocator)
155 | m[] = 0;
156 | Node* n = emplace!Node(cast(Node*) m.ptr, first, 0, m[Node.sizeof .. $]);
157 | assert((cast(size_t) n.mem.ptr) % 8 == 0, "The memoriez!");
158 | first = n;
159 | }
160 |
161 | void deallocateNode()
162 | {
163 | assert(first !is null);
164 | import std.experimental.allocator.mallocator : AlignedMallocator;
165 |
166 | Node* next = first.next;
167 | ubyte[] mem = (cast(ubyte*) first)[0 .. Node.sizeof + first.mem.length];
168 | version (debug_rollback_allocator)
169 | mem[] = 0;
170 | GC.removeRange(mem.ptr);
171 | AlignedMallocator.instance.deallocate(mem);
172 | first = next;
173 | }
174 |
175 | Node* first;
176 | }
177 |
178 | @("most simple usage, including memory across multiple pointers")
179 | unittest
180 | {
181 | RollbackAllocator rba;
182 | size_t[10] checkpoint;
183 | foreach (i; 0 .. 10)
184 | {
185 | checkpoint[i] = rba.setCheckpoint();
186 | rba.allocate(4000);
187 | }
188 |
189 | foreach_reverse (i; 0 .. 10)
190 | {
191 | rba.rollback(checkpoint[i]);
192 | }
193 | }
194 |
195 | @("many allocates and frees while leaking memory")
196 | unittest
197 | {
198 | RollbackAllocator rba;
199 | foreach (i; 0 .. 10)
200 | {
201 | size_t[3] checkpoint;
202 | foreach (n; 0 .. 3)
203 | {
204 | checkpoint[n] = rba.setCheckpoint();
205 | rba.allocate(4000);
206 | }
207 | foreach_reverse (n; 1 .. 3)
208 | {
209 | rba.rollback(checkpoint[n]);
210 | }
211 | }
212 | }
213 |
214 | @("allocating overly big")
215 | unittest
216 | {
217 | import std.stdio : stderr;
218 |
219 | RollbackAllocator rba;
220 | size_t[200] checkpoint;
221 | size_t cp;
222 | foreach (i; 1024 * 8 - 100 .. 1024 * 8 + 100)
223 | {
224 | try
225 | {
226 | checkpoint[cp++] = rba.setCheckpoint();
227 | rba.allocate(i);
228 | }
229 | catch (Error e)
230 | {
231 | stderr.writeln("Unittest: crashed in allocating ", i, " bytes");
232 | throw e;
233 | }
234 | }
235 |
236 | foreach_reverse (i, c; checkpoint[0 .. cp])
237 | {
238 | try
239 | {
240 | rba.rollback(c);
241 | }
242 | catch (Error e)
243 | {
244 | stderr.writeln("Unittest: crashed in rolling back ", i, " (address ", c, ")");
245 | throw e;
246 | }
247 | }
248 | }
249 |
--------------------------------------------------------------------------------
/src/dparse/stack_buffer.d:
--------------------------------------------------------------------------------
1 | module dparse.stack_buffer;
2 |
3 | import core.memory : GC;
4 |
5 | import std.traits;
6 |
7 | //version = debug_stack_allocator;
8 |
9 | struct StackBuffer
10 | {
11 | bool put(T)(T t)
12 | {
13 | import std.experimental.allocator.mallocator : Mallocator;
14 |
15 | static if (is(T == class) || isPointer!T)
16 | if (t is null)
17 | return false;
18 |
19 | if (_length == 0 && arr is null)
20 | arr = stackSpace[];
21 |
22 | static if (is(T == class))
23 | static assert(T.sizeof == size_t.sizeof);
24 |
25 | static if (hasIndirections!T)
26 | while (_length % size_t.sizeof != 0)
27 | put(ubyte(1));
28 |
29 | if (arr.ptr != stackSpace.ptr)
30 | {
31 | if (_length + T.sizeof > arr.length)
32 | {
33 | size_t newLength = arr.length << 1;
34 | while (_length + T.sizeof > newLength)
35 | newLength <<= 1;
36 | auto oldPtr = arr.ptr;
37 | Mallocator.instance.reallocate(arr, newLength);
38 | GC.removeRange(oldPtr);
39 | GC.addRange(arr.ptr, arr.length);
40 | version (debug_stack_allocator)
41 | (cast(ubyte[]) arr)[_length .. $] = 0;
42 | }
43 | }
44 | else if (_length + T.sizeof > stackSpace.length)
45 | {
46 | size_t newLength = stackSpace.length << 1;
47 | while (_length + T.sizeof > newLength)
48 | newLength <<= 1;
49 | arr = Mallocator.instance.allocate(newLength);
50 | GC.addRange(arr.ptr, arr.length);
51 | version (debug_stack_allocator)
52 | (cast(ubyte[]) arr)[] = 0;
53 | arr[0 .. stackSpace.length] = stackSpace[];
54 | }
55 | arr[_length .. _length + T.sizeof] = (cast(void*) &t)[0 .. T.sizeof];
56 | _length += T.sizeof;
57 | return true;
58 | }
59 |
60 | ~this()
61 | {
62 | import std.experimental.allocator.mallocator:Mallocator;
63 |
64 | version (debug_stack_allocator)
65 | (cast(ubyte[]) arr)[] = 0;
66 | if (arr.ptr !is stackSpace.ptr)
67 | {
68 | GC.removeRange(arr.ptr);
69 | Mallocator.instance.deallocate(arr);
70 | }
71 | }
72 |
73 | inout(void[]) opSlice() inout pure nothrow @nogc @safe return scope
74 | {
75 | return arr[0 .. _length];
76 | }
77 |
78 | @disable this(this);
79 |
80 | uint length() const pure nothrow @nogc @safe @property
81 | {
82 | return _length;
83 | }
84 |
85 | alias opDollar = length;
86 |
87 | void clear()
88 | {
89 | _length = 0;
90 | }
91 |
92 | private:
93 |
94 | void[8 * 16] stackSpace;
95 | void[] arr;
96 | uint _length;
97 | }
98 |
99 | unittest
100 | {
101 | StackBuffer sb;
102 | ubyte[80] u;
103 | sb.put(u);
104 | assert(sb.length == 80);
105 | static struct S
106 | {
107 | void[100] u;
108 | }
109 |
110 | S s;
111 | sb.put(s);
112 |
113 | class B
114 | {
115 | int b;
116 | }
117 |
118 | class D : B
119 | {
120 | double d;
121 | }
122 |
123 | B b = new B;
124 | sb.put(b);
125 |
126 | B d = new D;
127 | sb.put(d);
128 | }
129 |
130 | package struct TypedStackBuffer(T)
131 | if (__traits(isPOD, T))
132 | {
133 | void push(T value) @trusted
134 | {
135 | sb.put(value);
136 | }
137 |
138 | void opOpAssign(string op : "~")(T value)
139 | {
140 | push(value);
141 | }
142 |
143 | ref inout(T) back() inout pure nothrow @nogc @safe @property
144 | {
145 | return (cast(inout(T)[])sb.opSlice[$ - T.sizeof .. $])[0];
146 | }
147 |
148 | void popBack() pure nothrow @nogc @safe @property
149 | {
150 | assert(!empty);
151 | sb._length -= T.sizeof;
152 | }
153 |
154 | bool empty() const pure nothrow @nogc @safe @property
155 | {
156 | return sb.length == 0;
157 | }
158 |
159 | uint length() const pure nothrow @nogc @safe @property
160 | {
161 | return sb.length / T.sizeof;
162 | }
163 |
164 | private:
165 | StackBuffer sb;
166 | }
167 |
--------------------------------------------------------------------------------
/src/dparse/strings.d:
--------------------------------------------------------------------------------
1 | /// Utility for unescaping D string literals of any kind
2 | module dparse.strings;
3 |
4 | import std.algorithm;
5 | import std.array;
6 | import std.ascii : isAlphaNum, isHexDigit, isWhite;
7 | import std.conv;
8 | import std.range;
9 | import std.string;
10 | import std.utf;
11 |
12 | /**
13 | * Checks if a string literal input has correct start/end sequences (quotes) to
14 | * be any kind of D string literal.
15 | *
16 | * Bugs: doesn't check for validity of token strings.
17 | *
18 | * Standards: $(LINK https://dlang.org/spec/lex.html#string_literals)
19 | */
20 | bool isStringLiteral(const(char)[] literal, out char stringCloseChar,
21 | out bool hasPostfix, out bool parseEscapes, out int prefixLength)
22 | {
23 | // there are no 1 character strings
24 | if (literal.length < 2)
25 | return false;
26 |
27 | // check for valid start
28 | bool allowPostfix;
29 | switch (literal[0])
30 | {
31 | case 'r': // WysiwygString
32 | case 'x': // HexString
33 | if (literal[1] != '"')
34 | return false;
35 | stringCloseChar = '"';
36 | allowPostfix = true;
37 | prefixLength = 2;
38 | break;
39 | case 'q': // DelimitedString
40 | if (literal[1] == '{')
41 | stringCloseChar = '}';
42 | else if (literal[1] == '"')
43 | stringCloseChar = '"';
44 | else
45 | return false;
46 |
47 | allowPostfix = false;
48 | prefixLength = 2;
49 | break;
50 | case '`':
51 | case '"':
52 | stringCloseChar = literal[0];
53 | allowPostfix = true;
54 | parseEscapes = stringCloseChar == '"';
55 | prefixLength = 1;
56 | break;
57 | default:
58 | return false;
59 | }
60 |
61 | if (allowPostfix && literal[$ - 1].among!('c', 'w', 'd'))
62 | {
63 | hasPostfix = true;
64 | literal = literal[0 .. $ - 1];
65 | }
66 |
67 | if (literal.length <= prefixLength || literal[$ - 1] != stringCloseChar)
68 | return false;
69 |
70 | if (parseEscapes)
71 | {
72 | size_t countBackslashes = 0;
73 | foreach_reverse (dchar c; literal[0 .. $ - 1])
74 | {
75 | if (c != '\\')
76 | break;
77 | countBackslashes++;
78 | }
79 |
80 | // check if end escapes the quote, making this an invalid string
81 | if ((countBackslashes % 2) != 0)
82 | return false; // uneven backslash count -> invalid end
83 | }
84 |
85 | return true;
86 | }
87 |
88 | /// ditto
89 | bool isStringLiteral(const(char)[] literal)
90 | {
91 | char stringCloseChar;
92 | bool hasPostfix, parseEscapes;
93 | int prefixLength;
94 | return isStringLiteral(literal, stringCloseChar, hasPostfix, parseEscapes,
95 | prefixLength);
96 | }
97 |
98 | ///
99 | unittest
100 | {
101 | assert(isStringLiteral(`"hello"`));
102 | assert(isStringLiteral(`"ñ"`));
103 | assert(isStringLiteral(`"hello world!"`));
104 | assert(isStringLiteral(`r"hello world!"c`));
105 | assert(isStringLiteral(`r"hello world!"d`));
106 | assert(isStringLiteral(`q{cool}`));
107 | assert(isStringLiteral(`q{cool\}`));
108 | assert(isStringLiteral(`"\\"`));
109 | assert(!isStringLiteral(`"\\\"`));
110 | assert(isStringLiteral(`"\\\\"`));
111 | assert(isStringLiteral(`"a\\\\"`));
112 | assert(!isStringLiteral(`"ñ\"`));
113 | assert(isStringLiteral(`"ñ\\"`));
114 | assert(isStringLiteral(`""`));
115 | assert(isStringLiteral(`q""`));
116 | assert(isStringLiteral(`x""`));
117 | assert(!isStringLiteral(``));
118 | assert(!isStringLiteral(`"`));
119 | assert(!isStringLiteral(`w""`));
120 | assert(!isStringLiteral(`hello"`));
121 | assert(!isStringLiteral(`"hello`));
122 | assert(!isStringLiteral(`"hello world`));
123 | assert(!isStringLiteral(`hello world`));
124 | assert(!isStringLiteral(`r"`));
125 | assert(!isStringLiteral(`rr"ok"`));
126 | assert(!isStringLiteral(`x"`));
127 | assert(!isStringLiteral(`x" `));
128 | assert(!isStringLiteral(`qqqq`));
129 | }
130 |
131 | /// Defines different handler types what to do when invalid escape sequences are
132 | /// found inside $(LREF unescapeString).
133 | enum InvalidEscapeAction
134 | {
135 | /// keep the backslash character as well as the escape characters in the
136 | /// string like in the input string.
137 | keep = 0,
138 | /// Ignore and skip offending characters, drop them from the output. Named
139 | /// character entities are still being included like $(LREF keep) as they
140 | /// are not currently implemented.
141 | skip,
142 | /// Throw a ConvException on invalid escape sequences. Does not throw
143 | /// anything on unknown named character entities as they are not currently
144 | /// implemented but instead treats them like $(LREF keep).
145 | error
146 | }
147 |
148 | /**
149 | * Unescapes a D string, effectively being the same as mixing in the string into
150 | * some function call, but only for single string literals.
151 | *
152 | * Strips quotes, prefixes and suffixes, interprets escape sequences in normal
153 | * double quoted strings and interprets hex strings. Returns simple slices for
154 | * non-escaped strings.
155 | *
156 | * It's undefined how invalid/malformed strings are evaluated.
157 | *
158 | * Bugs: doesn't check for validity of token strings, doesn't interpret named
159 | * character entity escape sequences, (HTML-kind escape sequences) doesn't check
160 | * nesting level of delimited strings.
161 | *
162 | * Standards: $(LINK https://dlang.org/spec/lex.html#string_literals)
163 | */
164 | string unescapeString(
165 | InvalidEscapeAction invalidEscapeAction = InvalidEscapeAction.error
166 | )(
167 | string input
168 | )
169 | in
170 | {
171 | assert(isStringLiteral(input));
172 | }
173 | do
174 | {
175 | char stringCloseChar;
176 | bool hasPostfix, parseEscapes;
177 | int prefixLength;
178 | isStringLiteral(input, stringCloseChar, hasPostfix, parseEscapes,
179 | prefixLength);
180 |
181 | if (hasPostfix)
182 | input = input[0 .. $ - 1];
183 |
184 | auto content = input[prefixLength .. $ - 1];
185 |
186 | if (!content.length)
187 | return content;
188 |
189 | if (input[0] == 'x')
190 | {
191 | // hex string, obsolete but still implemented
192 | return parseHexStringContent!invalidEscapeAction(content);
193 | }
194 | else if (input[0] == 'q' && input[1] == '"')
195 | {
196 | content = content.normalizeNewLines;
197 | if (isIdentifierChar(content[0]))
198 | {
199 | auto ln = content.indexOf('\n');
200 | if (ln == -1)
201 | {
202 | final switch (invalidEscapeAction)
203 | {
204 | case InvalidEscapeAction.keep:
205 | return content;
206 | case InvalidEscapeAction.skip:
207 | return null;
208 | case InvalidEscapeAction.error:
209 | throw new ConvException("Invalid delimited escape string");
210 | }
211 | }
212 | auto delimiter = content[0 .. ln];
213 | content = content[ln + 1 .. $];
214 | if (!content.endsWith(chain("\n", delimiter)))
215 | {
216 | final switch (invalidEscapeAction)
217 | {
218 | case InvalidEscapeAction.keep:
219 | return content;
220 | case InvalidEscapeAction.skip:
221 | auto lastNl = content.lastIndexOf('\n');
222 | if (lastNl == -1)
223 | return content;
224 | else
225 | return content[0 .. lastNl];
226 | case InvalidEscapeAction.error:
227 | throw new ConvException("Delimited escape string not ending correctly");
228 | }
229 | }
230 | return content[0 .. $ - delimiter.length];
231 | }
232 | else
233 | {
234 | char delimiterChar = content[0];
235 | char endChar;
236 | switch (delimiterChar)
237 | {
238 | case '[': endChar = ']'; break;
239 | case '(': endChar = ')'; break;
240 | case '<': endChar = '>'; break;
241 | case '{': endChar = '}'; break;
242 | default: endChar = delimiterChar; break;
243 | }
244 |
245 | if (content[1 .. $].endsWith(endChar))
246 | return content[1 .. $ - 1];
247 | else
248 | {
249 | final switch (invalidEscapeAction)
250 | {
251 | case InvalidEscapeAction.keep:
252 | return content;
253 | case InvalidEscapeAction.skip:
254 | return content[1 .. $];
255 | case InvalidEscapeAction.error:
256 | throw new ConvException("Invalid delimited escape string");
257 | }
258 | }
259 | }
260 | }
261 | else
262 | {
263 | if (!parseEscapes)
264 | return content.normalizeNewLines;
265 | else
266 | return unescapeDoubleQuotedContent!invalidEscapeAction(
267 | content.normalizeNewLines);
268 | }
269 | }
270 |
271 | ///
272 | unittest
273 | {
274 | assert(unescapeString(q{r"I am Oz"}) == r"I am Oz");
275 | assert(unescapeString(q{r"c:\games\Sudoku.exe"}) == r"c:\games\Sudoku.exe");
276 | assert(unescapeString(q{r"ab\n"}) == r"ab\n");
277 |
278 | assert(unescapeString(q{`the Great and Powerful.`}) == `the Great and Powerful.`);
279 | assert(unescapeString(q{`c:\games\Empire.exe`}) == `c:\games\Empire.exe`);
280 | assert(unescapeString(q{`The "lazy" dog`}) == `The "lazy" dog`);
281 | assert(unescapeString(q{`a"b\n`}) == `a"b\n`);
282 |
283 | assert(unescapeString(q{"Who are you?"}) == "Who are you?");
284 | assert(unescapeString(q{"c:\\games\\Doom.exe"}) == "c:\\games\\Doom.exe");
285 | assert(unescapeString(q{"ab\n"}) == "ab\n");
286 |
287 | assert(unescapeString(`x"0A"`) == hexString!"0A");
288 | assert(unescapeString(`x"00 FBCD 32FD 0A"`) == hexString!"00 FBCD 32FD 0A");
289 |
290 | assert(unescapeString(`q"(foo(xxx))"`) == q"(foo(xxx))");
291 | assert(unescapeString(`q"[foo{]"`) == q"[foo{]");
292 | assert(unescapeString(`q""`) == q"");
293 | assert(unescapeString(`q"{foo(}"`) == q"{foo(}");
294 | assert(unescapeString(`q"EOS
295 | This
296 | is a multi-line
297 | heredoc string
298 | EOS"`) == q"EOS
299 | This
300 | is a multi-line
301 | heredoc string
302 | EOS");
303 | assert(unescapeString(`q"/foo]/"`) == `foo]`);
304 |
305 | assert(unescapeString(`q{this is the voice of}`) == q{this is the voice of});
306 | assert(unescapeString(`q{/*}*/ }`) == q{/*}*/ });
307 | assert(unescapeString(`q{ world(q{control}); }`) == q{ world(q{control}); });
308 | assert(unescapeString(`q{ __TIME__ }`) == q{ __TIME__ });
309 |
310 | assert(unescapeString(q{"hello"c}) == "hello");
311 | assert(unescapeString(q{"hello"w}) == "hello");
312 | assert(unescapeString(q{"hello"d}) == "hello");
313 |
314 | assert(unescapeString(`""`) == "");
315 | assert(unescapeString(`"hello\'world\"cool\""`) == "hello\'world\"cool\"");
316 | assert(unescapeString(`"\x0A"`) == "\x0A");
317 | assert(unescapeString(`"\u200b"`) == "\u200b");
318 | assert(unescapeString(`"\U0001F4A9"`) == "\U0001F4A9");
319 | assert(unescapeString(`"\0"`) == "\0");
320 | assert(unescapeString(`"\1"`) == "\1");
321 | assert(unescapeString(`"\12"`) == "\12");
322 | assert(unescapeString(`"\127"`) == "\127");
323 | assert(unescapeString(`"\1278"`) == "\1278");
324 | assert(unescapeString(`"\12a8"`) == "\12a8");
325 | assert(unescapeString(`"\1a28"`) == "\1a28");
326 | assert(unescapeString(`x"afDE"`) == "\xaf\xDE");
327 | assert(unescapeString("\"hello\nworld\rfoo\r\nbar\u2028ok\u2029\"")
328 | == "hello\nworld\nfoo\nbar\nok\n");
329 | }
330 |
331 | unittest
332 | {
333 | import std.exception : assertThrown;
334 |
335 | // unimplemented named characters
336 | assert(unescapeString(`"\&foo;"`) == "\\&foo;");
337 |
338 | assertThrown!ConvException(unescapeString(`"\&foo"`));
339 | assert(unescapeString!(InvalidEscapeAction.keep)(`"\&foo"`) == "\\&foo");
340 | assert(unescapeString!(InvalidEscapeAction.skip)(`"\&foo"`) == "");
341 | }
342 |
343 | unittest
344 | {
345 | import std.exception : assertThrown;
346 |
347 | assertThrown!ConvException(unescapeString(`q"EOS"`));
348 | assert(unescapeString!(InvalidEscapeAction.keep)(`q"EOS"`) == "EOS");
349 | assert(unescapeString!(InvalidEscapeAction.skip)(`q"EOS"`) == "");
350 |
351 | assertThrown!ConvException(unescapeString(`q"EOS
352 | hello"`));
353 | assert(unescapeString!(InvalidEscapeAction.keep)(`q"EOS
354 | hello"`) == "hello");
355 | assert(unescapeString!(InvalidEscapeAction.skip)(`q"EOS
356 | hello"`) == "hello");
357 | assert(unescapeString!(InvalidEscapeAction.skip)(`q"EOS
358 | hello
359 | world"`) == "hello");
360 |
361 | assertThrown!ConvException(unescapeString(`q"/xd"`));
362 | assert(unescapeString!(InvalidEscapeAction.keep)(`q"/xd"`) == "/xd");
363 | assert(unescapeString!(InvalidEscapeAction.skip)(`q"/xd"`) == "xd");
364 |
365 | assertThrown!ConvException(unescapeString(`"\x"`));
366 | assert(unescapeString!(InvalidEscapeAction.keep)(`"\x"`) == "\\x");
367 | assert(unescapeString!(InvalidEscapeAction.skip)(`"\x"`) == "");
368 |
369 | assertThrown!ConvException(unescapeString(`"\u0"`));
370 | assert(unescapeString!(InvalidEscapeAction.keep)(`"\u0"`) == "\\u0");
371 | assert(unescapeString!(InvalidEscapeAction.skip)(`"\u0"`) == "");
372 |
373 | assertThrown!ConvException(unescapeString(`"\U0000000"`));
374 | assert(unescapeString!(InvalidEscapeAction.keep)(`"\U0000000"`) == "\\U0000000");
375 | assert(unescapeString!(InvalidEscapeAction.skip)(`"\U0000000"`) == "");
376 |
377 | assertThrown!ConvException(unescapeString(`"\xAG"`));
378 | assert(unescapeString!(InvalidEscapeAction.keep)(`"\xAG"`) == "\\xAG");
379 | assert(unescapeString!(InvalidEscapeAction.skip)(`"\xAG"`) == "");
380 |
381 | assertThrown!ConvException(unescapeString(`"\u00AG"`));
382 | assert(unescapeString!(InvalidEscapeAction.keep)(`"\u00AG"`) == "\\u00AG");
383 | assert(unescapeString!(InvalidEscapeAction.skip)(`"\u00AG"`) == "");
384 |
385 | assertThrown!ConvException(unescapeDoubleQuotedContent(`a\`));
386 | assert(unescapeDoubleQuotedContent!(InvalidEscapeAction.keep)(`a\`) == "a\\");
387 | assert(unescapeDoubleQuotedContent!(InvalidEscapeAction.skip)(`a\`) == "a");
388 |
389 | assertThrown!ConvException(unescapeString(`"\z"`));
390 | assert(unescapeString!(InvalidEscapeAction.keep)(`"\z"`) == "\\z");
391 | assert(unescapeString!(InvalidEscapeAction.skip)(`"\z"`) == "z");
392 |
393 | assert(parseHexStringContent("") == "");
394 |
395 | assertThrown!ConvException(unescapeString(`x"AG"`));
396 | assert(unescapeString!(InvalidEscapeAction.keep)(`x"AG"`) == "AG");
397 | assert(unescapeString!(InvalidEscapeAction.skip)(`x"AG"`) == "");
398 |
399 | assertThrown!ConvException(unescapeString(`x"A"`));
400 | assert(unescapeString!(InvalidEscapeAction.keep)(`x"A"`) == "A");
401 | assert(unescapeString!(InvalidEscapeAction.skip)(`x"A"`) == "");
402 | }
403 |
404 | private string unescapeDoubleQuotedContent(
405 | InvalidEscapeAction invalidEscapeAction = InvalidEscapeAction.error
406 | )(
407 | string input
408 | )
409 | {
410 | auto escape = input.indexOf('\\');
411 | if (escape == -1)
412 | return input;
413 |
414 | auto ret = appender!string;
415 | ret.reserve(input.length);
416 | size_t start = 0;
417 |
418 | bool requireMinLength(size_t length)
419 | {
420 | if (escape + length >= input.length)
421 | {
422 | final switch (invalidEscapeAction)
423 | {
424 | case InvalidEscapeAction.keep:
425 | ret ~= input[start .. $];
426 | start = input.length;
427 | return false;
428 | case InvalidEscapeAction.skip:
429 | start = input.length;
430 | return false;
431 | case InvalidEscapeAction.error:
432 | throw new ConvException("Unfinished escape at end of string");
433 | }
434 | }
435 | else
436 | {
437 | return true;
438 | }
439 | }
440 |
441 | void errorInvalidCharacter(size_t continueAt)
442 | {
443 | final switch (invalidEscapeAction)
444 | {
445 | case InvalidEscapeAction.keep:
446 | ret ~= input[start .. continueAt];
447 | start = continueAt;
448 | break;
449 | case InvalidEscapeAction.skip:
450 | start = continueAt;
451 | break;
452 | case InvalidEscapeAction.error:
453 | throw new ConvException("Invalid escape character before index "
454 | ~ continueAt.to!string);
455 | }
456 | }
457 |
458 | bool parseUnicode(size_t length)
459 | {
460 | auto c = input[escape + 2 .. escape + 2 + length];
461 | if (!c.all!isHexDigit)
462 | {
463 | errorInvalidCharacter(escape + 2 + length);
464 | return false;
465 | }
466 | dchar ch = cast(dchar) c.to!uint(16);
467 | char[4] buf;
468 | auto size = encode(buf, ch);
469 | ret ~= buf[0 .. size];
470 | start = escape + 2 + length;
471 | return true;
472 | }
473 |
474 | Loop: while (escape != -1)
475 | {
476 | ret ~= input[start .. escape];
477 | start = escape;
478 |
479 | if (!requireMinLength(1))
480 | break;
481 |
482 | Switch:
483 | switch (input[escape + 1])
484 | {
485 | case '\'':
486 | case '"':
487 | case '?':
488 | case '\\':
489 | ret ~= input[escape + 1];
490 | start = escape + 2;
491 | break;
492 |
493 | case 'a': ret ~= '\a'; start = escape + 2; break;
494 | case 'b': ret ~= '\b'; start = escape + 2; break;
495 | case 'f': ret ~= '\f'; start = escape + 2; break;
496 | case 'n': ret ~= '\n'; start = escape + 2; break;
497 | case 'r': ret ~= '\r'; start = escape + 2; break;
498 | case 't': ret ~= '\t'; start = escape + 2; break;
499 | case 'v': ret ~= '\v'; start = escape + 2; break;
500 |
501 | case 'x':
502 | if (!requireMinLength(3))
503 | break Loop;
504 | char a = input[escape + 2];
505 | char b = input[escape + 3];
506 | if (!a.isHexDigit || !b.isHexDigit)
507 | {
508 | errorInvalidCharacter(escape + 4);
509 | break;
510 | }
511 | ret ~= cast(char)(a.parseHexChar << 4 | b.parseHexChar);
512 | start = escape + 4;
513 | break;
514 | case 'u':
515 | if (!requireMinLength(1 + 4))
516 | break Loop;
517 | parseUnicode(4);
518 | break;
519 | case 'U':
520 | if (!requireMinLength(1 + 8))
521 | break Loop;
522 | parseUnicode(8);
523 | break;
524 | case '0': .. case '7':
525 | int length = 1;
526 | foreach (n; 2 .. 4)
527 | {
528 | if (escape + 1 + n > input.length)
529 | break;
530 | char c = input[escape + n];
531 | if (c >= '0' && c <= '7')
532 | length = n;
533 | else
534 | break;
535 | }
536 | int c = input[escape + 1 .. escape + 1 + length].to!int(8);
537 | ret ~= cast(char) c;
538 | start = escape + 1 + length;
539 | break;
540 | case '&':
541 | auto end = input.indexOf(';', escape + 2);
542 | if (end == -1)
543 | {
544 | errorInvalidCharacter(input.length);
545 | }
546 | else
547 | {
548 | ret ~= input[escape .. end + 1];
549 | start = end + 1;
550 | }
551 | break;
552 | default:
553 | errorInvalidCharacter(escape + 1);
554 | break;
555 | }
556 |
557 | escape = input.indexOf('\\', start);
558 | }
559 | ret ~= input[start .. $];
560 | return ret.data;
561 | }
562 |
563 | unittest
564 | {
565 | assert(unescapeDoubleQuotedContent(`hello world`) == "hello world");
566 | assert(unescapeDoubleQuotedContent(`hello\nworld`) == "hello\nworld");
567 | assert(unescapeDoubleQuotedContent(`hello\tworld`) == "hello\tworld");
568 | assert(unescapeDoubleQuotedContent(`hello\u200bworld`) == "hello\u200bworld");
569 | assert(unescapeDoubleQuotedContent(`hello \"\\ok`) == "hello \"\\ok");
570 | assert(unescapeDoubleQuotedContent(`こんにちは \"\\ñ`) == "こんにちは \"\\ñ");
571 | }
572 |
573 | private string parseHexStringContent(
574 | InvalidEscapeAction invalidEscapeAction = InvalidEscapeAction.error
575 | )(
576 | string input
577 | )
578 | {
579 | if (!input.length)
580 | return input;
581 |
582 | auto ret = appender!string;
583 | ret.reserve(input.length / 3);
584 | char buf;
585 | foreach (i, char c; input)
586 | {
587 | if (c.isWhite)
588 | continue;
589 |
590 | if (!c.isHexDigit)
591 | {
592 | final switch (invalidEscapeAction)
593 | {
594 | case InvalidEscapeAction.keep:
595 | if (buf != char.init)
596 | {
597 | ret ~= buf;
598 | buf = char.init;
599 | }
600 | ret ~= c;
601 | break;
602 | case InvalidEscapeAction.skip:
603 | break;
604 | case InvalidEscapeAction.error:
605 | throw new ConvException("Invalid hex character at index "
606 | ~ i.to!string);
607 | }
608 | }
609 | else
610 | {
611 | if (buf == char.init)
612 | {
613 | buf = c;
614 | }
615 | else
616 | {
617 | ret ~= cast(char)(buf.parseHexChar << 4 | c.parseHexChar);
618 | buf = char.init;
619 | }
620 | }
621 | }
622 |
623 | if (buf != char.init)
624 | {
625 | final switch (invalidEscapeAction)
626 | {
627 | case InvalidEscapeAction.keep:
628 | ret ~= buf;
629 | break;
630 | case InvalidEscapeAction.skip:
631 | break;
632 | case InvalidEscapeAction.error:
633 | throw new ConvException("Unterminated hex character at end of string");
634 | }
635 | }
636 |
637 | return ret.data;
638 | }
639 |
640 | private int parseHexChar(char c)
641 | in
642 | {
643 | assert(c.isHexDigit);
644 | assert('a' > 'A' && 'A' > '0'); // just checking that ASCII doesn't suddenly change
645 | }
646 | do
647 | {
648 | // can omit range ends and digit check because of function preconditions
649 | if (c >= 'a')
650 | return (c - 'a') + 10;
651 | else if (c >= 'A')
652 | return (c - 'A') + 10;
653 | else
654 | return c - '0';
655 | }
656 |
657 | private bool isIdentifierChar(char c)
658 | {
659 | return isAlphaNum(c) || c == '_';
660 | }
661 |
662 | /// normalizes all line endings with \n, as parsed in D strings
663 | private string normalizeNewLines(string text)
664 | {
665 | import std.utf : codeLength;
666 |
667 | enum exoticLineBreakLength = codeLength!char('\u2028');
668 | static immutable dchar[] nlCharacters = ['\r', '\u2028', '\u2029'];
669 |
670 | auto end = text.indexOfAny(nlCharacters);
671 | if (end == -1)
672 | return text;
673 | auto ret = appender!string;
674 | ret.reserve(text.length);
675 | size_t start = 0;
676 | while (end != -1)
677 | {
678 | ret ~= text[start .. end];
679 | ret ~= '\n';
680 | if (end + 1 < text.length && text[end] == '\r' && text[end + 1] == '\n')
681 | end++;
682 | else if (text[end] != '\r')
683 | end += exoticLineBreakLength - 1;
684 | start = end + 1;
685 | end = text.indexOfAny(nlCharacters, start);
686 | }
687 | ret ~= text[start .. $];
688 | return ret.data;
689 | }
690 |
691 | ///
692 | unittest
693 | {
694 | string testNoChange = "hello\nworld!";
695 | assert(normalizeNewLines(testNoChange).ptr is testNoChange.ptr);
696 |
697 | assert(normalizeNewLines("hello\rworld") == "hello\nworld");
698 | assert(normalizeNewLines("hello\r\nworld") == "hello\nworld");
699 | assert(normalizeNewLines("hello\r\n\nworld") == "hello\n\nworld");
700 | assert(normalizeNewLines("hello\u2028\nworld") == "hello\n\nworld");
701 | assert(normalizeNewLines("hello\u2029\nworld") == "hello\n\nworld");
702 | assert(normalizeNewLines("hello\r") == "hello\n");
703 | }
704 |
--------------------------------------------------------------------------------
/src/dparse/trivia.d:
--------------------------------------------------------------------------------
1 | /**
2 | * Module to work with trivia tokens (`comment`, `whitespace`,
3 | * `specialTokenSequence`) which are attached to tokens near them when source
4 | * code gets tokenized.
5 | */
6 | module dparse.trivia;
7 |
8 | import std.algorithm;
9 | import std.array;
10 | import std.range;
11 | import std.string;
12 | import std.traits;
13 |
14 | import dparse.lexer;
15 |
16 | enum CommentType : ubyte
17 | {
18 | none,
19 | docLine,
20 | docBlock,
21 | normalLine,
22 | normalBlock,
23 | }
24 |
25 | CommentType determineCommentType(string comment) pure nothrow @safe
26 | {
27 | auto bytes = comment.representation;
28 | auto index = bytes.startsWith(
29 | "//".representation,
30 | "/+".representation,
31 | "/*".representation
32 | );
33 | bool isDoc = bytes.length >= 3 && bytes[1] == bytes[2];
34 | switch (index)
35 | {
36 | case 1:
37 | // Don't treat "////////...." comments as doc comments
38 | isDoc = isDoc && (bytes.length == 3 || bytes[3..$].any!(c => c != '/'));
39 | return isDoc ? CommentType.docLine : CommentType.normalLine;
40 | case 2:
41 | case 3:
42 | return isDoc ? CommentType.docBlock : CommentType.normalBlock;
43 | default:
44 | return CommentType.none;
45 | }
46 | }
47 |
48 | ///
49 | unittest
50 | {
51 | assert (determineCommentType("/// hello") == CommentType.docLine);
52 | assert (determineCommentType("/++ hello") == CommentType.docBlock);
53 | assert (determineCommentType("/** hello") == CommentType.docBlock);
54 | assert (determineCommentType("// hello") == CommentType.normalLine);
55 | assert (determineCommentType("/+ hello") == CommentType.normalBlock);
56 | assert (determineCommentType("/* hello") == CommentType.normalBlock);
57 | assert (determineCommentType("/ hello") == CommentType.none);
58 | assert (determineCommentType("/") == CommentType.none);
59 |
60 | assert (determineCommentType("////////////////////") == CommentType.normalLine);
61 | assert (determineCommentType("///") == CommentType.docLine);
62 | assert (determineCommentType("/// ") == CommentType.docLine);
63 | }
64 |
65 | bool isDocComment(CommentType type) @safe nothrow pure
66 | {
67 | return type == CommentType.docLine || type == CommentType.docBlock;
68 | }
69 |
70 | /**
71 | * Removes "decoration" such as leading whitespace, leading + and * characters,
72 | * and places the result into the given output range
73 | */
74 | public void unDecorateComment(T)(string comment, auto ref T outputRange)
75 | if (isOutputRange!(T, string))
76 | in
77 | {
78 | assert (comment.length >= 3);
79 | }
80 | do
81 | {
82 | import std.string : chompPrefix, KeepTerminator, lineSplitter, stripRight;
83 |
84 | string leadingChars;
85 |
86 | enum LineType { none, normal, strange }
87 | LineType prevLineType;
88 |
89 | switch (comment[0 .. 3])
90 | {
91 | case "///":
92 | foreach (line; lineSplitter!(KeepTerminator.yes)(comment))
93 | {
94 | if (leadingChars.empty)
95 | {
96 | size_t k = 3;
97 | while (k < line.length && (line[k] == ' ' || line[k] == '\t'))
98 | k++;
99 | leadingChars = line[0 .. k];
100 | }
101 | outputRange.put(line.chompPrefix(leadingChars));
102 | }
103 | break;
104 | case "/++":
105 | case "/**":
106 | alias CL = MultiLineCommentHelper!(ElementEncodingType!(typeof(comment)));
107 | CL cl = CL(comment);
108 | cl.process(outputRange);
109 | break;
110 | default:
111 | outputRange.put(comment);
112 | }
113 | }
114 |
115 | ///
116 | unittest
117 | {
118 | import std.array:array, appender;
119 | import std.stdio:stderr;
120 | stderr.writeln("Running unittest for unDecorateComment...");
121 |
122 | string[] inputs = [
123 | "/***************\n*******************/",
124 | "/***************\n *\n ******************/",
125 | "/**\n*/",
126 | "/** */",
127 | "/***/",
128 | "/******/",
129 | "/** abcde1 */",
130 | "/// abcde2\n/// abcde2",
131 | "/**\n * stuff1\n */",
132 | "/**\n *\n * stuff2\n */",
133 | "/**\n *\n * stuff3\n *\n */",
134 | "/**\n *\n * stuff4\n *\n*/",
135 | "/**\n * abcde3\n * abcde3 \n */",
136 | "/**\n * abcde4\n *\n * abcde4\n */",
137 | "/**abcde5\n*abcde5\n*/",
138 | "/** abcde6\n * abcde6\n*/",
139 | "/**\n1\n\n\n\n*/",
140 | "/**\r\n1\r\n\r\n\r\n\r\n*/",
141 | "/**\na1\n\na2\n\n*/",
142 | "/**b1\n*b2\n*b3*/",
143 | "/**c1\n *c2\n *c3*/",
144 | "/**d1\n *d2\n *d3\n*/",
145 | "///a\fbc\n///def"
146 | ];
147 | string[] outputs = [
148 | "",
149 | "",
150 | "",
151 | "",
152 | "",
153 | "",
154 | "abcde1",
155 | "abcde2\nabcde2",
156 | "stuff1",
157 | "stuff2",
158 | "stuff3",
159 | "stuff4",
160 | "abcde3\n abcde3",
161 | "abcde4\n\nabcde4",
162 | "abcde5\nabcde5",
163 | "abcde6\nabcde6",
164 | "1",
165 | "1",
166 | "a1\n\na2",
167 | "b1\nb2\nb3",
168 | "c1\nc2\nc3",
169 | "d1\nd2\nd3",
170 | "a\fbc\ndef"
171 | ];
172 |
173 | // tests where * and + are not interchangeable
174 | string[2][] np =
175 | [
176 | ["/**\n * d1\n d2\n */", "* d1\nd2"],
177 | ["/**\n + d1\n d2\n */", "+ d1\nd2"],
178 | ["/**d1\n\n\n*d2\n*/", "d1\n\n*d2"],
179 | ];
180 |
181 | assert(inputs.length == outputs.length);
182 | foreach (pair; zip(inputs, outputs))
183 | {
184 | foreach (b; [true, false])
185 | {
186 | auto app = appender!string();
187 | unDecorateComment(b ? pair[0] : pair[0].replace("*", "+"), app);
188 | assert(pair[1] == app.data, "[[" ~ pair[0] ~ "]] => [[" ~ app.data ~ "]]");
189 | }
190 | }
191 | foreach (pair; np)
192 | {
193 | auto app = appender!string();
194 | unDecorateComment(pair[0], app);
195 | assert(pair[1] == app.data, "[[" ~ pair[0] ~ "]] => [[" ~ app.data ~ "]]");
196 | }
197 | stderr.writeln("Unittest for unDecorateComment passed.");
198 | }
199 |
200 | /** Gives a line per line view on DDOC comments of type `/++` and `/**` which
201 | * makes easier to remove the decoration and in an almost 100% nogc way. */
202 | private struct MultiLineCommentHelper(CharType : const(char))
203 | {
204 | // this struct is more used as a 'function with nested functions' would.
205 | this() @disable;
206 | this(this) @disable;
207 | auto opAssign(T)(T t) @disable;
208 |
209 | private:
210 |
211 | char[][] lines;
212 | // either lines.length or lines.length-1, depending on if last line only closes
213 | size_t lastLineInBlockPlusOne;
214 | // either '*' or '+'
215 | const(char) commentChar;
216 | // either 0 or 1, depending on if first line only opens
217 | ubyte firstLineInBlock;
218 |
219 | import std.ascii : isWhite;
220 |
221 | void stripIndent() @safe @nogc pure nothrow
222 | {
223 | if (lines.length < 2)
224 | return;
225 | size_t count;
226 | foreach (const j; 0 .. lines[1].length)
227 | if (!(lines[1][j]).isWhite)
228 | {
229 | count = j;
230 | break;
231 | }
232 | if (count < 2)
233 | return;
234 | foreach (ref line; lines[1 .. $])
235 | {
236 | foreach (const j; 0 .. line.length)
237 | {
238 | if (!(line[j]).isWhite)
239 | break;
240 | if (j == count - 1)
241 | {
242 | line = line[j .. $];
243 | break;
244 | }
245 | }
246 | }
247 | }
248 |
249 | void processFirstLine() @safe @nogc pure nothrow
250 | {
251 | assert(lines.length);
252 | if (lines[0].length > 3)
253 | {
254 | foreach (const i; 1..lines[0].length)
255 | {
256 | if (lines[0][i] == commentChar)
257 | {
258 | if (i < lines[0].length - 2)
259 | continue;
260 | if (i == lines[0].length - 2 && lines[0][i+1] == '/')
261 | {
262 | lines[0][] = ' ';
263 | break;
264 | }
265 | if (i == lines[0].length - 1)
266 | {
267 | lines[0][] = ' ';
268 | break;
269 | }
270 | }
271 | else
272 | {
273 | lines[0][0..i] = ' ';
274 | break;
275 | }
276 | }
277 | }
278 | lines[0][0..3] = " ";
279 | if (lines.length == 1 &&
280 | lines[0][$-2] == commentChar && lines[0][$-1] == '/')
281 | {
282 | lines[0][$-2..$] = " ";
283 | }
284 | foreach (const i; 0..lines[0].length)
285 | if (!(lines[0][i].isWhite))
286 | return;
287 | firstLineInBlock = 1;
288 | }
289 |
290 | void processLastLine() @safe @nogc pure nothrow
291 | {
292 | lastLineInBlockPlusOne = lines.length;
293 | if (lines.length == 1)
294 | return;
295 | size_t closeStartIndex = size_t.max;
296 | foreach (const i; 0..lines[$-1].length)
297 | {
298 | if (lines[$-1][i] == commentChar)
299 | {
300 | if (closeStartIndex == size_t.max)
301 | closeStartIndex = i;
302 | if (i == lines[$-1].length - 2)
303 | {
304 | // see the FIXME note in unDecorate()
305 | lastLineInBlockPlusOne = closeStartIndex == 0 ? lines.length-1 : lines.length;
306 |
307 | lines[$-1][closeStartIndex..$] = ' ';
308 | break;
309 | }
310 | }
311 | else
312 | {
313 | closeStartIndex = size_t.max;
314 | lastLineInBlockPlusOne = lines.length;
315 | }
316 | }
317 | }
318 |
319 | void unDecorate() @safe @nogc pure nothrow
320 | {
321 | if (lines.length == 1 || lines.length == 2 && lines[$-1].length == 0)
322 | return;
323 | bool allDecorated;
324 | static immutable char[2][2] pattern = [[' ', '*'],[' ', '+']];
325 | const ubyte patternIndex = commentChar == '+';
326 | // first line is never decorated
327 | const size_t lo = 1;
328 | // although very uncommon, the last line can be decorated e.g in `* lastline */`:
329 | // the first '*' is a deco if all prev lines are also decorated.
330 | // FIXME: `hi` should be set to `lastLineInBlockPlusOne`...
331 | const size_t hi = (lines[$-1].length > 1 &&
332 | (lines[$-1][0] == commentChar || lines[$-1][0..2] == pattern[patternIndex]))
333 | ? lines.length : lines.length-1;
334 | // deco with a leading white
335 | foreach (const i; lo .. hi)
336 | {
337 | if (lines[i].length < 2)
338 | break;
339 | else if (lines[i][0..2] != pattern[patternIndex])
340 | break;
341 | else if (i == hi-1)
342 | allDecorated = true;
343 | }
344 | // deco w/o leading white
345 | if (!allDecorated)
346 | foreach (const i; lo .. hi)
347 | {
348 | if (lines[i].length == 0)
349 | break;
350 | if (lines[i][0] != commentChar)
351 | break;
352 | else if (i == hi-1)
353 | allDecorated = true;
354 | }
355 | if (!allDecorated)
356 | return;
357 |
358 | const size_t indexToChange = (lines[lo][0] == commentChar) ? 0 : 1;
359 | foreach (ref line; lines[lo .. hi])
360 | line[indexToChange] = ' ';
361 | }
362 |
363 | void stripLeft() @safe @nogc pure nothrow
364 | {
365 | foreach (const i; 0 .. lines[0].length)
366 | if (!(lines[0][i]).isWhite)
367 | {
368 | lines[0] = lines[0][i..$];
369 | break;
370 | }
371 | if (lines.length == 1)
372 | return;
373 | while (true)
374 | {
375 | bool processColumn;
376 | foreach (ref line; lines[1 .. lastLineInBlockPlusOne])
377 | {
378 | if (line.length == 0)
379 | continue;
380 | if (!(line[0]).isWhite)
381 | return;
382 | processColumn = true;
383 | }
384 | if (!processColumn)
385 | return;
386 | foreach (ref line; lines[1 .. lastLineInBlockPlusOne])
387 | {
388 | if (line.length == 0)
389 | continue;
390 | line = line[1..$];
391 | }
392 | }
393 | }
394 |
395 | void stripRight() @safe @nogc pure nothrow
396 | {
397 | foreach (ref line; lines[0 .. lines.length])
398 | {
399 | if (line.length == 0)
400 | continue;
401 | if ((line[$-1]).isWhite)
402 | {
403 | size_t firstWhite = line.length;
404 | while (firstWhite > 0 && (line[firstWhite-1]).isWhite)
405 | firstWhite--;
406 | line = line[0..firstWhite];
407 | }
408 | }
409 | }
410 |
411 | void run() @safe @nogc pure nothrow
412 | {
413 | stripIndent();
414 | processFirstLine();
415 | processLastLine();
416 | unDecorate();
417 | stripLeft();
418 | stripRight();
419 | }
420 |
421 | public:
422 |
423 | this(CharType[] text) @safe pure nothrow
424 | {
425 | assert(text.length >= 3 && text[0] == '/',
426 | "MultiLineCommentHelper text must start with a comment in form /++ or /**");
427 |
428 | commentChar = text[1];
429 | size_t startIndex, i;
430 | Appender!(char[][]) linesApp;
431 | linesApp.reserve(512);
432 |
433 | void storeLine(size_t endIndexPlusOne)
434 | {
435 | static if (isMutable!CharType)
436 | linesApp ~= text[startIndex..endIndexPlusOne];
437 | else
438 | linesApp ~= text[startIndex..endIndexPlusOne].dup;
439 | }
440 |
441 | // if we go over text length (in \r\n) we already stored the line, so just exit there
442 | while (i < text.length)
443 | {
444 | // check if next char is going to be end of text, store until then & break
445 | if (i + 1 == text.length)
446 | {
447 | storeLine(text.length);
448 | break;
449 | }
450 | if (text[i] == '\n')
451 | {
452 | storeLine(i);
453 | startIndex = i + 1;
454 | }
455 | else if (i + 1 < text.length && text[i .. i+2] == "\r\n")
456 | {
457 | storeLine(i);
458 | i++;
459 | startIndex = i + 1;
460 | }
461 | i++;
462 | }
463 | lines = linesApp.data;
464 | }
465 |
466 | void process(T)(ref T outbuffer)
467 | {
468 | run();
469 | outbuffer.reserve(lines.length * 90);
470 | bool prevWritten, empties;
471 | foreach (ref line; lines[firstLineInBlock .. lines.length])
472 | {
473 | if (line.length != 0)
474 | {
475 | // close preceeding line
476 | if (prevWritten)
477 | outbuffer ~= "\n";
478 | // insert new empty line
479 | if (prevWritten && empties)
480 | outbuffer ~= "\n";
481 |
482 | outbuffer ~= line;
483 | prevWritten = true;
484 | empties = false;
485 | }
486 | else empties = true;
487 | }
488 | }
489 | }
490 |
491 | unittest
492 | {
493 | import std.conv : to;
494 |
495 | alias SC = MultiLineCommentHelper!(immutable(char));
496 |
497 | // checks full comment processing on the given string and compares the generated lines
498 | void check(string comment, string[] lines, size_t lineNo = __LINE__)
499 | {
500 | auto sc = SC(comment);
501 | sc.run();
502 | assert(sc.lines == lines, sc.lines.to!string ~ " != " ~ lines.to!string
503 | ~ " (for check on line " ~ lineNo.to!string ~ ")");
504 | }
505 |
506 | // check common cases while typing
507 | check("/++", [""]);
508 | check("/++\r", [""]);
509 | check("/++\n", [""]);
510 | check("/++\r\n", [""]);
511 | check("/++\r\n+", ["", "+"]);
512 | check("/++\r\n+ ok", ["", "ok"]);
513 | check("/++\r\n+ ok\r\n+/", ["", "ok", ""]);
514 | check("/++/", [""]);
515 | }
516 |
517 | /// Extracts and combines ddoc comments from trivia comments.
518 | string extractDdocFromTrivia(Tokens)(Tokens tokens) pure nothrow @safe
519 | if (isInputRange!Tokens && (is(ElementType!Tokens : Token) || is(ElementType!Tokens : TriviaToken)))
520 | {
521 | bool hasDoc;
522 | auto ret = appender!string;
523 | foreach (trivia; tokens)
524 | {
525 | if (trivia.type == tok!"comment"
526 | && trivia.text.determineCommentType.isDocComment)
527 | {
528 | hasDoc = true;
529 | if (!ret.data.empty)
530 | ret.put('\n');
531 | unDecorateComment(trivia.text, ret);
532 | }
533 | }
534 |
535 | if (ret.data.length)
536 | return ret.data;
537 | else
538 | return hasDoc ? "" : null;
539 | }
540 |
541 | unittest
542 | {
543 | Token[] tokens = [
544 | Token(cast(ubyte) tok!"whitespace", "\n\n", 0, 0, 0),
545 | Token(cast(ubyte) tok!"comment", "///", 0, 0, 0),
546 | Token(cast(ubyte) tok!"whitespace", "\n", 0, 0, 0)
547 | ];
548 |
549 | // Empty comment is non-null
550 | auto comment = extractDdocFromTrivia(tokens);
551 | assert(comment !is null);
552 | assert(comment == "");
553 |
554 | // Missing comment is null
555 | comment = extractDdocFromTrivia(tokens[0 .. 1]);
556 | assert(comment is null);
557 | assert(comment == "");
558 | }
559 |
560 | string extractLeadingDdoc(const Token token) pure nothrow @safe
561 | {
562 | return extractDdocFromTrivia(token.leadingTrivia);
563 | }
564 |
565 | string extractTrailingDdoc(const Token token) pure nothrow @safe
566 | {
567 | return extractDdocFromTrivia(token.trailingTrivia.filter!(a => a.line == token.line));
568 | }
569 |
570 | // test token trivia members
571 | unittest
572 | {
573 | import std.conv : to;
574 | import std.exception : enforce;
575 |
576 | static immutable src = `/// this is a module.
577 | // mixed
578 | /// it can do stuff
579 | module foo.bar;
580 |
581 | // hello
582 |
583 | /**
584 | * some doc
585 | * hello
586 | */
587 | int x; /// very nice
588 |
589 | // TODO: do stuff
590 | void main() {
591 | #line 40
592 | /// could be better
593 | writeln(":)");
594 | }
595 |
596 | ///
597 | unittest {}
598 |
599 | /// end of file`;
600 |
601 | LexerConfig cf;
602 | StringCache ca = StringCache(16);
603 |
604 | const tokens = getTokensForParser(src, cf, &ca);
605 |
606 | assert(tokens.length == 22);
607 |
608 | assert(tokens[0].type == tok!"module");
609 | assert(tokens[0].leadingTrivia.length == 6);
610 | assert(tokens[0].leadingTrivia[0].type == tok!"comment");
611 | assert(tokens[0].leadingTrivia[0].text == "/// this is a module.");
612 | assert(tokens[0].leadingTrivia[1].type == tok!"whitespace");
613 | assert(tokens[0].leadingTrivia[1].text == "\n");
614 | assert(tokens[0].leadingTrivia[2].type == tok!"comment");
615 | assert(tokens[0].leadingTrivia[2].text == "// mixed");
616 | assert(tokens[0].leadingTrivia[3].type == tok!"whitespace");
617 | assert(tokens[0].leadingTrivia[3].text == "\n");
618 | assert(tokens[0].leadingTrivia[4].type == tok!"comment");
619 | assert(tokens[0].leadingTrivia[4].text == "/// it can do stuff");
620 | assert(tokens[0].leadingTrivia[5].type == tok!"whitespace");
621 | assert(tokens[0].leadingTrivia[5].text == "\n");
622 | assert(tokens[0].trailingTrivia.length == 1);
623 | assert(tokens[0].trailingTrivia[0].type == tok!"whitespace");
624 | assert(tokens[0].trailingTrivia[0].text == " ");
625 |
626 | assert(tokens[1].type == tok!"identifier");
627 | assert(tokens[1].text == "foo");
628 | assert(!tokens[1].leadingTrivia.length);
629 | assert(!tokens[1].trailingTrivia.length);
630 |
631 | assert(tokens[2].type == tok!".");
632 | assert(!tokens[2].leadingTrivia.length);
633 | assert(!tokens[2].trailingTrivia.length);
634 |
635 | assert(tokens[3].type == tok!"identifier");
636 | assert(tokens[3].text == "bar");
637 | assert(!tokens[3].leadingTrivia.length);
638 | assert(!tokens[3].trailingTrivia.length);
639 |
640 | assert(tokens[4].type == tok!";");
641 | assert(!tokens[4].leadingTrivia.length);
642 | assert(tokens[4].trailingTrivia.length == 1);
643 | assert(tokens[4].trailingTrivia[0].type == tok!"whitespace");
644 | assert(tokens[4].trailingTrivia[0].text == "\n\n");
645 |
646 | assert(tokens[5].type == tok!"int");
647 | assert(tokens[5].leadingTrivia.length == 4);
648 | assert(tokens[5].leadingTrivia[0].text == "// hello");
649 | assert(tokens[5].leadingTrivia[1].text == "\n\n");
650 | assert(tokens[5].leadingTrivia[2].text == "/**\n * some doc\n * hello\n */");
651 | assert(tokens[5].leadingTrivia[3].text == "\n");
652 | assert(tokens[5].trailingTrivia.length == 1);
653 | assert(tokens[5].trailingTrivia[0].text == " ");
654 |
655 | assert(tokens[6].type == tok!"identifier");
656 | assert(tokens[6].text == "x");
657 | assert(!tokens[6].leadingTrivia.length);
658 | assert(!tokens[6].trailingTrivia.length);
659 |
660 | assert(tokens[7].type == tok!";");
661 | assert(!tokens[7].leadingTrivia.length);
662 | assert(tokens[7].trailingTrivia.length == 3);
663 | assert(tokens[7].trailingTrivia[0].text == " ");
664 | assert(tokens[7].trailingTrivia[1].text == "/// very nice");
665 | assert(tokens[7].trailingTrivia[2].text == "\n\n");
666 |
667 | assert(tokens[8].type == tok!"void");
668 | assert(tokens[8].leadingTrivia.length == 2);
669 | assert(tokens[8].leadingTrivia[0].text == "// TODO: do stuff");
670 | assert(tokens[8].leadingTrivia[1].text == "\n");
671 | assert(tokens[8].trailingTrivia.length == 1);
672 | assert(tokens[8].trailingTrivia[0].text == " ");
673 |
674 | assert(tokens[9].type == tok!"identifier");
675 | assert(tokens[9].text == "main");
676 | assert(!tokens[9].leadingTrivia.length);
677 | assert(!tokens[9].trailingTrivia.length);
678 |
679 | assert(tokens[10].type == tok!"(");
680 | assert(!tokens[10].leadingTrivia.length);
681 | assert(!tokens[10].trailingTrivia.length);
682 |
683 | assert(tokens[11].type == tok!")");
684 | assert(!tokens[11].leadingTrivia.length);
685 | assert(tokens[11].trailingTrivia.length == 1);
686 | assert(tokens[11].trailingTrivia[0].text == " ");
687 |
688 | assert(tokens[12].type == tok!"{");
689 | assert(!tokens[12].leadingTrivia.length);
690 | assert(tokens[12].trailingTrivia.length == 1);
691 | assert(tokens[12].trailingTrivia[0].text == "\n ");
692 |
693 | assert(tokens[13].type == tok!"identifier");
694 | assert(tokens[13].text == "writeln");
695 | assert(tokens[13].leadingTrivia.length == 4);
696 | assert(tokens[13].leadingTrivia[0].type == tok!"specialTokenSequence");
697 | assert(tokens[13].leadingTrivia[0].text == "#line 40");
698 | assert(tokens[13].leadingTrivia[1].type == tok!"whitespace");
699 | assert(tokens[13].leadingTrivia[1].text == "\n ");
700 | assert(tokens[13].leadingTrivia[2].type == tok!"comment");
701 | assert(tokens[13].leadingTrivia[2].text == "/// could be better");
702 | assert(tokens[13].leadingTrivia[3].type == tok!"whitespace");
703 | assert(tokens[13].leadingTrivia[3].text == "\n ");
704 | assert(!tokens[13].trailingTrivia.length);
705 |
706 | assert(tokens[14].type == tok!"(");
707 | assert(!tokens[14].leadingTrivia.length);
708 | assert(!tokens[14].trailingTrivia.length);
709 |
710 | assert(tokens[15].type == tok!"stringLiteral");
711 | assert(!tokens[15].leadingTrivia.length);
712 | assert(!tokens[15].trailingTrivia.length);
713 |
714 | assert(tokens[16].type == tok!")");
715 | assert(!tokens[16].leadingTrivia.length);
716 | assert(!tokens[16].trailingTrivia.length);
717 |
718 | assert(tokens[17].type == tok!";");
719 | assert(!tokens[17].leadingTrivia.length);
720 | assert(tokens[17].trailingTrivia.length == 1);
721 | assert(tokens[17].trailingTrivia[0].text == "\n");
722 |
723 | assert(tokens[18].type == tok!"}");
724 | assert(!tokens[18].leadingTrivia.length);
725 | assert(tokens[18].trailingTrivia.length == 1);
726 | assert(tokens[18].trailingTrivia[0].type == tok!"whitespace");
727 | assert(tokens[18].trailingTrivia[0].text == "\n\n");
728 |
729 | assert(tokens[19].type == tok!"unittest");
730 | assert(tokens[19].leadingTrivia.length == 2);
731 | assert(tokens[19].leadingTrivia[0].type == tok!"comment");
732 | assert(tokens[19].leadingTrivia[0].text == "///");
733 | assert(tokens[19].leadingTrivia[1].type == tok!"whitespace");
734 | assert(tokens[19].leadingTrivia[1].text == "\n");
735 |
736 | assert(tokens[19].trailingTrivia.length == 1);
737 | assert(tokens[19].trailingTrivia[0].type == tok!"whitespace");
738 | assert(tokens[19].trailingTrivia[0].text == " ");
739 |
740 | assert(tokens[20].type == tok!"{");
741 | assert(!tokens[20].leadingTrivia.length);
742 | assert(!tokens[20].trailingTrivia.length);
743 |
744 | assert(tokens[21].type == tok!"}");
745 | assert(!tokens[21].leadingTrivia.length);
746 | assert(tokens[21].trailingTrivia.length == 2);
747 | assert(tokens[21].trailingTrivia[0].type == tok!"whitespace");
748 | assert(tokens[21].trailingTrivia[0].text == "\n\n");
749 | assert(tokens[21].trailingTrivia[1].type == tok!"comment");
750 | assert(tokens[21].trailingTrivia[1].text == "/// end of file");
751 | }
752 |
--------------------------------------------------------------------------------
/test/ast_checks/assert_args.d:
--------------------------------------------------------------------------------
1 | static assert(foo, "a", b, "c");
2 |
--------------------------------------------------------------------------------
/test/ast_checks/assert_args.txt:
--------------------------------------------------------------------------------
1 | ./module/declaration/staticAssertDeclaration//assertArguments/unaryExpression[1]//identifierOrTemplateInstance/identifier[text()="foo"]
2 | ./module/declaration/staticAssertDeclaration//assertArguments/unaryExpression[2]/primaryExpression/stringLiteral[text()='"a"']
3 | ./module/declaration/staticAssertDeclaration//assertArguments/unaryExpression[3]//identifierOrTemplateInstance/identifier[text()="b"]
4 | ./module/declaration/staticAssertDeclaration//assertArguments/unaryExpression[4]/primaryExpression/stringLiteral[text()='"c"']
5 |
--------------------------------------------------------------------------------
/test/ast_checks/errorRecovery.d:
--------------------------------------------------------------------------------
1 | // things that test that they abort properly, but not emit any AST:
2 |
3 | void asm1() {
4 | asm {
5 | align true;
6 | }
7 | }
8 |
9 | void asm2() {
10 | asm const {
11 | }
12 | }
13 |
14 | void randomContinue() {
15 | continue 4;
16 | }
17 |
18 | void randomBreak() {
19 | break 4;
20 | }
21 |
22 | void randomGoto() {
23 | goto 4;
24 | }
25 |
26 | void randomDebug() {
27 | debug = true;
28 | }
29 |
30 | void randomDebug2() {
31 | debug (true)
32 | {
33 | }
34 | }
35 |
36 | void foo3()
37 | in(x > 4)
38 |
39 | void thisIsCurrentlyEaten() {}
40 |
41 | struct 5
42 | {
43 | void ignoredAsWell() {}
44 | }
45 |
46 | void brokenSwitch()
47 | {
48 | switch (;)
49 | {
50 | }
51 | }
52 |
53 | void brokenCall()
54 | {
55 | foo(
56 | }
57 |
58 | void randomVersion() {
59 | version (true)
60 | {
61 | }
62 | }
63 |
64 | void randomVersion2() {
65 | version = x("");
66 | }
67 |
68 | class X : Sub
69 | if (x)
70 | void ignored() {}
71 | void afterClass() {}
72 |
73 | version;
74 |
75 | void versionWorks() {}
76 |
77 | mixin = 4;
78 |
79 | void mixinWorks() {}
80 |
81 | version = true;
82 |
83 | void discardedVersion() {}
84 |
85 | // things that test that they abort properly and emit partial or corrected AST:
86 |
87 | void foo() out(x > 4) {}
88 | void foo2() out(true; x > 4) {}
89 |
90 | version = 1
91 |
92 | void bar()
93 | {
94 | do {
95 |
96 | } while (x)
97 | }
98 |
99 | void baz()
100 | {
101 | import a
102 | import b;
103 | }
104 |
105 | @
--------------------------------------------------------------------------------
/test/ast_checks/errorRecovery.txt:
--------------------------------------------------------------------------------
1 | INCLUDES_PARSE_ERROR
2 | ./module/declaration/functionDeclaration[name = 'asm1']
3 | ./module/declaration/functionDeclaration[name = 'asm2']
4 | ./module/declaration/functionDeclaration[name = 'randomContinue']
5 | ./module/declaration/functionDeclaration[name = 'randomBreak']
6 | ./module/declaration/functionDeclaration[name = 'randomGoto']
7 | ./module/declaration/functionDeclaration[name = 'randomDebug']
8 | ./module/declaration/functionDeclaration[name = 'randomDebug2']
9 | ./module/declaration/functionDeclaration[name = 'brokenSwitch']
10 | ./module/declaration/functionDeclaration[name = 'brokenCall']
11 | ./module/declaration/functionDeclaration[name = 'randomVersion']
12 | ./module/declaration/functionDeclaration[name = 'randomVersion2']
13 | ./module/declaration/functionDeclaration[name = 'afterClass']
14 | ./module/declaration/functionDeclaration[name = 'versionWorks']
15 | ./module/declaration/functionDeclaration[name = 'mixinWorks']
16 | ./module/declaration/functionDeclaration[name = 'discardedVersion']
17 | ./module/declaration/functionDeclaration[name = 'foo']//outContractExpression/assertArguments/cmpExpression
18 | ./module/declaration/functionDeclaration[name = 'foo2']//outContractExpression/assertArguments/cmpExpression
19 | ./module/declaration/versionSpecification[intLiteral = '1']
20 | ./module/declaration/functionDeclaration[name = 'bar']/functionBody//doStatement
21 | ./module/declaration/functionDeclaration[name = 'baz']/functionBody//importDeclaration/singleImport/identifierChain[identifier = 'a']
22 | ./module/declaration/functionDeclaration[name = 'baz']/functionBody//importDeclaration/singleImport/identifierChain[identifier = 'b']
23 |
--------------------------------------------------------------------------------
/test/ast_checks/file1.d:
--------------------------------------------------------------------------------
1 | struct UselessStruct
2 | {
3 | static if (true)
4 | {
5 | unittest {}
6 | }
7 |
8 | private:
9 |
10 | }
11 |
12 | int someNumber;
13 |
--------------------------------------------------------------------------------
/test/ast_checks/file1.txt:
--------------------------------------------------------------------------------
1 | ./module//structBody//compileCondition
2 | ./module//structBody//attributeDeclaration
3 | ./module/declaration/variableDeclaration//type2[text()="int"]
4 |
--------------------------------------------------------------------------------
/test/ast_checks/foreach.d:
--------------------------------------------------------------------------------
1 | void foo(T)(T[] arr)
2 | {
3 | foreach (enum ref scope const inout alias f; arr) {}
4 | }
5 |
--------------------------------------------------------------------------------
/test/ast_checks/foreach.txt:
--------------------------------------------------------------------------------
1 | //functionDeclaration//foreachStatement//foreachType/alias
2 | //functionDeclaration//foreachStatement//foreachType/enum
3 | //functionDeclaration//foreachStatement//foreachType/ref
4 | //functionDeclaration//foreachStatement//foreachType/scope
5 | //functionDeclaration//foreachStatement//foreachType/typeConstructor[text()='const']
6 | //functionDeclaration//foreachStatement//foreachType/typeConstructor[text()='inout']
7 |
--------------------------------------------------------------------------------
/test/ast_checks/interpolated_string.d:
--------------------------------------------------------------------------------
1 | void foo()
2 | {
3 | writeln(i"Hello name, you have $$(wealth) in your account right now");
4 | }
5 |
--------------------------------------------------------------------------------
/test/ast_checks/interpolated_string.txt:
--------------------------------------------------------------------------------
1 | //interpolatedString[@startQuote='i"']
2 | //interpolatedString[@endQuote='"']
3 | //interpolatedString/text[text()='Hello name, you have $']
4 | //interpolatedString/text[text()=' in your account right now']
5 | //interpolatedString/expression/unaryExpression
6 |
--------------------------------------------------------------------------------
/test/ast_checks/issue428.d:
--------------------------------------------------------------------------------
1 | debug:
2 | const a = 1;
3 |
--------------------------------------------------------------------------------
/test/ast_checks/issue428.txt:
--------------------------------------------------------------------------------
1 | //conditionalDeclaration//trueDeclarations[@style="colon"]
2 |
--------------------------------------------------------------------------------
/test/ast_checks/issue471.d:
--------------------------------------------------------------------------------
1 | void foo()
2 | {
3 | auto bar1 = () => 4;
4 | auto bar2 = ref () => 4;
5 | auto bar3 = auto ref () => 4;
6 | auto bar4 = function () => 4;
7 | auto bar5 = function ref () => 4;
8 | auto bar6 = function auto ref () => 4;
9 | }
--------------------------------------------------------------------------------
/test/ast_checks/issue471.txt:
--------------------------------------------------------------------------------
1 | //variableDeclaration//autoDeclarationPart//name[text()="bar1"]/../initializer//functionLiteralExpression
2 | not(//variableDeclaration//autoDeclarationPart//name[text()="bar1"]/../initializer//functionLiteralExpression[@ref])
3 | //variableDeclaration//autoDeclarationPart//name[text()="bar2"]/../initializer//functionLiteralExpression[@ref]
4 | //variableDeclaration//autoDeclarationPart//name[text()="bar2"]/../initializer//functionLiteralExpression[@ref="ref"]
5 | //variableDeclaration//autoDeclarationPart//name[text()="bar3"]/../initializer//functionLiteralExpression[@ref="auto ref"]
6 | //variableDeclaration//autoDeclarationPart//name[text()="bar4"]/../initializer//functionLiteralExpression
7 | not(//variableDeclaration//autoDeclarationPart//name[text()="bar4"]/../initializer//functionLiteralExpression[@ref])
8 | //variableDeclaration//autoDeclarationPart//name[text()="bar5"]/../initializer//functionLiteralExpression[@ref]
9 | //variableDeclaration//autoDeclarationPart//name[text()="bar5"]/../initializer//functionLiteralExpression[@ref="ref"]
10 | //variableDeclaration//autoDeclarationPart//name[text()="bar6"]/../initializer//functionLiteralExpression[@ref="auto ref"]
11 |
--------------------------------------------------------------------------------
/test/ast_checks/moduleDec4.d:
--------------------------------------------------------------------------------
1 | @something deprecated module moduleDec3;
2 |
--------------------------------------------------------------------------------
/test/ast_checks/moduleDec4.txt:
--------------------------------------------------------------------------------
1 | /module/moduleDeclaration/atAttribute/identifier[text()="something"]
2 | /module/moduleDeclaration/deprecated
3 |
--------------------------------------------------------------------------------
/test/ast_checks/named_arguments.d:
--------------------------------------------------------------------------------
1 | void main()
2 | {
3 | a(100);
4 | b(x: 100);
5 | c(x: 100, y: 200);
6 | d!(a: "a", b: "b")("c");
7 | }
8 |
--------------------------------------------------------------------------------
/test/ast_checks/named_arguments.txt:
--------------------------------------------------------------------------------
1 | //functionCallExpression[unaryExpression//identifier='b']//namedArgument[identifier='x']
2 | //functionCallExpression[unaryExpression//identifier='c']//namedArgument[identifier='x']
3 | //functionCallExpression[unaryExpression//identifier='c']//namedArgument[identifier='y']
4 | //functionCallExpression[unaryExpression//identifier='d']//namedTemplateArgument[identifier='a']
5 | //functionCallExpression[unaryExpression//identifier='d']//namedTemplateArgument[identifier='b']
6 |
--------------------------------------------------------------------------------
/test/ast_checks/oneLineFunctionDoc.d:
--------------------------------------------------------------------------------
1 | void fun() {} /// Test
2 |
--------------------------------------------------------------------------------
/test/ast_checks/oneLineFunctionDoc.txt:
--------------------------------------------------------------------------------
1 | //functionDeclaration/ddoc
2 |
--------------------------------------------------------------------------------
/test/ast_checks/scope_exit.d:
--------------------------------------------------------------------------------
1 | void foo() {
2 | scope (exit)
3 | int hi;
4 | }
5 |
6 | void bar() {
7 | // wtf does this even mean, why does this work with DMD?!
8 | int x = 1;
9 | switch (x)
10 | {
11 | case 1:
12 | break;
13 | case 2:
14 | break;
15 | scope (exit)
16 | default:
17 | foo();
18 | break;
19 | }
20 | }
--------------------------------------------------------------------------------
/test/ast_checks/scope_exit.txt:
--------------------------------------------------------------------------------
1 | ./module/declaration[1]/functionDeclaration/name[text()="foo"]
2 | ./module/declaration[1]/functionDeclaration//scopeGuardStatement/declarationOrStatement/declaration/variableDeclaration
3 | ./module/declaration[2]/functionDeclaration/name[text()="bar"]
4 | ./module/declaration[2]/functionDeclaration//switchStatement/statement//declarationOrStatement[1]/statement/caseStatement//intLiteral[text()="1"]
5 | ./module/declaration[2]/functionDeclaration//switchStatement/statement//declarationOrStatement[2]/statement/caseStatement//intLiteral[text()="2"]
6 | # scope (exit) becomes part of `case 2:`, which may be wrong, since DMD doesn't handle it like so, but the grammar is specified like so
7 | ./module/declaration[2]/functionDeclaration//switchStatement/statement//declarationOrStatement[2]/statement/caseStatement//scopeGuardStatement
8 |
--------------------------------------------------------------------------------
/test/ast_checks/shortenedFunction.d:
--------------------------------------------------------------------------------
1 | int abcdef(int a) => a * 3;
2 | @property propy() in(true || false) out(r; r == 4) => _x;
3 |
--------------------------------------------------------------------------------
/test/ast_checks/shortenedFunction.txt:
--------------------------------------------------------------------------------
1 | ./module/declaration[1]/functionDeclaration/name[text()="abcdef"]
2 | ./module/declaration[1]/functionDeclaration//functionBody/shortenedFunctionBody
3 | ./module/declaration[1]/functionDeclaration//functionBody/shortenedFunctionBody//mulExpression
4 | ./module/declaration[2]/functionDeclaration/name[text()="propy"]
5 | ./module/declaration[2]/functionDeclaration/storageClass/atAttribute/identifier[text()="property"]
6 | ./module/declaration[2]/functionDeclaration//functionBody/shortenedFunctionBody
7 | ./module/declaration[2]/functionDeclaration//inOutContractExpression[1]//inContractExpression
8 | ./module/declaration[2]/functionDeclaration//inOutContractExpression[2]//outContractExpression
9 |
--------------------------------------------------------------------------------
/test/ast_checks/switch_condition.d:
--------------------------------------------------------------------------------
1 | void a()
2 | {
3 | switch (auto line = readln)
4 | {
5 | default:
6 | line.strip;
7 | }
8 | }
9 |
10 | void b()
11 | {
12 | switch (scope line = readln)
13 | {
14 | default:
15 | line.strip;
16 | }
17 | }
18 |
19 | void c()
20 | {
21 | switch (const line = readln)
22 | {
23 | default:
24 | line.strip;
25 | }
26 | }
27 |
28 | void d()
29 | {
30 | switch (const inout string line = readln)
31 | {
32 | default:
33 | line.strip;
34 | }
35 | }
--------------------------------------------------------------------------------
/test/ast_checks/switch_condition.txt:
--------------------------------------------------------------------------------
1 | //functionDeclaration[name = 'a']//functionBody//switchStatement/condition/auto
2 | not(//functionDeclaration[name = 'a']//functionBody//switchStatement/condition/scope)
3 | //functionDeclaration[name = 'a']//functionBody//switchStatement/condition/identifier[text()='line']
4 | //functionDeclaration[name = 'a']//functionBody//switchStatement/condition/unaryExpression//identifier[text()='readln']
5 | //functionDeclaration[name = 'a']//functionBody//switchStatement/statement//defaultStatement//identifier[text()='line']
6 | //functionDeclaration[name = 'a']//functionBody//switchStatement/statement//defaultStatement//identifier[text()='strip']
7 | not(//functionDeclaration[name = 'b']//functionBody//switchStatement/condition/auto)
8 | //functionDeclaration[name = 'b']//functionBody//switchStatement/condition/scope
9 | //functionDeclaration[name = 'b']//functionBody//switchStatement/condition/identifier[text()='line']
10 | //functionDeclaration[name = 'b']//functionBody//switchStatement/condition/unaryExpression//identifier[text()='readln']
11 | //functionDeclaration[name = 'b']//functionBody//switchStatement/statement//defaultStatement//identifier[text()='line']
12 | //functionDeclaration[name = 'b']//functionBody//switchStatement/statement//defaultStatement//identifier[text()='strip']
13 | not(//functionDeclaration[name = 'c']//functionBody//switchStatement/condition/auto)
14 | not(//functionDeclaration[name = 'c']//functionBody//switchStatement/condition/scope)
15 | //functionDeclaration[name = 'c']//functionBody//switchStatement/condition/typeConstructor[text()='const']
16 | //functionDeclaration[name = 'c']//functionBody//switchStatement/condition/identifier[text()='line']
17 | //functionDeclaration[name = 'c']//functionBody//switchStatement/condition/unaryExpression//identifier[text()='readln']
18 | //functionDeclaration[name = 'c']//functionBody//switchStatement/statement//defaultStatement//identifier[text()='line']
19 | //functionDeclaration[name = 'c']//functionBody//switchStatement/statement//defaultStatement//identifier[text()='strip']
20 | not(//functionDeclaration[name = 'd']//functionBody//switchStatement/condition/auto)
21 | not(//functionDeclaration[name = 'd']//functionBody//switchStatement/condition/scope)
22 | //functionDeclaration[name = 'd']//functionBody//switchStatement/condition/typeConstructor[text()='const']
23 | //functionDeclaration[name = 'd']//functionBody//switchStatement/condition/typeConstructor[text()='inout']
24 | //functionDeclaration[name = 'd']//functionBody//switchStatement/condition/type[@pretty='string']
25 | //functionDeclaration[name = 'd']//functionBody//switchStatement/condition/identifier[text()='line']
26 | //functionDeclaration[name = 'd']//functionBody//switchStatement/condition/unaryExpression//identifier[text()='readln']
27 | //functionDeclaration[name = 'd']//functionBody//switchStatement/statement//defaultStatement//identifier[text()='line']
28 | //functionDeclaration[name = 'd']//functionBody//switchStatement/statement//defaultStatement//identifier[text()='strip']
29 |
--------------------------------------------------------------------------------
/test/ast_checks/throw_expressions.d:
--------------------------------------------------------------------------------
1 | int main()
2 | {
3 | foo(throw someThrowable, bar);
4 |
5 | return foo ? bar : throw new Exception("Hello, World!");
6 | }
7 |
--------------------------------------------------------------------------------
/test/ast_checks/throw_expressions.txt:
--------------------------------------------------------------------------------
1 | //functionDeclaration[name = 'main']
2 | //functionCallExpression/unaryExpression/primaryExpression/identifierOrTemplateInstance[identifier='foo']
3 | //functionCallExpression/arguments/namedArgumentList/namedArgument[1]/unaryExpression/throwExpression//*[identifier='someThrowable']
4 | //functionCallExpression/arguments/namedArgumentList/namedArgument[2]/unaryExpression/primaryExpression/*[identifier='bar']
5 | //ternaryExpression/*[1]//*[identifier='foo']
6 | //ternaryExpression/*[2]//*[identifier='bar']
7 | //ternaryExpression/*[3]/throwExpression/unaryExpression/newExpression/type[@pretty='Exception']
8 | //ternaryExpression/*[3]/throwExpression/unaryExpression/newExpression/arguments//stringLiteral
9 |
--------------------------------------------------------------------------------
/test/ast_checks/while_condition.d:
--------------------------------------------------------------------------------
1 | void a()
2 | {
3 | while (auto line = readln)
4 | {
5 | line.strip;
6 | }
7 | }
8 |
9 | void b()
10 | {
11 | while (scope line = readln)
12 | {
13 | line.strip;
14 | }
15 | }
16 |
17 | void c()
18 | {
19 | while (const line = readln)
20 | {
21 | line.strip;
22 | }
23 | }
24 |
25 | void d()
26 | {
27 | while (const inout string line = readln)
28 | {
29 | line.strip;
30 | }
31 | }
--------------------------------------------------------------------------------
/test/ast_checks/while_condition.txt:
--------------------------------------------------------------------------------
1 | //functionDeclaration[name = 'a']//functionBody//whileStatement/condition/auto
2 | not(//functionDeclaration[name = 'a']//functionBody//whileStatement/condition/scope)
3 | //functionDeclaration[name = 'a']//functionBody//whileStatement/condition/identifier[text()='line']
4 | //functionDeclaration[name = 'a']//functionBody//whileStatement/condition/unaryExpression//identifier[text()='readln']
5 | //functionDeclaration[name = 'a']//functionBody//whileStatement/declarationOrStatement//identifier[text()='line']
6 | //functionDeclaration[name = 'a']//functionBody//whileStatement/declarationOrStatement//identifier[text()='strip']
7 | not(//functionDeclaration[name = 'b']//functionBody//whileStatement/condition/auto)
8 | //functionDeclaration[name = 'b']//functionBody//whileStatement/condition/scope
9 | //functionDeclaration[name = 'b']//functionBody//whileStatement/condition/identifier[text()='line']
10 | //functionDeclaration[name = 'b']//functionBody//whileStatement/condition/unaryExpression//identifier[text()='readln']
11 | //functionDeclaration[name = 'b']//functionBody//whileStatement/declarationOrStatement//identifier[text()='line']
12 | //functionDeclaration[name = 'b']//functionBody//whileStatement/declarationOrStatement//identifier[text()='strip']
13 | not(//functionDeclaration[name = 'c']//functionBody//whileStatement/condition/auto)
14 | not(//functionDeclaration[name = 'c']//functionBody//whileStatement/condition/scope)
15 | //functionDeclaration[name = 'c']//functionBody//whileStatement/condition/typeConstructor[text()='const']
16 | //functionDeclaration[name = 'c']//functionBody//whileStatement/condition/identifier[text()='line']
17 | //functionDeclaration[name = 'c']//functionBody//whileStatement/condition/unaryExpression//identifier[text()='readln']
18 | //functionDeclaration[name = 'c']//functionBody//whileStatement/declarationOrStatement//identifier[text()='line']
19 | //functionDeclaration[name = 'c']//functionBody//whileStatement/declarationOrStatement//identifier[text()='strip']
20 | not(//functionDeclaration[name = 'd']//functionBody//whileStatement/condition/auto)
21 | not(//functionDeclaration[name = 'd']//functionBody//whileStatement/condition/scope)
22 | //functionDeclaration[name = 'd']//functionBody//whileStatement/condition/typeConstructor[text()='const']
23 | //functionDeclaration[name = 'd']//functionBody//whileStatement/condition/typeConstructor[text()='inout']
24 | //functionDeclaration[name = 'd']//functionBody//whileStatement/condition/type[@pretty='string']
25 | //functionDeclaration[name = 'd']//functionBody//whileStatement/condition/identifier[text()='line']
26 | //functionDeclaration[name = 'd']//functionBody//whileStatement/condition/unaryExpression//identifier[text()='readln']
27 | //functionDeclaration[name = 'd']//functionBody//whileStatement/declarationOrStatement//identifier[text()='line']
28 | //functionDeclaration[name = 'd']//functionBody//whileStatement/declarationOrStatement//identifier[text()='strip']
29 |
--------------------------------------------------------------------------------
/test/fail_files/aliases.d:
--------------------------------------------------------------------------------
1 | alias Fun(T T T) oops;
2 | alias Fun(T) = const(const()) oops(;
3 | alias Fun(T) = oops(;
4 | alias Fun(T) = int(oops(;
5 | alias Fun(T) == int(oops(;
6 |
7 |
--------------------------------------------------------------------------------
/test/fail_files/asm-gcc.d:
--------------------------------------------------------------------------------
1 | void main()
2 | {
3 | asm
4 | {
5 | "mov A B";
6 | ;
7 | "mov A B" : (a);
8 | "mov A B" : xx "rw" (a);
9 |
10 | "mov A B" : "rw" (a), ;
11 | "mov A B" : "rw" (a), : ;
12 | "mov A B" : "rw" (a) : , : ;
13 |
14 | "mov A B" : "rw" (a) : "r" (b) : this;
15 |
16 |
17 | "mov A B" : "rw" (a) : "r" (b) : "xxx" : 0;
18 |
19 | "mov A B" : "rw" (a) : "r" (b) : "xxx" : LEnd ;
20 | }
21 | }
--------------------------------------------------------------------------------
/test/fail_files/bad_asm.d:
--------------------------------------------------------------------------------
1 | void main(){ asm{ db cast(ubyte[]) "é"; } }
2 |
--------------------------------------------------------------------------------
/test/fail_files/bad_enum_1.d:
--------------------------------------------------------------------------------
1 | enum : float
2 | {
3 | int x = 10,
4 | }
5 |
--------------------------------------------------------------------------------
/test/fail_files/bad_enum_2.d:
--------------------------------------------------------------------------------
1 | enum : int;
2 |
--------------------------------------------------------------------------------
/test/fail_files/bad_enum_3.d:
--------------------------------------------------------------------------------
1 | enum A
2 | {
3 | a;
4 | }
5 |
--------------------------------------------------------------------------------
/test/fail_files/bad_enums.d:
--------------------------------------------------------------------------------
1 | enum : int;
2 |
--------------------------------------------------------------------------------
/test/fail_files/bad_parens.d:
--------------------------------------------------------------------------------
1 | unittest
2 | {
3 | ushort r = bswap(*(cast(ushort*) (bytes.ptr + index));
4 | }
5 |
--------------------------------------------------------------------------------
/test/fail_files/better_block_leave.d:
--------------------------------------------------------------------------------
1 | void foo()
2 | {
3 | c =
4 | }
5 |
6 | alias b this;
7 |
--------------------------------------------------------------------------------
/test/fail_files/contracts.d:
--------------------------------------------------------------------------------
1 | void foo() out(true) do {}
2 | void foo() out(;true, "false") out {} {}
3 | void foo() out(;true, "false",,) do {}
4 | void foo() out(
5 | void foo() out$
6 | void foo() out
7 | void foo() in(
8 | void foo() in$
9 | void foo() in
10 | void foo() { in }
11 | void foo() { out }
12 |
13 | struct Fpp{invariant()}
14 |
--------------------------------------------------------------------------------
/test/fail_files/dcd_tricks.d:
--------------------------------------------------------------------------------
1 | struct A { int a; }
2 | struct B { int b; }
3 |
4 | B node;
5 |
6 | void foo(A node)
7 | {
8 | void bar(B node)
9 | {
10 | node.
11 | }
12 | node.
13 | }
14 |
15 | node.
16 |
--------------------------------------------------------------------------------
/test/fail_files/ifConditions.d:
--------------------------------------------------------------------------------
1 | void foo()
2 | {
3 | if (auto const(Type)* data = call()){}
4 | if (const const a = call()){}
5 | if (auto auto a = call()){}
6 | if (Type!(0) = expr()){}
7 | if (Type!(0) i){}
8 | }
9 |
--------------------------------------------------------------------------------
/test/fail_files/incompleteStatement198_0.d:
--------------------------------------------------------------------------------
1 | a[{break
2 |
--------------------------------------------------------------------------------
/test/fail_files/incompleteStatement198_1.d:
--------------------------------------------------------------------------------
1 | a[{continue
2 |
--------------------------------------------------------------------------------
/test/fail_files/incompleteStatement198_2.d:
--------------------------------------------------------------------------------
1 | a[{do
2 |
--------------------------------------------------------------------------------
/test/fail_files/incompleteStatement198_3.d:
--------------------------------------------------------------------------------
1 | a[{for
2 |
--------------------------------------------------------------------------------
/test/fail_files/incompleteStatement198_4.d:
--------------------------------------------------------------------------------
1 | a[{foreach
2 |
--------------------------------------------------------------------------------
/test/fail_files/incompleteStatement198_5.d:
--------------------------------------------------------------------------------
1 | a[{if
2 |
--------------------------------------------------------------------------------
/test/fail_files/incompleteStatement198_6.d:
--------------------------------------------------------------------------------
1 | a[{synchronized
2 |
--------------------------------------------------------------------------------
/test/fail_files/incompleteStatement198_7.d:
--------------------------------------------------------------------------------
1 | a[{while
2 |
--------------------------------------------------------------------------------
/test/fail_files/issue0078.d:
--------------------------------------------------------------------------------
1 | {
2 | int foo();
3 | }
4 | {}
5 |
--------------------------------------------------------------------------------
/test/fail_files/issue0158.d:
--------------------------------------------------------------------------------
1 | T[++const() null @NotAnAssignExpr / immutable].Y y;
2 |
--------------------------------------------------------------------------------
/test/fail_files/issue0171.d:
--------------------------------------------------------------------------------
1 | class Foo{a}
2 | struct Foo{int}
--------------------------------------------------------------------------------
/test/fail_files/issue0176.d:
--------------------------------------------------------------------------------
1 | void foo(){ asm{ align 8); }}
--------------------------------------------------------------------------------
/test/fail_files/issue0179.d:
--------------------------------------------------------------------------------
1 | struct id { this() { foreach( a;1..2) { switch (id) goto
2 |
--------------------------------------------------------------------------------
/test/fail_files/issue0227.d:
--------------------------------------------------------------------------------
1 | static if (true)
2 | {
3 | template A()
4 | {
5 | // Err mssg Used to be gagged and parse OK
6 | enum a = 1
7 | enum b = 0;
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/test/fail_files/issue095.d:
--------------------------------------------------------------------------------
1 | enum A
2 | {
3 | a,,
4 | }
5 |
--------------------------------------------------------------------------------
/test/fail_files/issue245.d:
--------------------------------------------------------------------------------
1 | void f() {
2 | a[b
3 |
--------------------------------------------------------------------------------
/test/fail_files/issue459.d:
--------------------------------------------------------------------------------
1 | void main()
2 | {
3 | pragma(msg, "add a `" ~ A.stringof ~ "`for " ~ t.stringof");
4 | }
--------------------------------------------------------------------------------
/test/fail_files/killer.d:
--------------------------------------------------------------------------------
1 | // Evil block of invalid code that used to kill the parser
2 | unittest
3 | {
4 | a = b!(b!(b!(b!(b!(b!(b!(b!(b!(b!(b!(b!(b!(b!(b!(b!(b!(b!(b!(b!(b!(b!(b!(b!(b!(b!(b!(b!(b!(b!(b!(b!(b!(b!(b!(b!(b!(b!(b!(b!(
5 | occRange = [
6 | OteKaostk!(CRowjOLnk!("01","100x", RCOJE!(QTEURLE(7,132468,0)0)),
7 | OteKaostk!(CRowjOLnk!("01","210x", RCOJE!(QTEURLE(54,2641896,0)0)),
8 | OteKaostk!(CRowjOLnk!("01","220x", RCOJE!(QTEURLE(671,31636308,0)0)),
9 | OteKaostk!(CRowjOLnk!("01","564a", RCOJE!(QTEURLE(195,4825080,0)0)),
10 | OteKaostk!(CRowjOLnk!("01","564b", RCOJE!(QTEURLE(624,15223104,0)0)),
11 | OteKaostk!(CRowjOLnk!("01","XXXX", RCOJE!(QTEURLE(664,14892192,0)0)),
12 | OteKaostk!(CRowjOLnk!("04","0", RCOJE!(QTEURLE(46593.000002000015,1248158357.3444164,0)))),
13 | OteKaostk!(CRowjOLnk!("04","210x", RCOJE!(QTEURLE(8,254208,0)0)),
14 | OteKaostk!(CRowjOLnk!("04","220x", RCOJE!(QTEURLE(157,6447048,0)0)),
15 | OteKaostk!(CRowjOLnk!("04","564a", RCOJE!(QTEURLE(85,2196060,0)0)),
16 | OteKaostk!(CRowjOLnk!("04","564b", RCOJE!(QTEURLE(105,2465820,0)0)),
17 | OteKaostk!(CRowjOLnk!("04","XXXX", RCOJE!(QTEURLE(217,4291392,0)0)),
18 | OteKaostk!(CRowjOLnk!("971","0", RCOJE!(QTEURLE(114821.00000200002,3605356322.8689,0)))),
19 | OteKaostk!(CRowjOLnk!("971","100x", RCOJE!(QTEURLE(0.117114,3260.45376,1)))),
20 | OteKaostk!(CRowjOLnk!("971","210x", RCOJE!(QTEURLE(18,509328,0)0)),
21 | OteKaostk!(CRowjOLnk!("971","220x", RCOJE!(QTEURLE(334,13999944,0)0)),
22 | OteKaostk!(CRowjOLnk!("971","564a", RCOJE!(QTEURLE(95,2471520,0)0)),
23 | OteKaostk!(CRowjOLnk!("971","564b", RCOJE!(QTEURLE(493,11299560,0)0)),
24 | OteKaostk!(CRowjOLnk!("971","XXXX", RCOJE!(QTEURLE(885,23098500,0)0))
25 | ];
26 | }
27 |
--------------------------------------------------------------------------------
/test/fail_files/killer2.d:
--------------------------------------------------------------------------------
1 | unittest
2 | {
3 | version (53056)[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
4 | union {}
5 | Klse
6 | gosh ÿ 'A+ SPL : tape];
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/test/fail_files/misc_coverage.d:
--------------------------------------------------------------------------------
1 | module misc_coverage;
2 |
3 | uint a[*!*];
4 |
5 | const extern([Zzzz]) a = 8;
6 |
7 | auto a(8) = 8;
8 |
9 | void foo()
10 | {
11 | foreach(a;z) break ++ZzZ--;
12 | }
13 |
14 | class Base : List, ++ZzZ--, Of, Base {}
15 |
16 | void foo()
17 | {
18 | switch(foo)
19 | {
20 | case low: .. case high ++ZzZ--;
21 | case arg,list ++ZzZ--;
22 | default ++ZzZ--;
23 | }
24 | switch(foo)
25 | {
26 | case ++
27 | }
28 | switch(foo)
29 | {
30 | case one: final a;
31 | }
32 | switch(foo)
33 | {
34 | case one: static a;
35 | }
36 | }
37 |
38 | enum E
39 | {
40 | a,
41 | b = ++ZzZ[*!*]ZzZ--;
42 | }
43 |
44 | alias a = 0, b = a;
45 |
46 | version ++ZzZ--;
47 |
48 | void foo()
49 | {
50 | for (i; cond(); i++) }
51 | }
52 |
53 | alias @++ const void null;
54 |
55 | alias int fun() @++;
56 |
57 | alias T = @++ U;
58 |
59 | alias T = extern ++ZzZ-- U;
60 |
61 | int[8] a = [+o+,+o+];
62 |
63 | import ++;
64 |
65 | __vector( a;
66 | __vector) a;
67 | __vector() a;
68 | __vector(__vector) a;
69 |
70 | class A : SomeDynarray[] {}
71 |
72 | //keep at the end
73 | void foo(){a +=
74 |
--------------------------------------------------------------------------------
/test/fail_files/pragma_exp_bound.d:
--------------------------------------------------------------------------------
1 | void main() {
2 | pragma(msg F
3 | }
4 |
--------------------------------------------------------------------------------
/test/fail_files/shortenedMethod.d:
--------------------------------------------------------------------------------
1 | int bar() in { assert(true); } => 1;
2 |
--------------------------------------------------------------------------------
/test/fail_files/sillyparse.d:
--------------------------------------------------------------------------------
1 | void main()
2 | {
3 | if ()
4 | }
5 |
6 | void main(@) int);
7 |
--------------------------------------------------------------------------------
/test/fail_files/throwattribute.d:
--------------------------------------------------------------------------------
1 | void doThings(throw int x)
2 | {
3 | }
4 |
--------------------------------------------------------------------------------
/test/fail_files/varargs-attributes.d:
--------------------------------------------------------------------------------
1 | int printf(const(char)*, ref ...);
2 |
--------------------------------------------------------------------------------
/test/fail_files/with_better_dcd.d:
--------------------------------------------------------------------------------
1 | module a;
2 | void foo(){with(A)}
3 |
--------------------------------------------------------------------------------
/test/fuzzer.d:
--------------------------------------------------------------------------------
1 | import dparse.lexer;
2 | import std.random;
3 | import std.stdio;
4 |
5 | void main()
6 | {
7 | foreach (i; 0 .. 100)
8 | writeRandomToken();
9 | }
10 |
11 | void writeRandomToken()
12 | {
13 | again:
14 | IdType i = cast(IdType) uniform(1, IdType.max);
15 | switch (i)
16 | {
17 | case tok!"int":
18 | case tok!"uint":
19 | case tok!"double":
20 | case tok!"idouble":
21 | case tok!"float":
22 | case tok!"ifloat":
23 | case tok!"short":
24 | case tok!"ushort":
25 | case tok!"long":
26 | case tok!"ulong":
27 | case tok!"char":
28 | case tok!"wchar":
29 | case tok!"dchar":
30 | case tok!"bool":
31 | case tok!"void":
32 | case tok!"cent":
33 | case tok!"ucent":
34 | case tok!"real":
35 | case tok!"ireal":
36 | case tok!"byte":
37 | case tok!"ubyte":
38 | case tok!"cdouble":
39 | case tok!"cfloat":
40 | case tok!"creal":
41 | case tok!",":
42 | case tok!".":
43 | case tok!"..":
44 | case tok!"...":
45 | case tok!"/":
46 | case tok!"/=":
47 | case tok!"!":
48 | case tok!"!<":
49 | case tok!"!<=":
50 | case tok!"!<>":
51 | case tok!"!<>=":
52 | case tok!"!=":
53 | case tok!"!>":
54 | case tok!"!>=":
55 | case tok!"$":
56 | case tok!"%":
57 | case tok!"%=":
58 | case tok!"&":
59 | case tok!"&&":
60 | case tok!"&=":
61 | case tok!"(":
62 | case tok!")":
63 | case tok!"*":
64 | case tok!"*=":
65 | case tok!"+":
66 | case tok!"++":
67 | case tok!"+=":
68 | case tok!"-":
69 | case tok!"--":
70 | case tok!"-=":
71 | case tok!":":
72 | case tok!";":
73 | case tok!"<":
74 | case tok!"<<":
75 | case tok!"<<=":
76 | case tok!"<=":
77 | case tok!"<>":
78 | case tok!"<>=":
79 | case tok!"=":
80 | case tok!"==":
81 | case tok!"=>":
82 | case tok!">":
83 | case tok!">=":
84 | case tok!">>":
85 | case tok!">>=":
86 | case tok!">>>":
87 | case tok!">>>=":
88 | case tok!"?":
89 | case tok!"@":
90 | case tok!"[":
91 | case tok!"]":
92 | case tok!"^":
93 | case tok!"^=":
94 | case tok!"^^":
95 | case tok!"^^=":
96 | case tok!"{":
97 | case tok!"|":
98 | case tok!"|=":
99 | case tok!"||":
100 | case tok!"}":
101 | case tok!"~":
102 | case tok!"~=":
103 | case tok!"abstract":
104 | case tok!"alias":
105 | case tok!"align":
106 | case tok!"asm":
107 | case tok!"assert":
108 | case tok!"auto":
109 | case tok!"break":
110 | case tok!"case":
111 | case tok!"cast":
112 | case tok!"const":
113 | case tok!"continue":
114 | case tok!"debug":
115 | case tok!"default":
116 | case tok!"delegate":
117 | case tok!"delete":
118 | case tok!"deprecated":
119 | case tok!"do":
120 | case tok!"else":
121 | case tok!"enum":
122 | case tok!"extern":
123 | case tok!"false":
124 | case tok!"final":
125 | case tok!"finally":
126 | case tok!"function":
127 | case tok!"goto":
128 | case tok!"immutable":
129 | case tok!"import":
130 | case tok!"in":
131 | case tok!"inout":
132 | case tok!"invariant":
133 | case tok!"is":
134 | case tok!"lazy":
135 | case tok!"macro":
136 | case tok!"mixin":
137 | case tok!"module":
138 | case tok!"new":
139 | case tok!"nothrow":
140 | case tok!"null":
141 | case tok!"out":
142 | case tok!"override":
143 | case tok!"pragma":
144 | case tok!"pure":
145 | case tok!"ref":
146 | case tok!"return":
147 | case tok!"scope":
148 | case tok!"shared":
149 | case tok!"static":
150 | case tok!"super":
151 | case tok!"template":
152 | case tok!"this":
153 | case tok!"throw":
154 | case tok!"true":
155 | case tok!"try":
156 | case tok!"typedef":
157 | case tok!"typeid":
158 | case tok!"typeof":
159 | case tok!"unittest":
160 | case tok!"version":
161 | case tok!"__DATE__":
162 | case tok!"__EOF__":
163 | case tok!"__FILE__":
164 | case tok!"__FUNCTION__":
165 | case tok!"__gshared":
166 | case tok!"__LINE__":
167 | case tok!"__MODULE__":
168 | case tok!"__parameters":
169 | case tok!"__PRETTY_FUNCTION__":
170 | case tok!"__TIME__":
171 | case tok!"__TIMESTAMP__":
172 | case tok!"__traits":
173 | case tok!"__vector":
174 | case tok!"__VENDOR__":
175 | case tok!"__VERSION__":
176 | case tok!"export":
177 | case tok!"package":
178 | case tok!"private":
179 | case tok!"public":
180 | case tok!"protected":
181 | case tok!"synchronized":
182 | write(str(i), " ");
183 | break;
184 | case tok!"class":
185 | case tok!"interface":
186 | case tok!"union":
187 | case tok!"struct":
188 | write(str(i), " ");
189 | if (uniform(0, 9) > 3)
190 | write("ident ");
191 | break;
192 | case tok!"switch":
193 | case tok!"if":
194 | case tok!"for":
195 | case tok!"foreach":
196 | case tok!"foreach_reverse":
197 | case tok!"while":
198 | case tok!"with":
199 | case tok!"catch":
200 | write(str(i), " ");
201 | if (uniform(0, 9) > 3)
202 | write("(");
203 | break;
204 | case tok!"doubleLiteral":
205 | write("1.0 ");
206 | break;
207 | case tok!"floatLiteral":
208 | write("1.0f ");
209 | break;
210 | case tok!"intLiteral":
211 | write("1 ");
212 | break;
213 | case tok!"longLiteral":
214 | write("1L ");
215 | break;
216 | case tok!"uintLiteral":
217 | write("1U ");
218 | break;
219 | case tok!"ulongLiteral":
220 | write("1UL ");
221 | break;
222 | case tok!"idoubleLiteral":
223 | case tok!"ifloatLiteral":
224 | case tok!"realLiteral":
225 | case tok!"irealLiteral":
226 | break;
227 | case tok!"dstringLiteral":
228 | case tok!"stringLiteral":
229 | case tok!"wstringLiteral":
230 | writeStringLiteral();
231 | break;
232 | case tok!"identifier":
233 | write("ident ");
234 | break;
235 | default:
236 | goto again;
237 | }
238 | }
239 |
240 | void writeStringLiteral()
241 | {
242 | switch (uniform(0, 6))
243 | {
244 | case 0: writeDoubleQuoteStringLiteral(); break;
245 | case 1: writeHeredocStringLiteral(); break;
246 | case 2: writeDelimitedStringLiteral(); break;
247 | case 3: writeBacktickStringLiteral(); break;
248 | case 4: writeRDoubleQuoteStringLiteral(); break;
249 | case 5: writeCharLiteral(); break;
250 | default: break;
251 | }
252 | }
253 |
254 | void writeDoubleQuoteStringLiteral()
255 | {
256 | write('"');
257 | auto length = uniform(0, 30);
258 | foreach (i; 0 .. length)
259 | {
260 | again:
261 | auto j = uniform(0, 128);
262 | switch (j)
263 | {
264 | case 0: .. case 6: goto again;
265 | case 7: write(`\a`); break;
266 | case 8: write(`\b`); break;
267 | case 9: write(`\t`); break;
268 | case 10: write(`\n`); break;
269 | case 11: write(`\v`); break;
270 | case 12: write(`\f`); break;
271 | case 13: write(`\r`); break;
272 | case 14: .. case 31: goto again;
273 | case 32: .. case 33:
274 | case 35: .. case 91:
275 | case 93: .. case 176:
276 | write(cast(char) j);
277 | break;
278 | case 34: write(`\"`); break;
279 | case 92: write(`\\`); break;
280 | default: goto again;
281 | }
282 | }
283 | write('"');
284 | write([' ', 'c', 'w', 'd'][uniform(0, 4)]);
285 | write(' ');
286 | }
287 |
288 | void writeHeredocStringLiteral()
289 | {
290 |
291 | }
292 |
293 | void writeDelimitedStringLiteral()
294 | {
295 |
296 | }
297 |
298 | void writeBacktickStringLiteral()
299 | {
300 |
301 | }
302 |
303 | void writeRDoubleQuoteStringLiteral()
304 | {
305 |
306 | }
307 |
308 | void writeCharLiteral()
309 | {
310 |
311 | }
312 |
--------------------------------------------------------------------------------
/test/fuzzer.sh:
--------------------------------------------------------------------------------
1 | TOTALRUNS=10000
2 |
3 | FILES=$(find ../experimental_allocator/src/ ../src/dparse/ ../src/std/experimental/ -name "*.d")
4 |
5 | echo "Compiling fuzzer"
6 | dmd fuzzer.d -I../src/ ${FILES} || exit 1
7 | echo "Done"
8 | echo "Compiling parser"
9 | dmd -O -inline -g tester.d -I../src/ ${FILES} || exit 1
10 | echo "Done"
11 | printf " "
12 | for i in $(seq $TOTALRUNS); do
13 | printf "\b\b\b\b\b\b\b\b\b\b\b"
14 | printf "%5d/%5d" $i $TOTALRUNS
15 | ./fuzzer > tokens.txt
16 | ./tester tokens.txt > output.txt 2>&1
17 | if [ $? -eq 139 ]; then echo "Segfaulted..."; sed -e "s/ /\\n/g" tokens.txt > tokens-newlines.txt; exit 1; fi
18 | grep ception output.txt && sed -e "s/ /\\n/g" tokens.txt > tokens-newlines.txt && exit 1;
19 | done
20 | printf "\n"
21 |
--------------------------------------------------------------------------------
/test/pass_files/ae.d:
--------------------------------------------------------------------------------
1 | void httpRequest(HttpRequest request, void delegate(Data) resultHandler, void delegate(string) errorHandler, int redirectCount = 0)
2 | {
3 |
4 | void responseHandler(HttpResponse response, string disconnectReason)
5 | {
6 | if (!response)
7 | if (errorHandler)
8 | errorHandler(disconnectReason);
9 | else
10 | throw new Exception(disconnectReason);
11 | else
12 | if (response.status >= 300 && response.status < 400 && "Location" in response.headers)
13 | {
14 | if (redirectCount == 15)
15 | throw new Exception("HTTP redirect loop: " ~ request.url);
16 | request.resource = applyRelativeURL(request.url, response.headers["Location"]);
17 | if (response.status == HttpStatusCode.SeeOther)
18 | {
19 | request.method = "GET";
20 | request.data = null;
21 | }
22 | httpRequest(request, resultHandler, errorHandler, redirectCount+1);
23 | }
24 | else
25 | if (errorHandler)
26 | try
27 | resultHandler(response.getContent());
28 | catch (Exception e)
29 | errorHandler(e.msg);
30 | else
31 | resultHandler(response.getContent());
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/test/pass_files/alias_assign.d:
--------------------------------------------------------------------------------
1 | template T(X)
2 | {
3 | alias A = int;
4 | A = X;
5 | struct B
6 | {
7 | A t;
8 | }
9 | }
10 |
11 | void fun()
12 | {
13 | auto b = T!float.B();
14 | }
15 |
16 | // https://github.com/dlang/phobos/pull/8033
17 | template EraseAll(args...)
18 | if (args.length >= 1)
19 | {
20 | alias EraseAll = AliasSeq!();
21 | static foreach (arg; args[1 .. $])
22 | static if (!isSame!(args[0], arg))
23 | EraseAll = AliasSeq!(EraseAll, arg);
24 | }
25 |
26 | // https://github.com/dlang/phobos/pull/8034
27 | template NoDuplicates(args...)
28 | {
29 | alias NoDuplicates = AliasSeq!();
30 | static foreach (arg; args)
31 | NoDuplicates = AppendUnique!(NoDuplicates, arg);
32 | }
33 |
34 | // https://github.com/dlang/phobos/pull/8036
35 | template ReplaceAll(args...)
36 | {
37 | alias ReplaceAll = AliasSeq!();
38 | static foreach (arg; args[2 .. $])
39 | {
40 | static if (isSame!(args[0], arg))
41 | ReplaceAll = AliasSeq!(ReplaceAll, args[1]);
42 | else
43 | ReplaceAll = AliasSeq!(ReplaceAll, arg);
44 | }
45 | }
46 |
47 | // https://github.com/dlang/phobos/pull/8037
48 | template Reverse(args...)
49 | {
50 | alias Reverse = AliasSeq!();
51 | static foreach_reverse (arg; args)
52 | Reverse = AliasSeq!(Reverse, arg);
53 | }
54 |
55 | // https://github.com/dlang/phobos/pull/8038
56 | template MostDerived(T, TList...)
57 | {
58 | import std.traits : Select;
59 | alias MostDerived = T;
60 | static foreach (U; TList)
61 | MostDerived = Select!(is(U : MostDerived), U, MostDerived);
62 | }
63 |
64 | // https://github.com/dlang/phobos/pull/8044
65 | template Repeat(size_t n, items...)
66 | {
67 | static if (n == 0)
68 | {
69 | alias Repeat = AliasSeq!();
70 | }
71 | else
72 | {
73 | alias Repeat = items;
74 | enum log2n =
75 | {
76 | uint result = 0;
77 | auto x = n;
78 | while (x >>= 1)
79 | ++result;
80 | return result;
81 | }();
82 | static foreach (i; 0 .. log2n)
83 | {
84 | Repeat = AliasSeq!(Repeat, Repeat);
85 | }
86 | Repeat = AliasSeq!(Repeat, Repeat!(n - (1u << log2n), items));
87 | }
88 | }
89 |
90 | // https://github.com/dlang/phobos/pull/8047
91 | template Stride(int stepSize, Args...)
92 | if (stepSize != 0)
93 | {
94 | alias Stride = AliasSeq!();
95 | static if (stepSize > 0)
96 | {
97 | static foreach (i; 0 .. (Args.length + stepSize - 1) / stepSize)
98 | Stride = AliasSeq!(Stride, Args[i * stepSize]);
99 | }
100 | else
101 | {
102 | static foreach (i; 0 .. (Args.length - stepSize - 1) / -stepSize)
103 | Stride = AliasSeq!(Stride, Args[$ - 1 + i * stepSize]);
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/test/pass_files/aliases.d:
--------------------------------------------------------------------------------
1 | alias a = b;
2 | alias b a;
3 | alias int b;
4 | alias int b, c, d, e;
5 | alias c = int;
6 | alias x = y, w = z;
7 | alias const immutable int constInt;
8 | alias shared(int) sharedInt;
9 | alias a(b) = c;
10 | alias a(b) = c, d = e, f = g;
11 | alias a(b) = const c, d = int;
12 | alias a(b) = const c, d = double[int[string]];
13 | alias a = c.d.e;
14 | struct S
15 | {
16 | int a;
17 | alias a this;
18 | }
19 | class Foo
20 | {
21 | void bar()
22 | {
23 | alias self = this;
24 | }
25 | }
26 |
27 | // C-style aliases
28 | alias int GetterType() @property;
29 | alias int SetterType(int) @property;
30 | alias string SetterType(int, string) @nogc;
31 | alias string SetterType(int, string) @safe;
32 | alias int F1();
33 | alias @property int F2();
34 | alias string F3();
35 | alias nothrow @trusted uint F4();
36 | alias int F5(Object);
37 | alias bool F6(Object);
38 | alias int F1();
39 | alias int F2() pure nothrow;
40 | alias int F3() @safe;
41 | alias int F23() @safe pure nothrow;
42 |
43 | // return type covariance
44 | alias long F4();
45 | class C {}
46 | class D : C {}
47 | alias C F5();
48 | alias D F6();
49 | alias typeof(null) F7();
50 | alias int[] F8();
51 | alias int* F9();
52 |
53 | // variadic type equality
54 | alias int F10(int);
55 | alias int F11(int...);
56 | alias int F12(int, ...);
57 |
58 | // linkage equality
59 | alias extern(C) int F13(int);
60 | alias extern(D) int F14(int);
61 | alias extern(Windows) int F15(int);
62 |
63 | // ref & @property equality
64 | alias int F16(int);
65 | alias ref int F17(int);
66 | alias @property int F18(int);
67 |
68 | // function types with '='
69 | alias Fun1(T) = T(T t) @safe;
70 | alias Fun2 = void(int,int,int) pure nothrow;
71 | alias Fun3 = const void(int,int,int) @trusted;
72 | alias Fun4(T...) = shared const(Foo!Bar)(T t) const;
73 |
--------------------------------------------------------------------------------
/test/pass_files/asm-gcc.d:
--------------------------------------------------------------------------------
1 | module asm_gcc;
2 |
3 | ref T store(T)();
4 |
5 | enum asm1 = "mov %0, %0;";
6 | string asm2(int i) { return "mov %0, %0;"; }
7 |
8 | void main()
9 | {
10 | int var1, var2, var3, var4;
11 | int* ptr1;
12 |
13 | asm
14 | {
15 | // Some tests as found in dmd's iasmgcc.d
16 | "nop";
17 | asm1;
18 | asm2(1);
19 | mixin(`"repne"`, `~ "scasb"`);
20 |
21 | // GCC examples
22 | "notl %[iov]" : [iov] "=r" (var1) : "0" (var2) ;
23 | ;
24 | "mov %1, %0\n\t"
25 | "add $1, %0" : "=r" (var1) : "r" (var2) ;
26 |
27 | // DRuntime
28 | "cpuid" : "=a" (var1), "=c" (var2), "=d" (var3) : "a" (0x8000_0006) : "ebx" ;
29 |
30 | // Deprecated: Missing parens
31 | "cpuid" : "=a" var1, "=b" var2 : "a" 0x8000_001E : "ecx", "edx";
32 |
33 | "str x29, %0" : "=m" (var1) ;
34 |
35 | "mrs %0, cntvct_el0" : "=r" *ptr1;
36 |
37 | "mov %1, %0" : : "r" (var2) : "cc" : LCarry ;
38 | "mov %0, %0" : : "r" (var2) : "cc" ;
39 |
40 | "mov %0, %0" : "=r" (*ptr1) : "r" (store!int = 1) : "cc";
41 | }
42 |
43 | LCarry:
44 | asm /*goto*/ {
45 | "btl %1, %0\n\t"
46 | "jc %l2"
47 | : /* No outputs. */
48 | : "r" (var1), "r" (var2)
49 | : "cc"
50 | : LCarry
51 | ;
52 | }
53 |
54 | asm {
55 | ;
56 | ;
57 | "jmp LCarry" : : : : LCarry ;
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/test/pass_files/asm.d:
--------------------------------------------------------------------------------
1 | module hasasm;
2 |
3 | void doStuff()
4 | {
5 | asm nothrow @safe @nogc
6 | {
7 | xor RAX, RAX;
8 | }
9 | asm
10 | {
11 | mov EAX, 10u;
12 | mov RAX, 10UL;
13 | mov RAX, a;
14 | ret;
15 | mov RAX, a[100];
16 | mov RAX, [a + 100];
17 | mov RAX, a ? b : c;
18 | align 100;
19 | align whatever;
20 | label:
21 | mov RAX, RCX;
22 | db "test";
23 | mov RAX, 100;
24 | mov RAX, 10.0f;
25 | mov RAX, 10.0;
26 | mov ST(0), 1;
27 | add near ptr [EAX], 3;
28 | add byte ptr [EAX], 3;
29 | mov RAX, a.b.c;
30 | mov RAX, ~a;
31 | mov RAX, !a;
32 | mov RAX, -a;
33 | mov RAX, +a;
34 | mov RAX, offsetof a;
35 | mov EAX, FS:4;
36 | mov EAX, FS:CL;
37 | push dword ptr FS:[0];
38 | jge short L_largepositive;
39 | lea EDX,[ECX][ECX*8];
40 | in AL,6;
41 | out AL,6;
42 | int 3;
43 | }
44 | asm
45 | {
46 | align 4 ;
47 | LABEL: ;
48 | ;
49 |
50 | mov EAX, this;
51 | mov ECX, __LOCAL_SIZE;
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/test/pass_files/attributes.d:
--------------------------------------------------------------------------------
1 | extern int d;
2 | @uda int e;
3 | @("uda") int f;
4 | @uda(42) int g;
5 | @uda() int h;
6 | @uda!() int i;
7 | @uda!(int) int j;
8 | private int k;
9 | public int l;
10 | protected int m;
11 | shared int n;
12 | export int o;
13 | pragma(whatever) int p;
14 | @uda:
15 | public:
16 | int q;
17 | deprecated double r;
18 | deprecated("NEVAR USE THIS") double s;
19 | deprecated("NEVAR USE THIS" ~ " IT AM BAD") double s;
20 | @templateName!int(123) int t;
21 | @templateName(123) int u;
22 | extern(System) int v;
23 | align int a;
24 | align(8) int b;
25 | align(8 + c) int c;
26 |
--------------------------------------------------------------------------------
/test/pass_files/auto_declarations.d:
--------------------------------------------------------------------------------
1 | package(std)
2 | ref intersect()
3 | {
4 | }
5 |
6 | package(std)
7 | auto intersect()
8 | {
9 | }
10 |
11 | package(std)
12 | const intersect()
13 | {
14 | }
15 | public static immutable ctRegex(alias pattern, alias flags=[]) = ctRegexImpl!(pattern, flags).nr;
16 | struct S(T) { static T t = 0; }
17 | immutable a(A) = S!A.t, b(B) = S!B.t;
18 | const c(C) = S!C.t, d = S!int.t;
19 |
--------------------------------------------------------------------------------
/test/pass_files/bitfields.d:
--------------------------------------------------------------------------------
1 | struct B
2 | {
3 | int x:3, y:2;
4 | }
5 |
--------------------------------------------------------------------------------
/test/pass_files/body_as_ident.d:
--------------------------------------------------------------------------------
1 | void body()
2 | in
3 | {
4 | }
5 | body
6 | {
7 | Corpulence body;
8 | alias b = body;
9 | }
10 |
11 | struct Foo(Body)
12 | {
13 | static if (is(Body)){}
14 | }
15 |
16 | enum Body;
17 |
18 | @Body void foo();
19 |
--------------------------------------------------------------------------------
/test/pass_files/casts.d:
--------------------------------------------------------------------------------
1 | auto a = cast() b;
2 | auto a = cast(const) b;
3 | auto a = cast(const shared) b;
4 | auto a = cast(immutable) b;
5 | auto a = cast(inout) b;
6 | auto a = cast(inout shared) b;
7 | auto a = cast(shared) b;
8 | auto a = cast(shared const) b;
9 | auto a = cast(shared inout) b;
10 | auto a = cast(shared inout int*) b;
11 | auto a = cast(int) b;
12 |
--------------------------------------------------------------------------------
/test/pass_files/classes.d:
--------------------------------------------------------------------------------
1 | class A;
2 | class B {}
3 | class C : B {}
4 | class C : TList[0] {}
5 | class C : TList[0].TList[0].Prop {}
6 | class D(T) if (Z) : B {}
7 | class E(T) : B if (Z) {}
8 | class F(T);
9 | class G(T) if (Z);
10 | class H : public A {}
11 | class H : typeof(A).B {}
12 | class I { int x; alias y = this.x; }
13 | class J : K { int x; alias y = super.x; }
14 |
--------------------------------------------------------------------------------
/test/pass_files/compiler_2_104_0.d:
--------------------------------------------------------------------------------
1 | @int void f();
2 |
3 | @"my test" unittest
4 | {
5 |
6 | }
7 |
--------------------------------------------------------------------------------
/test/pass_files/constructors_destructors.d:
--------------------------------------------------------------------------------
1 | static this() {}
2 | shared static this() {}
3 | static ~this() {}
4 | shared static ~this() {}
5 |
6 | static this() @system {}
7 | shared static this() @system {}
8 | static ~this() @system {}
9 | shared static ~this() @system {}
10 |
11 | static this();
12 | shared static this();
13 | static ~this();
14 | shared static ~this();
15 |
16 | static this() @system;
17 | shared static this() @system;
18 | static ~this() @system;
19 | shared static ~this() @system;
20 |
21 | struct SomeStruct
22 | {
23 | @disable this();
24 | shared this() {}
25 | this() {}
26 | this(int a) {}
27 | ~this() {}
28 | shared ~this() {}
29 | }
30 |
--------------------------------------------------------------------------------
/test/pass_files/crazy1.d:
--------------------------------------------------------------------------------
1 | package mixin template phone() if (new class ulong {
2 | import omg = ouchMyFinger.pineapple;
3 | }
4 | & knife!__DATE__(phone is +33890, 'G', raspberry !is ~76988.5, cast (shared const) -import (assert ('q'))) &= 's' || raspberry)
5 | {
6 | import phone = aaargh.grape.aaargh : ouchMyFinger;
7 | unittest
8 | {
9 | }
10 | __gshared static ~this()
11 | in
12 | {
13 | asm
14 | {
15 | }
16 |
17 | }
18 | out (aaargh)
19 | {
20 | }
21 | body
22 | {
23 | immutable uint(assert (--32106[shared(creal).apple], omg));
24 | }
25 | }
26 |
27 | alias eggplant() = const creal;
28 | enum pineapple() = 100;
29 | enum remote(boom)(...) {}
30 |
31 | align tape()(bool* boom...)
32 | {
33 | }
34 |
35 | debug:
36 | version = 20571;
37 |
38 | enum apple(...) @carton
39 | {
40 | }
41 |
42 | creal[] eggplant = {
43 | return;
44 | }
45 | ;
46 |
47 | immutable drywall.orange plastic = {
48 | __VENDOR__;
49 | }
50 | ;
51 |
52 | synchronized gosh(omg..., boom)()
53 | {
54 | }
55 |
56 | enum phone(alias shared short acrylic : immutable ireal* = 78419) = 'P';
57 |
58 | unittest
59 | {
60 | version (53056)
61 | union {}
62 | else
63 | gosh %= 'A';
64 | }
65 |
66 | @carton template nanny_ogg(eggplant, orange) if (33586.8 !in (uint).knife)
67 | {
68 | }
69 |
70 | override scope class discworld(alias angelic.cocaine.items portal)
71 | {
72 | }
73 |
74 | shared static ~this()
75 | {
76 | synchronized
77 | if (auto boom = knife)
78 | unittest
79 | {
80 | }
81 |
82 | }
83 |
84 | abstract alias aaargh(alias grape knife : byte = &52133.9) = double;
85 |
86 | unittest
87 | {
88 | version (88876)
89 | default:
90 | synchronized invariant
91 | {
92 | switch ("migrane" ^^ new class ubyte {
93 | enum : ireal
94 | {
95 | zelda = 4488, carton = delete 27010.9
96 | }
97 | enum discworld;
98 | })
99 | remote == --'K';
100 | }
101 | else
102 | static plastic = void, slash = {};
103 |
104 | }
105 |
106 | package class acrylic : cfloat
107 | {
108 | override this(this omg : .pineapple!85919.grape = ulong)(ulong[&34679 = knife .. 48093] emerge..., ...)shared
109 | {
110 | asm
111 | {
112 | ds word 79944 < ~ + + byte ptr word ptr 67048.8 + 13589.6 & orange.knife.items >= ~real ptr zelda >= angelic ^ 50597.6;
113 | ds [remote.drywall ? + SPL : tape : 0];
114 | }
115 | }
116 | }
117 |
118 | deprecated ("apple") unittest
119 | {
120 | debug:
121 | union {}
122 | }
123 |
124 | unittest
125 | {
126 | const(knife!__DATE__.grape).boom == 'N';
127 | const(int).init == 0;
128 | }
129 |
130 | unittest
131 | {
132 | inout .phone!__VENDOR__ remote(wchar ...);
133 | }
134 |
135 | unittest
136 | {
137 | foreach (
138 | shared typeof (return).raspberry.apple!__FILE__* omg, shared discworld;
139 | 'W' ? *nanny_ogg, 89077 : 'D' ? 46910[emerge, 93690.9, 'f'] : ++"plastic")
140 | (ubyte).slash--.ouchMyFinger != *"zelda" >>>= ++zelda;
141 | }
142 |
143 | unittest
144 | {
145 | synchronized slash(shared creal acrylic : *49515)() if (cast (shared uint) "pineapple")
146 | {
147 | }
148 |
149 | do
150 | switch (__traits(gosh, pineapple) !in 84501)
151 | default:
152 | struct acrylic
153 | {
154 | auto ouchMyFinger = 'F', discworld = void;
155 | }
156 | while (__VENDOR__);
157 | }
158 | debug phone.tape knife = { immutable freedom = void, aaargh = void; };
159 |
160 | unittest
161 | {
162 | foreach_reverse (shared .gosh.eggplant!aaargh.discworld angelic;
163 | new real[*__TIME__ !is ~8633][__DATE__])
164 | {
165 | void plastic = void;
166 | }
167 | }
168 |
169 |
170 |
--------------------------------------------------------------------------------
/test/pass_files/declarations.d:
--------------------------------------------------------------------------------
1 | deprecated("this code is older than the dinosaurs") module declarations;
2 | int a;
3 | int[] a;
4 | int[string] a;
5 | int a, b;
6 | int a = .b.c;
7 | a.b c = d;
8 | .a.b c = d;
9 | typeof(a) c = d;
10 | typeof(a).b c = d;
11 | align int a;
12 | align(8) int a;
13 | align(8) align int a;
14 | int[] a = [];
15 | auto a = [1, 2, 3];
16 | auto a = [a:1, b:2, c:3];
17 | auto a = b, c = d;
18 | static if (true)
19 | int a;
20 | else
21 | int b;
22 |
23 | debug void foo();
24 | debug(something) void foo();
25 | debug(100) void foo();
26 | debug = 101;
27 | debug = identifier;
28 |
29 | version(AArch64) enum x = 100;
30 | version = coverage;
31 |
32 | static if (true):
33 | mixin ("int a;");
34 | mixin something;
35 | mixin something!A;
36 | mixin duff!(i, j, delegate { foo13(i); });
37 | mixin typeof(something!A).x;
38 | template mix(){
39 | int x;
40 | }
41 | mixin .mix;
42 | __vector(int[4]) intVector;
43 | ;
44 |
45 | enum a = 1;
46 | SomeStruct a = { a : 10, b : 20 };
47 | int[a .. b] c;
48 | int function(int) a;
49 | int function(int) const a;
50 | int delegate(int) a;
51 | int a = typeid(int).alignof;
52 | int a = typeid(10).alignof;
53 | int a = (int).sizeof;
54 | enum string STRING_CONSTANT = "abc";
55 | Size[][] minSizes = new Size[][](cols, rows);
56 | version(StdDdoc)
57 | {
58 | struct DirEntry
59 | {
60 | version (Windows)
61 | {
62 | }
63 | else version (Posix)
64 | {
65 | private this(string path);
66 | }
67 | }
68 | }
69 | idouble a = 4Li;
70 | idouble a = 4i;
71 | ifloat a = 4fi;
72 | ifloat a = 4Fi;
73 |
74 | static foreach (n; ['a', 'b', 'c'])
75 | {
76 | mixin("char " ~ n ~ ";");
77 | }
78 |
79 | static foreach_reverse (i; '0' .. '5')
80 | {
81 | mixin("int _" ~ i ~ ";");
82 | }
83 |
84 | static foreach (enum i, alias T; AliasSeq!(int, bool))
85 | {
86 | T a = i;
87 | }
88 |
89 | struct Foo(T);
90 | union Foo(T);
91 | class Foo(T);
92 | interface Foo(T);
93 |
94 | mixin("auto a = 1 + ", 1, ";");
95 |
96 | __traits(getMember, Foo, "Bar") fooBar;
97 | const(__traits(getMember, Foo, "Bar")) fooBar;
98 | alias FooBar = __traits(getMember, Foo, "Bar");
99 | const fooBar = cast(__traits(getMember, Foo, "Bar")) __traits(getMember, Foo, "bar");
100 | int twice(int x) = 2 * x;
101 | const int twice(int x) = 2 * x;
102 | immutable int twice(int x) = 2 * x;
103 |
104 | void foo()
105 | {
106 | __traits(getMember, Foo, "Bar") fooBar;
107 | immutable int twice(int x) = 2 * x;
108 | }
109 |
110 | alias Mt1 = mixin("foo", ".", "bar");
111 | alias Mt2 = mixin("int");
112 | const(mixin("int")) globalInt1;
113 | shared const(mixin("int")) globalInt2;
114 | const(mixin("int"))[][] globalIntMtx1;
115 |
116 |
--------------------------------------------------------------------------------
/test/pass_files/dip1000.d:
--------------------------------------------------------------------------------
1 | class Foo
2 | {
3 | @property auto front() scope
4 | {return new Foo;}
5 | }
--------------------------------------------------------------------------------
/test/pass_files/dip25.d:
--------------------------------------------------------------------------------
1 | @safe struct S {
2 | static int a;
3 | int b;
4 | ref int fun() { return a; } // fine, callers assume infinite lifetime
5 | ref int gun() { return b; } // ERROR! Cannot return a direct member
6 | ref int hun() return { return b; } // fine, result is scoped within this
7 | @safe ref int fun(ref return float x);
8 | }
9 | @safe struct S {
10 | private int x;
11 | ref int get() return { return x; } // should work, see next section
12 | }
13 |
--------------------------------------------------------------------------------
/test/pass_files/do_body.d:
--------------------------------------------------------------------------------
1 | void foo(int x)
2 | in
3 | {
4 | assert(x > 0);
5 | }
6 | do
7 | {
8 |
9 | }
10 |
11 | int foo2(int x)
12 | in
13 | {
14 | assert(x > 0);
15 | }
16 | out(r)
17 | {
18 | assert(r > 0);
19 | }
20 | do
21 | {
22 | return 0;
23 | }
24 |
--------------------------------------------------------------------------------
/test/pass_files/enums.d:
--------------------------------------------------------------------------------
1 | enum A { a }
2 | enum B { a, b, c }
3 | enum C { a = 10, b = 20, d = int.init, e }
4 | enum D : int { a }
5 | enum : int { a }
6 | enum { int b = 100 }
7 | enum
8 | {
9 | /// doc for a
10 | a,
11 | b, // doc for b
12 | c // doc for c
13 | }
14 |
15 | enum E
16 | {
17 | @disable member,
18 | @A @B deprecated("meep") member,
19 | deprecated("meep") member
20 | }
21 |
22 | // https://github.com/dlang-community/libdparse/issues/390
23 | enum F;
24 | enum G : long;
25 |
--------------------------------------------------------------------------------
/test/pass_files/exceptions.d:
--------------------------------------------------------------------------------
1 | void foo()
2 | {
3 | try {
4 | doSomething();
5 | } catch {
6 | doSomethingElse();
7 | }
8 |
9 | try {
10 | doSomething();
11 | } catch (Exception) {
12 | doSomethingElse();
13 | }
14 |
15 | try {
16 | doSomething();
17 | } catch (Exception e) {
18 | doSomethingElse();
19 | }
20 |
21 | try
22 | doSomething();
23 | finally
24 | doSomethingElse();
25 | }
26 |
--------------------------------------------------------------------------------
/test/pass_files/expressions.d:
--------------------------------------------------------------------------------
1 | auto a = 1 * 2;
2 | auto a = 1 + 2;
3 | auto a = 1 % 2;
4 | auto a = 1 || 2;
5 | auto a = 1 && 2;
6 | auto a = 1 << 2;
7 | auto a = 1 >> 2;
8 | auto a = 1 < 2;
9 | auto a = 1 > 2;
10 | auto a = 1 >>> 2;
11 | auto a = cast() a;
12 | auto a = cast(int) a;
13 | auto a = a || b || c && d;
14 | auto a = b++;
15 | auto a = ++b;
16 | auto a = b[10];
17 | auto a = b[10 .. $];
18 | auto a = b[$];
19 | auto a = b[1 .. 2];
20 | auto a = [10] ~ [20];
21 | auto a = [[10], [20]];
22 | auto a = [{1}];
23 | auto a = "string";
24 | auto a = "string" "concatenated";
25 | auto a = void.sizeof;
26 | auto a = int.mangleof;
27 | auto a = .x;
28 | auto a = const(int).mangleof;
29 | auto a = function(int a) { return a; };
30 | auto a = delegate(int a) { return a; };
31 | auto a = function() { return 100; };
32 | auto a = delegate() { return 100; };
33 | auto a = function { return 100; };
34 | auto a = delegate { return 100; };
35 | auto a = mixin("1 + ", 1);
36 | enum a = is(_execinfo == module);
37 | enum a = is(_execinfo == package);
38 | enum a = is(_execinfo == __vector);
39 |
40 | void foo()
41 | {
42 | a = b;
43 | a >>>= b;
44 | a >>= b;
45 | a <<= b;
46 | a += b;
47 | a -= b;
48 | a *= b;
49 | a %= b;
50 | a &= b;
51 | a /= b;
52 | a |= b;
53 | a ^^= b;
54 | a ^= b;
55 | a ~= b;
56 | auto a = b <= c;
57 | auto a = b == c;
58 | auto a = b is c;
59 | auto a = b !is c;
60 | auto a = b in c;
61 | auto a = b !in c;
62 | delete a;
63 | auto a = new b;
64 | auto a = new b();
65 | auto a = new b();
66 | auto a = const c();
67 | auto a = const(c)();
68 | auto a = import("foo.txt");
69 | auto a = b([a:1, b:2]);
70 | auto a = b((c));
71 | auto a = b((a) => a * 10_000);
72 | auto a = b((int a) {return a + 2;});
73 | enum a = typeof(b);
74 | enum a = typeid(b);
75 | enum a = is(_execinfo == module);
76 | enum a = is(_execinfo == package);
77 | enum a = is(_execinfo == __vector);
78 | enum a = is(a : b);
79 | enum a = __traits(classInstanceSize, b);
80 | enum a = mixin("something");
81 | enum a = mixin(nothing);
82 | pragma(startaddress, b);
83 | auto a = new int[100];
84 | auto a = new class {};
85 | auto a = new (x, y, z) class {};
86 | auto a = new (x, y, z) class (c, d) {};
87 | auto a = new (x, y, z) class A, B {};
88 | assert (a);
89 | assert (a,);
90 | assert (a, "b");
91 | assert (a, "b",);
92 | assert((lower & upper).empty);
93 | auto ptr = cast(const shared int*) &val;
94 | (cast(Node*) data.ptr).next = null;
95 | int[int[string]] aa5 = [["a":1]:2, ["b":3]:4];
96 | if (is(typeof(a) == __vector)){}
97 | Hand h = body.hands.left;
98 | }
99 |
--------------------------------------------------------------------------------
/test/pass_files/function_aliases.d:
--------------------------------------------------------------------------------
1 | alias aaa = a => a * 2;
2 | alias bbb = (a) => a * 2;
3 | alias ccc = (a) nothrow => a * 2;
4 | alias ddd = function void(a) => a * 2;
5 | alias eee = function void(a) nothrow => a * 2;
6 | alias fff = function void(a) { return 100; };
7 | alias ggg = function void(a) in { } out { } body { return 100; };
8 | alias hhh = delegate void(a) => a * 2;
9 | alias iii = delegate void(a) nothrow => a * 2;
10 | alias jjj = delegate void(a) { return 100; };
11 | alias kkk = delegate void(a) in { } out { } body { return 100; };
12 | alias lll = { return 100; };
13 | alias mmm = () { return 100; };
14 | alias nnn = () @nogc { return 100; };
15 | alias fun = (@(1) inout @(1) a) => {};
16 |
17 | // The following is valid according to D's grammar, but rejected by dmd
18 | /+unittest
19 | {
20 | alias abc = in { } out { } body { return 100; };
21 | alias abc = () in{ } out { } body { return 100; };
22 | alias abc = () @nogc in{ } out { } body { return 100; };
23 | doThings(in { } out { } body { return 100; });
24 | auto a = in { } out { } body { return 100; };
25 | }
26 | +/
27 |
--------------------------------------------------------------------------------
/test/pass_files/function_declarations.d:
--------------------------------------------------------------------------------
1 | void foo(int a ...) {}
2 | void foo(...) in {} body {}
3 | void foo(double) in {} out {} body {}
4 | void foo(const int) in {} out(a) {} body {}
5 | void foo(lazy real) out(a) {} in {} body {}
6 |
7 | void foo(T)();
8 | void foo(T)() in {} body {}
9 | void foo(T)() in {} out {} body {}
10 | void foo(T)() in {} out(a) {} body {}
11 | void foo(T)() out(a) {} in {} body {}
12 |
13 | void foo(T)(immutable(T) t) if (something) {}
14 | void foo(T)(in int great) if (something) in {} body {}
15 | void foo(T)(final void* param) if (something) in {} out {} body {}
16 | void foo(T)(char c = 'a') if (something) in {} out(a) {} body {}
17 | void foo(T)(char s[]) if (something) out(a) {} in {} body {}
18 |
19 | auto foo(int ...) { return 1; }
20 | auto ref foo() { return 1; }
21 | ref auto foo() { return 1; }
22 | const foo() { return 1; }
23 | auto inout foo() { return 1; }
24 | inout auto foo() { return 1; }
25 |
26 | int foo() pure { return 1; }
27 | int foo() const { return 1; }
28 | int foo() inout { return 1; }
29 | int foo() immutable { return 1; }
30 | int foo() shared { return 1; }
31 | int foo() const @safe { return 1; }
32 | int foo() const @safe nothrow { return 1; }
33 |
34 | auto a = function int (int a) { return a * 2; };
35 | auto a = function int (int a) pure { return a * 2; };
36 | auto a = function int (int a) @whatever { return a * 2; };
37 | auto a = function (int a) => a * 2;
38 | auto a = (int a) => a * 2;
39 | auto a = function int (int a) => a * 2;
40 | void bar()
41 | {
42 | doStuff(function int(int a) { return a / 2; });
43 | doStuff(function int(int a) body { return a / 2; });
44 | doStuff(function int(int a) in { assert (a > 10); } body { return a / 2; });
45 | }
46 |
47 | void foo(@(1) const @UDA int p);
48 |
49 | void cVarArg(int, ...);
50 | enum bool isInputRange = is(typeof((inout int = 0){}));
51 | auto a = b => b * 2;
52 |
53 | int typesafeVarArg(int a = 1, int[] rest = [] ...) { return 1; }
54 |
55 | void foo() in(true) do {}
56 | void foo() in(true,) do {}
57 | void foo() in(true,"false") do {}
58 | void foo() in(true,"false",) do {}
59 | void foo() in(true) in(true) do {}
60 | void foo() in(true) {}
61 | void foo() in(true) in(true) {}
62 | void foo() in(true) in {} do {}
63 | void foo() in {} in {} do {}
64 |
65 | void foo() out(;true) do {}
66 | void foo() out(;true, "false") do {}
67 | void foo() out(;true, "false",) do {}
68 | void foo() out(;true) out(;true) do {}
69 | void foo() out(;true,) {}
70 | void foo() out(;true) out(;true) {}
71 | void foo() out(;true) out {} do {}
72 | void foo() out {} out {} do {}
73 |
74 | void foo() in(true) out(;true) do {}
75 | void foo() out(; true) in(true) do {}
76 | void foo() out(result; true) in(true) do {}
77 | void foo() in(true) out(result; true) in(true) {}
78 | void foo() in(true) out(result; true) in(true);
79 |
--------------------------------------------------------------------------------
/test/pass_files/function_literals.d:
--------------------------------------------------------------------------------
1 | void main()
2 | {
3 | auto foo1() pure immutable
4 | {
5 | return 0;
6 | }
7 |
8 | auto foo2() pure const
9 | {
10 | return 0;
11 | }
12 | }
13 |
14 | void main()
15 | {
16 | auto dg1 = () pure immutable
17 | {
18 | return 0;
19 | };
20 | auto dg2 = () pure const
21 | {
22 | return 0;
23 | };
24 | }
25 |
26 | void testRefReturns()
27 | {
28 | alias flit11 = function ref int () { return a; };
29 | alias flit12 = delegate ref int () { return a; };
30 | alias flit13 = ref () {return a; };
31 |
32 | auto aflit11 = function ref int () { return a; };
33 | auto aflit12 = delegate ref int () { return a; };
34 | auto aflit13 = ref () {return a; };
35 |
36 | alias flit21 = function ref int () => a;
37 | alias flit22 = delegate ref int () => a;
38 | alias flit23 = ref () => a;
39 |
40 | auto aflit21 = function ref int () => a;
41 | auto aflit22 = delegate ref int () => a;
42 | auto aflit23 = ref () => a;
43 |
44 | (ref () => x )() = 1;
45 | assert((funa16271!( ref (ref a) => a)(x) += 1) == 7 );
46 | assert((funa16271!(function ref (ref a) => a)(x) += 1) == 8 );
47 | assert((funa16271!(function ref int(ref a) => a)(x) += 1) == 9 );
48 | assert((funa16271!(delegate ref (ref a) => a)(x) += 1) == 10);
49 | assert((funa16271!(delegate ref int(ref a) => a)(x) += 1) == 11);
50 | }
51 |
--------------------------------------------------------------------------------
/test/pass_files/helloworld.d:
--------------------------------------------------------------------------------
1 | import std.stdio;
2 |
3 | void main()
4 | {
5 | writeln("Hello World!");
6 | }
7 |
--------------------------------------------------------------------------------
/test/pass_files/ifConditions.d:
--------------------------------------------------------------------------------
1 | void foo()
2 | {
3 | if (const(Type)* data = call()){}
4 | if (const a = call()){}
5 | if (const shared a = call()){}
6 | if (auto a = call()){}
7 | if (immutable shared(Type) a = call()){}
8 | if (a) {}
9 | if (T t = T.init) {}
10 | if (T!0 t = T.init) {}
11 | if (true) {}
12 | }
13 |
14 | void main()
15 | {
16 | if ((a && b) || c) {}
17 | if (a && b || c) {}
18 | }
19 |
--------------------------------------------------------------------------------
/test/pass_files/imports.d:
--------------------------------------------------------------------------------
1 | import std.stdio;
2 | import foo, bar;
3 | import io = std.stdio;
4 | import std.stdio: writefln, foo = writef;
5 | import io = std.stdio : foo = writefln;
6 | import foo, bar, baz;
7 | import core.stdc.stdio, std.string : KeepTerminator;
8 |
--------------------------------------------------------------------------------
/test/pass_files/innerclass.d:
--------------------------------------------------------------------------------
1 | class Foo
2 | {
3 | class Bar
4 | {
5 | class Foobar { void method() {} }
6 | }
7 |
8 | public Bar bar;
9 | }
10 |
11 | void main ()
12 | {
13 | auto foo = new Foo;
14 | Foo.Bar bar = foo.new Bar;
15 | auto foo_bar = foo.new Bar;
16 | auto foobar = foo.bar.new Foobar;
17 | auto foobar = (foo.bar).new Foobar;
18 | (foo.new Bar).method;
19 | }
20 |
--------------------------------------------------------------------------------
/test/pass_files/interfaces.d:
--------------------------------------------------------------------------------
1 | interface A;
2 | interface B {}
3 | interface C : B {}
4 | interface D(T) if (Z) : B {}
5 | interface E(T) : B if (Z) {}
6 | interface F(T);
7 | interface G(T) if (Z);
8 | interface H{ void hat() in {} }
9 |
--------------------------------------------------------------------------------
/test/pass_files/issue00114.d:
--------------------------------------------------------------------------------
1 | void main ()
2 | {
3 | int a, b;
4 | int[string] aa = [ "hello" : a = a, "world" : b = b ];
5 | }
6 |
--------------------------------------------------------------------------------
/test/pass_files/issue0042.d:
--------------------------------------------------------------------------------
1 | /// Ditto
2 | template octal(alias s)
3 | if (isIntegral!(typeof(s)))
4 | {
5 | enum auto octal = octal!(typeof(s), to!string(s));
6 | }
7 |
--------------------------------------------------------------------------------
/test/pass_files/issue0047.d:
--------------------------------------------------------------------------------
1 | unittest
2 | {
3 | {
4 | {
5 | if (1)
6 | {
7 | }
8 | else
9 | {
10 | x;
11 | }
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/test/pass_files/issue0067.d:
--------------------------------------------------------------------------------
1 | auto a = b[1, 2..3];
2 | auto a = b[2..3];
3 |
--------------------------------------------------------------------------------
/test/pass_files/issue0070.d:
--------------------------------------------------------------------------------
1 | version (Foo)
2 | {
3 | version(D_Version2)
4 | {
5 | public import core.memory;
6 | }
7 | else:
8 | }
9 |
10 | version (Bar)
11 | int foo ();
12 | else:
13 | int foo(int);
14 |
--------------------------------------------------------------------------------
/test/pass_files/issue0095.d:
--------------------------------------------------------------------------------
1 | enum A
2 | {
3 | a,
4 | }
5 |
--------------------------------------------------------------------------------
/test/pass_files/issue0106.d:
--------------------------------------------------------------------------------
1 | void foo1(){if (const a = 0){}}
2 | void foo2(){if (const shared a = 0){}}
3 | void foo3(){if (immutable shared a = 0){}}
--------------------------------------------------------------------------------
/test/pass_files/issue0156.d:
--------------------------------------------------------------------------------
1 | module a;
2 |
3 | void foo()
4 | {
5 | const a = ["a":"b"];
6 | const a = [1:1];
7 | const a = [[1]:"a"];
8 | const a = [[1]:[1]];
9 | }
--------------------------------------------------------------------------------
/test/pass_files/issue0158.d:
--------------------------------------------------------------------------------
1 | T[1].Y y;
2 | T.T y;
3 | T.T y;
4 | T[] y;
5 | T* y;
6 | T[0].Y y;
7 | T.T[] y;
8 | T.T[8] y;
9 | T.T[8].T y;
10 | .T!"af" taf;
11 | .T!0[] t;
12 | T!(0)[] t;
13 | T!(0)[dim] t;
14 | alias SubList = T[lo.lo .. hi.hi];
15 |
--------------------------------------------------------------------------------
/test/pass_files/issue0291.d:
--------------------------------------------------------------------------------
1 | module issue0291;
2 |
3 | void foo()
4 | in { } // "so you need do{}?"
5 | out (; true) // No you don't, but libdparse thinks you still do.
6 | { }
7 |
--------------------------------------------------------------------------------
/test/pass_files/issue0413.d:
--------------------------------------------------------------------------------
1 | @("") export auto a() { }
2 |
--------------------------------------------------------------------------------
/test/pass_files/lexical.d:
--------------------------------------------------------------------------------
1 | #!/usr/bin/rdmd
2 |
3 | /// single line comment
4 | /* StarSlash */
5 | /***** ******/
6 | /**
7 | * 123
8 | */
9 | /+ StarPlus +/
10 | /++
11 | + 456
12 | +/
13 | /+ StarPlus /+ Nested +/ +/
14 |
15 | #line 10 "whatever.d"
16 |
17 | auto a = 1u;
18 | auto a = 1U;
19 | auto a = 1uL;
20 | auto a = 1UL;
21 | auto a = 1L;
22 | auto a = 1Lu;
23 | auto a = 1LU;
24 | auto a = 1i;
25 | auto a = 1.0;
26 | auto a = 1.0L;
27 | auto a = 1e10;
28 | auto a = 1.e10;
29 | auto a = 1e1L;
30 | auto a = 1e1f;
31 | auto a = 1e1F;
32 | auto a = 1e1i;
33 | auto a = 1e+1;
34 | auto a = 1e+_1;
35 | auto a = 1e-1;
36 | auto a = 1e-_1;
37 | auto a = b[1..2];
38 | auto a = 0x1p10;
39 | auto a = 0x1_2u;
40 | auto a = 0x1_2.fi;
41 | auto a = 0x1_2L;
42 | auto a = 0b1_0;
43 | auto a = 0b1u;
44 | auto a = 0b1L;
45 | auto a = 0b1UL;
46 | auto a = 0b1U;
47 | auto a = 0b1LU;
48 | string a = .1;
49 | string a = 'a';
50 | string a = '\0';
51 | string a = '\01';
52 | string a = '\012';
53 | string a = '\123';
54 | string a = '\u12aA';
55 | string a = '\U12aA5678';
56 | string a = "\"\?\\\0\a\b\f\n\r\t\v\xff\1\u1234\UaA345678";
57 | string a = "str"c;
58 | string a = "str"d;
59 | string a = "str"w;
60 | string a = `str`;
61 | string a = `str''""`;
62 | string a = r"\a\b\c"c;
63 | string a = x"12 34 56 78 90 ab cd ef AB CD EF";
64 | string a = x"AB"c;
65 | string a = x"AB"d;
66 | string a = x"AB"w;
67 | string a = q{int a;};
68 | string a = q{{int a;}};
69 | string a = q{int a;}c;
70 | string a = q{int a;}d;
71 | string a = q{int a;}w;
72 | string a = q"( " )";
73 | string a = q"( (") )";
74 | string a = q"< " >";
75 | string a = q"< <"> >";
76 | string a = q"{ " }";
77 | string a = q"{ {"} }";
78 | string a = q"[ " ]";
79 | string a = q"[ ["] ]";
80 | string a = q"IDENTIFIER
81 | "
82 | IDENTIFIER";
83 |
84 |
--------------------------------------------------------------------------------
/test/pass_files/linkageAttributes.d:
--------------------------------------------------------------------------------
1 | private:
2 | extern(C) int a;
3 | extern(D) int b;
4 | extern(Windows) int c;
5 | extern(Pascal) int d;
6 | extern(System) int e;
7 | extern(Objective-C) int f ;
8 | extern(C++) int g;
9 | extern(C++, a.b.c) int h;
10 | extern(C++, struct) int i;
11 | extern(C++, class) int j;
12 |
13 | extern(C++, "abc") int k;
14 | extern(C++, "a", "b", "c") int k;
15 | extern(C++, (abc)) int m;
16 | extern(C++, ("abc")) int n;
17 |
--------------------------------------------------------------------------------
/test/pass_files/misc_coverage.d:
--------------------------------------------------------------------------------
1 | module misc_coverage;
2 |
3 | uint a[][];
4 |
5 | alias T = deprecated U;
6 |
7 | alias T = extern const U;
8 |
--------------------------------------------------------------------------------
/test/pass_files/mixin_types.d:
--------------------------------------------------------------------------------
1 | mixin("int") variableName;
2 | void foo(mixin("int") arg) {
3 | mixin("int") localVar;
4 | }
5 | struct S {
6 | mixin("int") foo;
7 | }
8 |
--------------------------------------------------------------------------------
/test/pass_files/moduleDec1.d:
--------------------------------------------------------------------------------
1 | deprecated module moduleDec1;
2 |
--------------------------------------------------------------------------------
/test/pass_files/moduleDec2.d:
--------------------------------------------------------------------------------
1 | deprecated("Don't use this") module moduleDec2;
2 |
--------------------------------------------------------------------------------
/test/pass_files/moduleDec3.d:
--------------------------------------------------------------------------------
1 | @something module moduleDec3;
2 |
--------------------------------------------------------------------------------
/test/pass_files/moduleDec4.d:
--------------------------------------------------------------------------------
1 | @something deprecated module moduleDec3;
2 |
--------------------------------------------------------------------------------
/test/pass_files/much_recursion.d:
--------------------------------------------------------------------------------
1 | template Foo() {
2 | static if (a) {
3 | } else static if (b) {
4 | } else static if (b) {
5 | } else static if (b) {
6 | } else static if (b) {
7 | } else static if (b) {
8 | } else static if (b) {
9 | } else static if (b) {
10 | } else static if (b) {
11 | } else static if (b) {
12 | } else static if (b) {
13 | } else static if (b) {
14 | } else static if (b) {
15 | } else static if (b) {
16 | } else static if (b) {
17 | } else static if (b) {
18 | } else static if (b) {
19 | } else static if (b) {
20 | } else static if (b) {
21 | } else static if (b) {
22 | } else static if (b) {
23 | } else static if (b) {
24 | } else static if (b) {
25 | } else static if (b) {
26 | } else static if (b) {
27 | } else static if (b) {
28 | } else static if (b) {
29 | } else static if (b) {
30 | } else static if (b) {
31 | } else static if (b) {
32 | } else static if (b) {
33 | } else static if (b) {
34 | } else static if (b) {
35 | } else static if (b) {
36 | } else static if (b) {
37 | } else static if (b) {
38 | } else static if (b) {
39 | } else static if (b) {
40 | } else static if (b) {
41 | } else static if (b) {
42 | } else static if (b) {
43 | } else static if (b) {
44 | } else static if (b) {
45 | } else static if (b) {
46 | } else static if (b) {
47 | } else static if (b) {
48 | } else static if (b) {
49 | } else static if (b) {
50 | } else static if (b) {
51 | } else static if (b) {
52 | } else static if (b) {
53 | } else static if (b) {
54 | } else static if (b) {
55 | } else static if (b) {
56 | } else static if (b) {
57 | } else static if (b) {
58 | } else static if (b) {
59 | } else static if (b) {
60 | } else static if (b) {
61 | } else static if (b) {
62 | } else static if (b) {
63 | } else static if (b) {
64 | } else static if (b) {
65 | } else static if (b) {
66 | } else static if (b) {
67 | } else static if (b) {
68 | } else static if (b) {
69 | } else static if (b) {
70 | } else static if (b) {
71 | } else static if (b) {
72 | } else static if (b) {
73 | } else static if (b) {
74 | } else static if (b) {
75 | } else static if (b) {
76 | } else static if (b) {
77 | } else static if (b) {
78 | } else static if (b) {
79 | } else static if (b) {
80 | } else static if (b) {
81 | } else static if (b) {
82 | } else static if (b) {
83 | } else static if (b) {
84 | } else static if (b) {
85 | } else static if (b) {
86 | } else static if (b) {
87 | } else static if (b) {
88 | } else static if (b) {
89 | } else static if (b) {
90 | } else static if (b) {
91 | } else static if (b) {
92 | } else static if (b) {
93 | } else static if (b) {
94 | } else static if (b) {
95 | } else static if (b) {
96 | } else static if (b) {
97 | } else static if (b) {
98 | } else static if (b) {
99 | } else static if (b) {
100 | } else static if (b) {
101 | } else static if (b) {
102 | } else static if (b) {
103 | } else static if (b) {
104 | } else static if (b) {
105 | } else static if (b) {
106 | } else static if (b) {
107 | } else static if (b) {
108 | } else static if (b) {
109 | } else static if (b) {
110 | } else static if (b) {
111 | } else static if (b) {
112 | } else static if (b) {
113 | } else static if (b) {
114 | } else static if (b) {
115 | } else static if (b) {
116 | } else static if (b) {
117 | } else static if (b) {
118 | } else static if (b) {
119 | } else static if (b) {
120 | } else static if (b) {
121 | } else static if (b) {
122 | } else static if (b) {
123 | } else static if (b) {
124 | } else static if (b) {
125 | }
126 | }
127 |
--------------------------------------------------------------------------------
/test/pass_files/named_arguments.d:
--------------------------------------------------------------------------------
1 | void main()
2 | {
3 | a(100);
4 | b(x: 100);
5 | c(x: 100, y: 200);
6 | d!(a: "a", b: "b")("c");
7 | }
8 |
--------------------------------------------------------------------------------
/test/pass_files/pragmas.d:
--------------------------------------------------------------------------------
1 | module a;
2 |
3 | void foo()
4 | {
5 | pragma(bar) baz = 8;
6 |
7 | pragma(bar)
8 | {
9 | baz = 8;
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/test/pass_files/ptrntab.d:
--------------------------------------------------------------------------------
1 | OP[] optab =
2 | [
3 | { "sym", 0, { null } },
4 | { "sym", 0, { null } },
5 | { "sym", 0, { null } },
6 | { "sym", 0, { null } },
7 | { "sym", 0, { null } },
8 | { "sym", 0, { null } },
9 | { "sym", 0, { null } },
10 | { "sym", 0, { null } },
11 | { "sym", 0, { null } },
12 | { "sym", 0, { null } },
13 | { "sym", 0, { null } },
14 | { "sym", 0, { null } },
15 | { "sym", 0, { null } },
16 | { "sym", 0, { null } },
17 | { "sym", 0, { null } },
18 | { "sym", 0, { null } },
19 | { "sym", 0, { null } },
20 | { "sym", 0, { null } },
21 | { "sym", 0, { null } },
22 | { "sym", 0, { null } },
23 | { "sym", 0, { null } },
24 | { "sym", 0, { null } },
25 | { "sym", 0, { null } },
26 | { "sym", 0, { null } },
27 | { "sym", 0, { null } },
28 | { "sym", 0, { null } },
29 | { "sym", 0, { null } },
30 | { "sym", 0, { null } },
31 | { "sym", 0, { null } },
32 | { "sym", 0, { null } },
33 | { "sym", 0, { null } },
34 | { "sym", 0, { null } },
35 | { "sym", 0, { null } },
36 | { "sym", 0, { null } },
37 | { "sym", 0, { null } },
38 | { "sym", 0, { null } },
39 | { "sym", 0, { null } },
40 | { "sym", 0, { null } },
41 | { "sym", 0, { null } },
42 | { "sym", 0, { null } },
43 | { "sym", 0, { null } },
44 | { "sym", 0, { null } },
45 | { "sym", 0, { null } },
46 | { "sym", 0, { null } },
47 | { "sym", 0, { null } },
48 | { "sym", 0, { null } },
49 | { "sym", 0, { null } },
50 | { "sym", 0, { null } },
51 | { "sym", 0, { null } },
52 | { "sym", 0, { null } },
53 | { "sym", 0, { null } },
54 | { "sym", 0, { null } },
55 | { "sym", 0, { null } },
56 | { "sym", 0, { null } },
57 | { "sym", 0, { null } },
58 | { "sym", 0, { null } },
59 | { "sym", 0, { null } },
60 | { "sym", 0, { null } },
61 | { "sym", 0, { null } },
62 | { "sym", 0, { null } },
63 | { "sym", 0, { null } },
64 | { "sym", 0, { null } },
65 | { "sym", 0, { null } },
66 | { "sym", 0, { null } },
67 | { "sym", 0, { null } },
68 | { "sym", 0, { null } },
69 | { "sym", 0, { null } },
70 | { "sym", 0, { null } },
71 | { "sym", 0, { null } },
72 | { "sym", 0, { null } },
73 | { "sym", 0, { null } },
74 | { "sym", 0, { null } },
75 | { "sym", 0, { null } },
76 | { "sym", 0, { null } },
77 | { "sym", 0, { null } },
78 | { "sym", 0, { null } },
79 | { "sym", 0, { null } },
80 | { "sym", 0, { null } },
81 | { "sym", 0, { null } },
82 | { "sym", 0, { null } },
83 | { "sym", 0, { null } },
84 | { "sym", 0, { null } },
85 | { "sym", 0, { null } },
86 | { "sym", 0, { null } },
87 | { "sym", 0, { null } },
88 | { "sym", 0, { null } },
89 | { "sym", 0, { null } },
90 | { "sym", 0, { null } },
91 | { "sym", 0, { null } },
92 | { "sym", 0, { null } },
93 | { "sym", 0, { null } },
94 | { "sym", 0, { null } },
95 | { "sym", 0, { null } },
96 | { "sym", 0, { null } },
97 | { "sym", 0, { null } },
98 | { "sym", 0, { null } },
99 | { "sym", 0, { null } },
100 | { "sym", 0, { null } },
101 | { "sym", 0, { null } },
102 | { "sym", 0, { null } },
103 | { "sym", 0, { null } },
104 | { "sym", 0, { null } },
105 | { "sym", 0, { null } },
106 | { "sym", 0, { null } },
107 | { "sym", 0, { null } },
108 | { "sym", 0, { null } },
109 | { "sym", 0, { null } },
110 | ];
111 |
--------------------------------------------------------------------------------
/test/pass_files/shortenedMethods.d:
--------------------------------------------------------------------------------
1 | // these 2 are equivalent
2 | int foo() { return 1; }
3 | int bar() => 1;
4 |
5 | // https://github.com/dlang/dmd/blob/52844d4b1e9d6714bfd2e535f25a72074a046209/test/compilable/shortened_methods.d
6 | class A {
7 | int _x = 34;
8 | // short syntax works in all contexts
9 | @property x() => _x;
10 | @property x(int v) => _x = v;
11 |
12 | // including with contracts
13 | @property y() in(true) => _x;
14 |
15 | // or other auto returns
16 | auto foo() @safe => assert(0);
17 |
18 | // or normal method defintions
19 | bool isNull() => this is null;
20 | }
21 |
22 | class B : A{
23 | // short syntax also overrides the same as long syntax
24 | override bool isNull() => this !is null;
25 | }
26 |
27 | static assert((new A).x == 34);
28 |
29 | string test() => "hello"; // works at any scope
30 |
31 | static assert(test() == "hello"); // works normally
32 | static assert(is(typeof(&test) == string function())); // same normal type
33 |
34 | void func() {
35 | int a;
36 | int nested() => a; // and at nested scopes too
37 | }
--------------------------------------------------------------------------------
/test/pass_files/single_line_with_decl.d:
--------------------------------------------------------------------------------
1 | module a;
2 |
3 | enum A{a0}
4 |
5 | void foo()
6 | {
7 | with(A) const i = 0;
8 | with(A)
9 | {
10 | const i = 0;
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/test/pass_files/statements.d:
--------------------------------------------------------------------------------
1 | deprecated void foo()
2 | {
3 | if (a) b();
4 | if (a) b(); else c();
5 | if (auto a = i == 10) b();
6 | if (int i = a < 100) b();
7 | switch (x) {}
8 | switch (x) { case 10: break; }
9 | switch (x) { case 10: break; default: break; }
10 | label: switch (x) {
11 | case 1: break label;
12 | case 2: goto default;
13 | case 3: goto label2;
14 | case 4: goto case 3;
15 | case 5: .. case 100: break;
16 | }
17 | while (true) { continue; }
18 | while (true) { continue onAndOn; }
19 | label2: while (true) { break label2; }
20 | do nothing(); while(false);
21 | do { nothing(); } while(false);
22 | for (int i = 0; i < 100; i++) {}
23 | for (; i < 100; i++) {}
24 | for (; i < 100;) {}
25 | for (int i = 0; ; i++) {}
26 | foreach (a; b) {}
27 | foreach (int a; b) {}
28 | foreach (a, b; c) {}
29 | foreach (a; c .. d) {}
30 | foreach (ref a; c .. d) {}
31 | foreach (ref const a; c .. d) {}
32 | foreach (const ref a; c .. d) {}
33 | foreach (inout a; c .. d) {}
34 | scope(failure) complain();
35 | scope(success) celebrate();
36 | scope(success) {celebrate();}
37 | synchronized (swimming) {}
38 | throw aParty!tonight;
39 | with (great.power) comes(great.responsibility);
40 | final switch (x) {}
41 | version(ARM_HardFloat)
42 | a = b.c;
43 | else
44 | a = c.d;
45 | debug
46 | a = 100;
47 | static if (someCondition)
48 | a = 9;
49 | version(graphviz_debugging)
50 | {
51 | File f = File("graph%04d.dot".format(i), "w");
52 | tsTree.print(f);
53 | }
54 |
55 | version(Alpha)
56 | {
57 | }
58 | else
59 | {
60 | i++;
61 | }
62 | label:
63 |
64 |
65 | static foreach (n; ['a', 'b', 'c'])
66 | {{
67 | mixin(n ~ "++;");
68 | }}
69 |
70 | static foreach_reverse (i; 1 .. 10)
71 | {
72 | assert(i-- > 0);
73 | }
74 | mixin("auto a = 1 +", 1);
75 | }
76 |
--------------------------------------------------------------------------------
/test/pass_files/structs.d:
--------------------------------------------------------------------------------
1 | struct S
2 | {
3 | @disable this(this);
4 | this() { this.y++; }
5 | this(int a) { this.y++; }
6 | this() const { this.y++; }
7 | this(T)() { this.y++; }
8 | this(T)() if (U) { this.y++; }
9 | this(this) { this.y++; }
10 | this(this) @whatever { this.y++; }
11 | ~this();
12 | ~this() const {}
13 | invariant()
14 | {
15 | assert (x == 10);
16 | }
17 | invariant(true);
18 | invariant(true, "false");
19 | }
20 | struct S;
21 | struct S {}
22 | struct S(T) {}
23 | struct S(T) if (U) {}
24 |
--------------------------------------------------------------------------------
/test/pass_files/switch_condition_assignment.d:
--------------------------------------------------------------------------------
1 | import std : writeln, format;
2 |
3 | int get()
4 | {
5 | return 1;
6 | }
7 |
8 | void main()
9 | {
10 | switch (auto x = get()) {
11 | default:
12 | writeln("inside switch: ", x);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/test/pass_files/templates.d:
--------------------------------------------------------------------------------
1 | template a(b) {}
2 | template a(b, c) {}
3 | template a(b, c) if (d) {}
4 | template a(alias int a : 10) {}
5 | template a(alias int a : int) {}
6 | template a(alias int a : 10) {}
7 | template a(alias int a : int = 10) {}
8 | template a(alias int a : int) {}
9 | template a(alias int a = 10) {}
10 | template a(alias int a = int) {}
11 | template a(alias b) {}
12 | template a(alias b, c : d) {}
13 | template a(alias b, c : int) {}
14 | template a(alias b, c : int[]) {}
15 | template a(b) if (is (a : struct)) {}
16 | template a(b) if (is (a : union)) {}
17 | template a(b) if (is (a : class)) {}
18 | template a(b) if (is (a : interface)) {}
19 | template a(b) if (is (a : enum)) {}
20 | template a(b) if (is (a : function)) {}
21 | template a(b) if (is (a : delegate)) {}
22 | template a(b) if (is (a : super)) {}
23 | template a(b) if (is (a : return)) {}
24 | template a(b) if (is (a : __parameters)) {}
25 | template a(b) if (is (a : const)) {}
26 | template a(b) if (is (a : immutable)) {}
27 | template a(b) if (is (a : inout)) {}
28 | template a(b) if (is (a : shared)) {}
29 | enum A(T) = A;
30 | template A(T) if (is (T u : v, W)) {}
31 | mixin template A(T) { T t; }
32 | size_t replicateBits(size_t , )() {}
33 |
--------------------------------------------------------------------------------
/test/pass_files/test8898.d:
--------------------------------------------------------------------------------
1 | // REQUIRED_ARGS: -w
2 | // PERMUTE_ARGS:
3 |
4 | static if (true):
5 |
6 | version (Foo)
7 | {
8 | }
9 | else
10 | {
11 | }
12 |
--------------------------------------------------------------------------------
/test/pass_files/throwattribute.d:
--------------------------------------------------------------------------------
1 | void doStuff() throw {
2 | throw void doThings()
3 | {
4 |
5 | }
6 | throw new Exception("OH NO!");
7 | }
8 |
9 | throw:
10 | extern void throwsSomething();
11 |
--------------------------------------------------------------------------------
/test/pass_files/unions.d:
--------------------------------------------------------------------------------
1 | union { int a; char b; }
2 | union SomeUnion;
3 | union SomeUnion { int a; int b; }
4 | union SomeUnion(T) { int a; int b; }
5 | union SomeUnion(T) if (z) { int a; int b; }
6 |
7 |
--------------------------------------------------------------------------------
/test/pass_files/varargs-attributes.d:
--------------------------------------------------------------------------------
1 | int printf(const(char)*, const scope shared return ...);
2 | int printf2(const scope shared return ...);
3 | int printf3(const(char)*, ...);
4 |
--------------------------------------------------------------------------------
/test/pass_files/while_condition_assignment.d:
--------------------------------------------------------------------------------
1 | import std : writeln, format;
2 |
3 | void main()
4 | {
5 | int i = 10;
6 | // Silly example I know
7 | while (int not_four = (i != 4)) {
8 | writeln(format("%d is not 4!", i));
9 | i--;
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/test/run_tests.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -euo pipefail
4 |
5 | PASS_FILES=$(find pass_files -name "*.d" | sort)
6 | FAIL_FILES=$(find fail_files -name "*.d" | sort)
7 | PASS_COUNT=0
8 | FAIL_COUNT=0
9 | NORMAL="\033[01;0m"
10 | GREEN="\033[32m"
11 | RED="\033[31m"
12 | YELLOW="\033[33m"
13 | DMD=${DMD:=dmd}
14 | SOURCE_FILES="../src/std/experimental/*.d ../src/dparse/*.d "
15 | IMPORT_PATHS="-I../src/"
16 |
17 | echo -en "Compiling parse tester... "
18 | ${DMD} tester.d -debug $SOURCE_FILES -g $IMPORT_PATHS
19 | echo -e "${GREEN}DONE${NORMAL}"
20 |
21 | test_fail() {
22 | set +e
23 | ./tester "$@"
24 | test_fail_status=$?
25 | set -e
26 | if [ $test_fail_status -eq 1 ]; then
27 | return 0
28 | else
29 | return 1
30 | fi
31 | }
32 |
33 | # if tester segfaults, it's most likely due to a stack overflow
34 | # check the maxStackSize variable in tester.d in that case
35 | # (increasing it should be avoided if it's possible to implement tail recursion or other stack saving techniques)
36 |
37 | for i in $PASS_FILES; do
38 | echo -en "Parsing $i..."
39 | if ./tester "$i" 2>/dev/null 1>/dev/null; then
40 | echo -e "\t${GREEN}PASS${NORMAL}"
41 | ((PASS_COUNT=PASS_COUNT+1))
42 | else
43 | echo -e "\t${RED}FAIL${NORMAL}"
44 | ((FAIL_COUNT=FAIL_COUNT+1))
45 | ./tester "$i"
46 | fi
47 | done
48 |
49 | for i in $FAIL_FILES; do
50 | echo -en "Parsing $i..."
51 | if test_fail "$i" 2>/dev/null 1>/dev/null; then
52 | echo -e "\t${GREEN}PASS${NORMAL}"
53 | ((PASS_COUNT=PASS_COUNT+1))
54 | else
55 | echo -e "\t${RED}FAIL${NORMAL}"
56 | ((FAIL_COUNT=FAIL_COUNT+1))
57 | fi
58 | done
59 |
60 | echo
61 | if [ "$FAIL_COUNT" -eq 0 ]; then
62 | echo -e "${GREEN}${PASS_COUNT} parse test(s) passed and ${FAIL_COUNT} failed.${NORMAL}"
63 | else
64 | echo -e "${RED}${PASS_COUNT} parse test(s) passed and ${FAIL_COUNT} failed.${NORMAL}"
65 | exit 1
66 | fi
67 |
68 | if [[ ${BUILDKITE:-} != "true" ]]; then
69 | PASS_COUNT=0
70 | FAIL_COUNT=0
71 | echo
72 | for file in ast_checks/*.d; do
73 | echo -en "Running AST match tests on ${file}..."
74 | # The query file has the same base name as its corresponding D file, but
75 | # with a txt extension. It contains XPath expressions, one per line, that
76 | # must match nodes in the generated AST.
77 | queryFile=ast_checks/$(basename "$file" .d).txt
78 | lineCount=1
79 | currentPasses=0
80 | currentFailures=0
81 | expectParseFailure=0
82 | set +e
83 | AST="$(./tester --ast "$file" 2>/dev/null)"
84 | test_fail_status=$?
85 | set -e
86 | while read -r line || [ -n "$line" ]; do
87 | if [[ "$line" == "INCLUDES_PARSE_ERROR" ]]; then
88 | expectParseFailure=1
89 | elif [[ "$line" =~ ^# ]]; then
90 | true # comment line
91 | elif echo "$AST" | xmllint --xpath "${line}" - 2>&1 | grep 'XPath set is empty' >/dev/null; then
92 | echo
93 | echo -e " ${RED}Check on line $lineCount of $queryFile failed.${NORMAL}"
94 | ((currentFailures=currentFailures+1))
95 | else
96 | ((currentPasses=currentPasses+1))
97 | fi
98 | ((lineCount=lineCount+1))
99 | done < "$queryFile"
100 |
101 | if [[ $expectParseFailure -eq 0 ]]; then
102 | if [[ $test_fail_status -ne 0 ]]; then
103 | echo -e " ${RED}D parsing of $queryFile failed in general.${NORMAL}"
104 | ./tester --ast "$file" >/dev/null
105 | ((currentFailures=currentFailures+1))
106 | fi
107 | fi
108 |
109 | if [[ $currentFailures -gt 0 ]]; then
110 | echo -e " ${RED}${currentPasses} check(s) passed and ${currentFailures} check(s) failed${NORMAL}"
111 | ((FAIL_COUNT=FAIL_COUNT+1))
112 |
113 | if [ -z "${VERBOSE:-}" ]; then
114 | echo -e " Run with VERBOSE=1 to print AST XML"
115 | else
116 | echo
117 | ./tester --ast "$file" | xmllint --format -
118 | echo
119 | fi
120 | else
121 | echo -e " ${GREEN}${currentPasses} check(s) passed and ${currentFailures} check(s) failed${NORMAL}"
122 | ((PASS_COUNT=PASS_COUNT+1))
123 | fi
124 | done
125 | echo
126 | if [ "$FAIL_COUNT" -eq 0 ]; then
127 | echo -e "${GREEN}${PASS_COUNT} AST test(s) passed and ${FAIL_COUNT} failed.${NORMAL}"
128 | else
129 | echo -e "${RED}${PASS_COUNT} AST test(s) passed and ${FAIL_COUNT} failed.${NORMAL}"
130 | exit 1
131 | fi
132 | else
133 | echo
134 | echo -e "${YELLOW}Skipping AST checks in Buildkite CI${NORMAL}"
135 | fi
136 |
137 | if [[ ${DMD} == "gdmd" ]]
138 | then
139 | echo "GDC / GDMD does not support -cov"
140 | exit 0;
141 | fi
142 |
143 | echo
144 | find . -name "*.lst" -exec rm -f {} \;
145 | echo -en "Generating coverage reports... "
146 | ${DMD} tester.d -debug -cov -unittest $SOURCE_FILES $IMPORT_PATHS
147 | # if tester segfaults, it's most likely due to a stack overflow
148 | # check the maxStackSize variable in tester.d in that case
149 | # (increasing it should be avoided if it's possible to implement tail recursion or other stack saving techniques)
150 | ./tester --ast --DRT-testmode=run-main $PASS_FILES $FAIL_FILES ast_checks/*.d > /dev/null
151 | rm -rf coverage/
152 | mkdir coverage/
153 | find . -name "*.lst" | while read -r i; do
154 | dest=$(echo "$i" | sed -e "s/\\.\\.\\-//")
155 | mv "$i" "coverage/$dest";
156 | done
157 | echo -e "${GREEN}DONE${NORMAL}"
158 | for i in coverage/*.lst; do
159 | tail -n1 "$i"
160 | done
161 |
162 | rm -f tester.o
163 |
--------------------------------------------------------------------------------
/test/tester.d:
--------------------------------------------------------------------------------
1 | import core.thread;
2 | import dparse.ast;
3 | import dparse.astprinter;
4 | import dparse.lexer;
5 | import dparse.parser;
6 | import dparse.rollback_allocator : RollbackAllocator;
7 | import std.array;
8 | import std.exception;
9 | import std.file;
10 | import std.getopt;
11 | import std.stdio;
12 |
13 | int errorCount = 0;
14 | int warningCount = 0;
15 |
16 | void messageFunction(string fileName, size_t line, size_t column,
17 | string message, bool isError)
18 | {
19 | if (isError)
20 | {
21 | errorCount++;
22 | version (D_Coverage) {}
23 | else
24 | stderr.writefln("%s(%d:%d)[error]: %s", fileName, line, column, message);
25 | }
26 | else
27 | {
28 | version (D_Coverage) {}
29 | else
30 | stderr.writefln("%s(%d:%d)[warn ]: %s", fileName, line, column, message);
31 | warningCount++;
32 | }
33 | }
34 |
35 | void testTokenChecks()
36 | {
37 | foreach (IdType i; 0 .. IdType.max)
38 | {
39 | switch (i)
40 | {
41 | case tok!"int":
42 | case tok!"uint":
43 | case tok!"double":
44 | case tok!"idouble":
45 | case tok!"float":
46 | case tok!"ifloat":
47 | case tok!"short":
48 | case tok!"ushort":
49 | case tok!"long":
50 | case tok!"ulong":
51 | case tok!"char":
52 | case tok!"wchar":
53 | case tok!"dchar":
54 | case tok!"bool":
55 | case tok!"void":
56 | case tok!"cent":
57 | case tok!"ucent":
58 | case tok!"real":
59 | case tok!"ireal":
60 | case tok!"byte":
61 | case tok!"ubyte":
62 | case tok!"cdouble":
63 | case tok!"cfloat":
64 | case tok!"creal":
65 | assert (isBasicType(i));
66 | assert (!isNumberLiteral(i));
67 | assert (!isIntegerLiteral(i));
68 | assert (!isOperator(i));
69 | assert (!isKeyword(i));
70 | assert (!isStringLiteral(i));
71 | assert (!isProtection(i));
72 | break;
73 | case tok!"doubleLiteral":
74 | case tok!"floatLiteral":
75 | case tok!"idoubleLiteral":
76 | case tok!"ifloatLiteral":
77 | case tok!"realLiteral":
78 | case tok!"irealLiteral":
79 | assert (!isBasicType(i));
80 | assert (isNumberLiteral(i));
81 | assert (!isIntegerLiteral(i));
82 | assert (!isOperator(i));
83 | assert (!isKeyword(i));
84 | assert (!isStringLiteral(i));
85 | assert (!isProtection(i));
86 | break;
87 | case tok!"intLiteral":
88 | case tok!"longLiteral":
89 | case tok!"uintLiteral":
90 | case tok!"ulongLiteral":
91 | assert (!isBasicType(i));
92 | assert (isNumberLiteral(i));
93 | assert (isIntegerLiteral(i));
94 | assert (!isOperator(i));
95 | assert (!isKeyword(i));
96 | assert (!isStringLiteral(i));
97 | assert (!isProtection(i));
98 | break;
99 | case tok!",":
100 | case tok!".":
101 | case tok!"..":
102 | case tok!"...":
103 | case tok!"/":
104 | case tok!"/=":
105 | case tok!"!":
106 | case tok!"!<":
107 | case tok!"!<=":
108 | case tok!"!<>":
109 | case tok!"!<>=":
110 | case tok!"!=":
111 | case tok!"!>":
112 | case tok!"!>=":
113 | case tok!"$":
114 | case tok!"%":
115 | case tok!"%=":
116 | case tok!"&":
117 | case tok!"&&":
118 | case tok!"&=":
119 | case tok!"(":
120 | case tok!")":
121 | case tok!"*":
122 | case tok!"*=":
123 | case tok!"+":
124 | case tok!"++":
125 | case tok!"+=":
126 | case tok!"-":
127 | case tok!"--":
128 | case tok!"-=":
129 | case tok!":":
130 | case tok!";":
131 | case tok!"<":
132 | case tok!"<<":
133 | case tok!"<<=":
134 | case tok!"<=":
135 | case tok!"<>":
136 | case tok!"<>=":
137 | case tok!"=":
138 | case tok!"==":
139 | case tok!"=>":
140 | case tok!">":
141 | case tok!">=":
142 | case tok!">>":
143 | case tok!">>=":
144 | case tok!">>>":
145 | case tok!">>>=":
146 | case tok!"?":
147 | case tok!"@":
148 | case tok!"[":
149 | case tok!"]":
150 | case tok!"^":
151 | case tok!"^=":
152 | case tok!"^^":
153 | case tok!"^^=":
154 | case tok!"{":
155 | case tok!"|":
156 | case tok!"|=":
157 | case tok!"||":
158 | case tok!"}":
159 | case tok!"~":
160 | case tok!"~=":
161 | assert (!isBasicType(i));
162 | assert (!isNumberLiteral(i));
163 | assert (!isIntegerLiteral(i));
164 | assert (isOperator(i));
165 | assert (!isKeyword(i));
166 | assert (!isStringLiteral(i));
167 | assert (!isProtection(i));
168 | break;
169 | case tok!"abstract":
170 | case tok!"alias":
171 | case tok!"align":
172 | case tok!"asm":
173 | case tok!"assert":
174 | case tok!"auto":
175 | case tok!"break":
176 | case tok!"case":
177 | case tok!"cast":
178 | case tok!"catch":
179 | case tok!"class":
180 | case tok!"const":
181 | case tok!"continue":
182 | case tok!"debug":
183 | case tok!"default":
184 | case tok!"delegate":
185 | case tok!"delete":
186 | case tok!"deprecated":
187 | case tok!"do":
188 | case tok!"else":
189 | case tok!"enum":
190 | case tok!"extern":
191 | case tok!"false":
192 | case tok!"final":
193 | case tok!"finally":
194 | case tok!"for":
195 | case tok!"foreach":
196 | case tok!"foreach_reverse":
197 | case tok!"function":
198 | case tok!"goto":
199 | case tok!"if":
200 | case tok!"immutable":
201 | case tok!"import":
202 | case tok!"in":
203 | case tok!"inout":
204 | case tok!"interface":
205 | case tok!"invariant":
206 | case tok!"is":
207 | case tok!"lazy":
208 | case tok!"macro":
209 | case tok!"mixin":
210 | case tok!"module":
211 | case tok!"new":
212 | case tok!"nothrow":
213 | case tok!"null":
214 | case tok!"out":
215 | case tok!"override":
216 | case tok!"pragma":
217 | case tok!"pure":
218 | case tok!"ref":
219 | case tok!"return":
220 | case tok!"scope":
221 | case tok!"shared":
222 | case tok!"static":
223 | case tok!"struct":
224 | case tok!"super":
225 | case tok!"switch":
226 | case tok!"synchronized":
227 | case tok!"template":
228 | case tok!"this":
229 | case tok!"throw":
230 | case tok!"true":
231 | case tok!"try":
232 | case tok!"typedef":
233 | case tok!"typeid":
234 | case tok!"typeof":
235 | case tok!"union":
236 | case tok!"unittest":
237 | case tok!"version":
238 | case tok!"while":
239 | case tok!"with":
240 | case tok!"__DATE__":
241 | case tok!"__EOF__":
242 | case tok!"__FILE__":
243 | case tok!"__FILE_FULL_PATH__":
244 | case tok!"__FUNCTION__":
245 | case tok!"__gshared":
246 | case tok!"__LINE__":
247 | case tok!"__MODULE__":
248 | case tok!"__parameters":
249 | case tok!"__PRETTY_FUNCTION__":
250 | case tok!"__TIME__":
251 | case tok!"__TIMESTAMP__":
252 | case tok!"__traits":
253 | case tok!"__vector":
254 | case tok!"__VENDOR__":
255 | case tok!"__VERSION__":
256 | assert (!isBasicType(i));
257 | assert (!isNumberLiteral(i));
258 | assert (!isIntegerLiteral(i));
259 | assert (!isOperator(i));
260 | assert (isKeyword(i));
261 | assert (!isStringLiteral(i));
262 | assert (!isProtection(i));
263 | break;
264 | case tok!"dstringLiteral":
265 | case tok!"stringLiteral":
266 | case tok!"wstringLiteral":
267 | assert (!isBasicType(i));
268 | assert (!isNumberLiteral(i));
269 | assert (!isIntegerLiteral(i));
270 | assert (!isOperator(i));
271 | assert (!isKeyword(i));
272 | assert (isStringLiteral(i));
273 | assert (!isProtection(i));
274 | break;
275 | case tok!"export":
276 | case tok!"package":
277 | case tok!"private":
278 | case tok!"public":
279 | case tok!"protected":
280 | assert (!isBasicType(i));
281 | assert (!isNumberLiteral(i));
282 | assert (!isIntegerLiteral(i));
283 | assert (!isOperator(i));
284 | assert (isKeyword(i));
285 | assert (!isStringLiteral(i));
286 | assert (isProtection(i));
287 | break;
288 | default:
289 | assert (!isBasicType(i));
290 | assert (!isNumberLiteral(i));
291 | assert (!isIntegerLiteral(i));
292 | assert (!isOperator(i));
293 | assert (!isKeyword(i));
294 | assert (!isStringLiteral(i));
295 | assert (!isProtection(i));
296 | break;
297 | }
298 | }
299 | }
300 |
301 | void testArbitraryASTs()
302 | {
303 | StringCache cache = StringCache(StringCache.defaultBucketCount);
304 | LexerConfig config;
305 | config.stringBehavior = StringBehavior.source;
306 | RollbackAllocator rba;
307 | string[] errors;
308 | void msgDelegate(string fileName, size_t line, size_t column, string message, bool isError)
309 | {
310 | errors ~= message;
311 | }
312 | auto parser = new Parser();
313 | parser.messageDelegate = &msgDelegate;
314 | parser.allocator = &rba;
315 |
316 | parser.tokens = getTokensForParser("struct S {}", config, &cache);
317 | assert(parser.parseCompileCondition() is null);
318 | assert(errors == ["`version`, `debug`, or `static` expected (found token `struct`)"]);
319 | errors = null;
320 |
321 | parser = new Parser();
322 | parser.messageDelegate = &msgDelegate;
323 | parser.allocator = &rba;
324 | parser.tokens = getTokensForParser("~", config, &cache);
325 | assert(parser.parseDestructor() is null);
326 | assert(errors == ["`this` expected instead of EOF"]);
327 | errors = null;
328 |
329 | parser = new Parser();
330 | parser.messageDelegate = &msgDelegate;
331 | parser.allocator = &rba;
332 | parser.tokens = getTokensForParser("for (x; y; z) {}", config, &cache);
333 | assert(parser.parseForeach() is null);
334 | assert(errors == ["`foreach` or `foreach_reverse` expected (found token `for`)"]);
335 | errors = null;
336 |
337 | parser = new Parser();
338 | parser.messageDelegate = &msgDelegate;
339 | parser.allocator = &rba;
340 | parser.tokens = getTokensForParser("version =", config, &cache);
341 | assert(parser.parseVersionSpecification() is null);
342 | assert(errors == ["Identifier or integer literal expected (found EOF)"]);
343 | errors = null;
344 |
345 | }
346 |
347 | int main(string[] args)
348 | {
349 | version (D_Coverage) testTokenChecks();
350 | version (D_Coverage) testArbitraryASTs();
351 |
352 | bool ast;
353 | getopt(args, "ast", &ast);
354 |
355 | enforce(args.length > 1, "Must specifiy at least one D file");
356 | auto printer = new XMLPrinter;
357 | printer.output = stdout;
358 | bool done;
359 |
360 | // increase stack size in case of segfault:
361 | // stack usage in debug / non-optimized mode is _much_ higher
362 | version (D_Coverage)
363 | enum maxStackSize = 256 * 4096;
364 | else debug
365 | enum maxStackSize = 256 * 4096;
366 | else
367 | enum maxStackSize = 40 * 4096;
368 |
369 | // use a fiber to limit stack size
370 | new Fiber({
371 | foreach (arg; args[1 .. $])
372 | {
373 | auto f = File(arg);
374 | immutable ulong fileSize = f.size();
375 | ubyte[] fileBytes = new ubyte[](fileSize);
376 | enforce(f.rawRead(fileBytes).length == fileSize);
377 | StringCache cache = StringCache(fileSize.optimalBucketCount);
378 | LexerConfig config;
379 | config.stringBehavior = StringBehavior.source;
380 | config.fileName = arg;
381 | const(Token)[] tokens = getTokensForParser(fileBytes, config, &cache);
382 | RollbackAllocator rba;
383 | auto mod = parseModule(ParserConfig(tokens, arg, &rba, &messageFunction));
384 | if (ast && mod !is null)
385 | printer.visit(mod);
386 | }
387 | done = true;
388 | }, maxStackSize).call();
389 | assert(done);
390 | if (!ast)
391 | writefln("Finished parsing with %d errors and %d warnings.",
392 | errorCount, warningCount);
393 |
394 | version (D_Coverage)
395 | return 0; // we don't care about error count in coverage mode
396 | else
397 | return errorCount == 0 ? 0 : 1;
398 | }
399 |
--------------------------------------------------------------------------------
/test/watcher.sh:
--------------------------------------------------------------------------------
1 | while $(true); do
2 | inotifywait -emodify -r ../src/ pass_files/ fail_files/;
3 | ./run_tests.sh;
4 | done
5 |
--------------------------------------------------------------------------------